深入浅出Win32多线程程序设计之综合实例 :串口通信

本章我们将以工业控制和嵌入式系统中运用极为广泛的串口通信为例讲述多线程的典型应用。

  而网络通信也是多线程应用最广泛的领域之一,所以本章的最后一节也将对多线程网络通信进行简短的描述。

  1.串口通信

  在工业控制系统中,工控机(一般都基于PC Windows平台)经常需要与单片机通过串口进行通信。因此,操作和使用PC的串口成为大多数单片机、嵌入式系统领域工程师必须具备的能力。

  串口的使用需要通过三个步骤来完成的:

  (1) 打开通信端口;

  (2) 初始化串口,设置波特率、数据位、停止位、奇偶校验等参数。为了给读者一个直观的印象,下图从Windows的"控制面板->系统->设备管理器->通信端口(COM1)"打开COM的设置窗口:
  (3) 读写串口。

  在WIN32平台下,对通信端口进行操作跟基本的文件操作一样。

  创建/打开COM资源

  下列函数如果调用成功,则返回一个标识通信端口的句柄,否则返回-1:
HADLE CreateFile(PCTSTR lpFileName, //通信端口名,如"COM1"
WORD dwDesiredAccess, //对资源的访问类型
WORD dwShareMode, //指定共享模式,COM不能共享,该参数为0
PSECURITY_ATTRIBUTES lpSecurityAttributes,
//安全描述符指针,可为NULL
WORD dwCreationDisposition, //创建方式
WORD dwFlagsAndAttributes, //文件属性,可为NULL
HANDLE hTemplateFile //模板文件句柄,置为NULL
);

  获得/设置COM属性

  下列函数可以获得COM口的设备控制块,从而获得相关参数:

BOOL WINAPI GetCommState(
 HANDLE hFile, //标识通信端口的句柄
 LPDCB lpDCB //指向一个设备控制块(DCB结构)的指针
);

  如果要调整通信端口的参数,则需要重新配置设备控制块,再用WIN32 API SetCommState()函数进行设置:

BOOL SetCommState(
 HANDLE hFile, //标识通信端口的句柄
 LPDCB lpDCB //指向一个设备控制块(DCB结构)的指针
);

  DCB结构包含了串口的各项参数设置,如下:

typedef struct _DCB
{
 // dcb
 DWORD DCBlength; // sizeof(DCB)
 DWORD BaudRate; // current baud rate
 DWORD fBinary: 1; // binary mode, no EOF check
 DWORD fParity: 1; // enable parity checking
 DWORD fOutxCtsFlow: 1; // CTS output flow control
 DWORD fOutxDsrFlow: 1; // DSR output flow control
 DWORD fDtrControl: 2; // DTR flow control type
 DWORD fDsrSensitivity: 1; // DSR sensitivity
 DWORD fTXContinueOnXoff: 1; // XOFF continues Tx
 DWORD fOutX: 1; // XON/XOFF out flow control
 DWORD fInX: 1; // XON/XOFF in flow control
 DWORD fErrorChar: 1; // enable error replacement
 DWORD fNull: 1; // enable null stripping
 DWORD fRtsControl: 2; // RTS flow control
 DWORD fAbortOnError: 1; // abort reads/writes on error
 DWORD fDummy2: 17; // reserved
 WORD wReserved; // not currently used
 WORD XonLim; // transmit XON threshold
 WORD XoffLim; // transmit XOFF threshold
 BYTE ByteSize; // number of bits/byte, 4-8
 BYTE Parity; // 0-4=no,odd,even,mark,space
 BYTE StopBits; // 0,1,2 = 1, 1.5, 2
 char XonChar; // Tx and Rx XON character
 char XoffChar; // Tx and Rx XOFF character
 char ErrorChar; // error replacement character
 char EofChar; // end of input character
 char EvtChar; // received event character
 WORD wReserved1; // reserved; do not use
} DCB;

  读写串口

  在读写串口之前,还要用PurgeComm()函数清空缓冲区,并用SetCommMask ()函数设置事件掩模来监视指定通信端口上的事件,其原型为:

BOOL SetCommMask(
 HANDLE hFile, //标识通信端口的句柄
 DWORD dwEvtMask //能够使能的通信事件
);

  串口上可能发生的事件如下表所示:

值 事件描述
EV_BREAK A break was detected on input.
EV_CTS The CTS (clear-to-send) signal changed state.
EV_DSR The DSR(data-set-ready) signal changed state.
EV_ERR A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
EV_RING A ring indicator was detected.
EV_RLSD The RLSD (receive-line-signal-detect) signal changed state.
EV_RXCHAR A character was received and placed in the input buffer.
EV_RXFLAG The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
EV_TXEMPTY The last character in the output buffer was sent.

  在设置好事件掩模后,我们就可以利用WaitCommEvent()函数来等待串口上发生事件,其函数原型为:

BOOL WaitCommEvent(
 HANDLE hFile, //标识通信端口的句柄
 LPDWORD lpEvtMask, //指向存放事件标识变量的指针
 LPOVERLAPPED lpOverlapped, // 指向overlapped结构
);

  我们可以在发生事件后,根据相应的事件类型,进行串口的读写操作:

BOOL ReadFile(HANDLE hFile, //标识通信端口的句柄
 LPVOID lpBuffer, //输入数据Buffer指针
 DWORD nNumberOfBytesToRead, // 需要读取的字节数
 LPDWORD lpNumberOfBytesRead, //实际读取的字节数指针
 LPOVERLAPPED lpOverlapped //指向overlapped结构
);
BOOL WriteFile(HANDLE hFile, //标识通信端口的句柄
 LPCVOID lpBuffer, //输出数据Buffer指针
 DWORD nNumberOfBytesToWrite, //需要写的字节数
 LPDWORD lpNumberOfBytesWritten, //实际写入的字节数指针
 LPOVERLAPPED lpOverlapped //指向overlapped结构
);


文章来自: 本站原创
Tags:
评论: 0 | 查看次数: 9133