《多线程串口编程详解》由会员分享,可在线阅读,更多相关《多线程串口编程详解(26页珍藏版)》请在金锄头文库上搜索。
1、深入浅出深入浅出 Win32Win32 多线程程序设计综合实例多线程程序设计综合实例本章我们将以工业控制和嵌入式系统中运用极为广泛的串口通信为例讲述多线程的典型应 用。 而网络通信也是多线程应用最广泛的领域之一,所以本章的最后一节也将对多线程网 络通信进行简短的描述。 1.串口通信 在工业控制系统中,工控机(一般都基于 PC Windows 平本章我们将以工业控制和嵌入式系统中运用极为广泛的串口通信为例讲述多线程的典型应 用。而网络通信也是多线程应用最广泛的领域之一,所以本章的最后一节也将对多线程网络通 信进行简短的描述。1.串口通信在工业控制系统中,工控机(一般都基于 PC Windows
2、平台)经常需要与单片机通过串口进 行通信。因此,操作和使用 PC 的串口成为大多数单片机、嵌入式系统领域工程师必须具备 的能力。串口的使用需要通过三个步骤来完成的:(1) 打开通信端口;(2) 初始化串口,设置波特率、数据位、停止位、奇偶校验等参数。为了给读者一个直 观的印象,下图从 Windows 的“控制面板系统设备管理器通信端口(COM1)“打开 COM 的设置窗口:(3) 读写串口。在 WIN32 平台下,对通信端口进行操作跟基本的文件操作一样。创建/打开 COM 资源下列函数如果调用成功,则返回一个标识通信端口的句柄,否则返回-1:HADLE CreateFile(PCTSTR lp
3、FileName, /通信端口名,如“COM1“ WORD dwDesiredAccess, /对资源的访问类型 WORD dwShareMode, /指定共享模式,COM 不能共享,该参数为 0PSECURITY_ATTRIBUTES lpSecurityAttributes, /安全描述符指针,可为 NULL WORD dwCreationDisposition, /创建方式 WORD dwFlagsAndAttributes, /文件属性,可为 NULL HANDLE hTemplateFile /模板文件句柄,置为 NULL); 获得/设置 COM 属性下列函数可以获得 COM 口的设
4、备控制块,从而获得相关参数:BOOL WINAPI GetCommState( HANDLE hFile, /标识通信端口的句柄 LPDCB lpDCB /指向一个设备控制块(DCB 结构)的指针); 如果要调整通信端口的参数,则需要重新配置设备控制块,再用 WIN32 API SetCommState()函数进行设置:BOOL SetCommState( HANDLE hFile, /标识通信端口的句柄 LPDCB lpDCB /指向一个设备控制块(DCB 结构)的指针); DCB 结构包含了串口的各项参数设置,如下:typedef struct _DCB / dcb DWORD DCBle
5、ngth; / 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 fDsrS
6、ensitivity: 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 DWOR
7、D 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,
8、2 = 1, 1.5, 2 char XonChar; / Tx and Rx XON characterchar 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()函数清空缓冲区
9、,并用 SetCommMask ()函数设置事 件掩模来监视指定通信端口上的事件,其原型为:BOOL SetCommMask( HANDLE hFile, /标识通信端口的句柄 DWORD dwEvtMask /能够使能的通信事件); 串口上可能发生的事件如下表所示:值事件描述EV_BREAKA break was detected on input.EV_CTSThe CTS (clear-to-send) signal changed state.EV_DSRThe DSR(data-set-ready) signal changed state.EV_ERRA line-status e
10、rror occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.EV_RINGA ring indicator was detected.EV_RLSDThe RLSD (receive-line-signal-detect) signal changed state.EV_RXCHARA character was received and placed in the input buffer.EV_RXFLAGThe event character was received and placed in
11、the input buffer. The event character is specified in the devices 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, /标
12、识通信端口的句柄 LPDWORD lpEvtMask, /指向存放事件标识变量的指针 LPOVERLAPPED lpOverlapped, / 指向 overlapped 结构); 我们可以在发生事件后,根据相应的事件类型,进行串口的读写操作:BOOL ReadFile(HANDLE hFile, /标识通信端口的句柄 LPVOID lpBuffer, /输入数据 Buffer 指针 DWORD nNumberOfBytesToRead, / 需要读取的字节数 LPDWORD lpNumberOfBytesRead, /实际读取的字节数指针 LPOVERLAPPED lpOverlapped
13、/指向 overlapped 结构); BOOL WriteFile(HANDLE hFile, /标识通信端口的句柄 LPCVOID lpBuffer, /输出数据 Buffer 指针 DWORD nNumberOfBytesToWrite, /需要写的字节数LPDWORD lpNumberOfBytesWritten, /实际写入的字节数指针 LPOVERLAPPED lpOverlapped /指向 overlapped 结构); 2.工程实例下面我们用第 1 节所述 API 实现一个多线程的串口通信程序。这个例子工程(工程名为 MultiThreadCom)的界面很简单,如下图所示:它
14、是一个多线程的应用程序,包括两个工作者线程,分别处理串口 1 和串口 2。为了简化问 题,我们让连接两个串口的电缆只包含 RX、TX 两根连线(即不以硬件控制 RS-232,串口上 只会发生 EV_TXEMPTY、EV_RXCHAR 事件)。在工程实例的 BOOL CMultiThreadComApp:InitInstance()函数中,启动并设置 COM1 和 COM2,其源代码为:BOOL CMultiThreadComApp:InitInstance() AfxEnableControlContainer(); /打开并设置 COM1hComm1=CreateFile(“COM1“, G
15、ENERIC_READ|GENERIC_WRITE, 0, NULL ,OPEN_EXISTING, 0,NULL); if (hComm1=(HANDLE)-1) AfxMessageBox(“打开 COM1 失败“);return false; else DCB wdcb; GetCommState (hComm1, wdcb.BaudRate=9600;SetCommState (hComm1, PurgeComm(hComm1,PURGE_TXCLEAR); /打开并设置 COM2hComm2=CreateFile(“COM2“, GENERIC_READ|GENERIC_WRITE,
16、 0, NULL ,OPEN_EXISTING, 0,NULL); if (hComm2=(HANDLE)-1) AfxMessageBox(“打开 COM2 失败“);return false; else DCB wdcb; GetCommState (hComm2, wdcb.BaudRate=9600; SetCommState (hComm2, PurgeComm(hComm2,PURGE_TXCLEAR); CMultiThreadComDlg dlg; m_pMainWnd = int nResponse = dlg.DoModal(); if (nResponse = IDOK) / TODO: Place code here to handle when the dialog is / dismissed with OK else if (nResponse =