13.6.4 串口线程函数的实现
串口线程处理函数CommThread()实现监控串口事件的功能,根据串口事件进行相应的处理,实现如下:
- 01 UINT CMySerial::CommThread(LPVOID pParam)
- 02 {
- 03 CMySerial *port = (CMySerial*)pParam; //串口类指针
- 04 //串口线程活动标识
- 05 port->m_bThreadAlive = TRUE;
- 06 //串口信息变量
- 07 DWORD BytesTransfered = 0;
- 08 DWORD Event = 0;
- 09 DWORD CommEvent = 0;
- 10 DWORD dwError = 0;
- 11 COMSTAT comstat;
- 12 BOOL bResult = TRUE;
- 13 //强制关闭串口
- 14 if (port->m_hComm)
- 15 {//清空串口缓冲
- 16 PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |
- 17 PURGE_RXABORT | PURGE_TXABORT);
- 18 }
- 19
- 20 //线程的循环体
- 21 for (;;)
- 22 {
- 23 bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);
- 24 //读取失败处理
- 25 if (!bResult)
- 26 {
- 27 switch (dwError = GetLastError())
- 28 {
- 29 case ERROR_IO_PENDING:
- 30 { //读取串口为空
- 31 break;
- 32 }
- 33 case 87:
- 34 {
- 35 break;
- 36 }
- 37 default:
- 38 { //错误处理
- 39 port->ProcessErrorMessage("WaitCommEvent()");
- 40 break;
- 41 }
- 42 }
- 43 }
- 44 else
- 45 {
- 46 //清空串口错误
- 47 bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
- 48 if (comstat.cbInQue == 0)
- 49 continue;
- 50 }
- 51 //获取串口事件并进行相应处理
- 52 Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
- 53 switch (Event)
- 54 {
- 55 case 0: //关闭串口
- 56 CloseHandle(port->m_hComm);
- 57 port->m_hComm=NULL;
- 58 port->m_bThreadAlive = FALSE;
- 59 AfxEndThread(100);
- 60 break;
- 61 case 1: //读串口
- 62 GetCommMask(port->m_hComm, &CommEvent);
- 63 if (CommEvent & EV_RXCHAR)
- 64 ReceiveChar(port, comstat);
- 65 break;
- 66 case 2: //写串口
- 67 WriteChar(port);
- 68 break;
- 69 }
- 70 }
- 71 return 0;
- 72 }
【代码解析】
第3行获保存串口类指针,第5行将串口线程活动标识置为真。第14~18行判断串口是否已经打开,如是则清空串口缓冲。第21~70行是串口线程的主循环体。第23行等待串口的异步通信事件,如果等待失败则在第25~43行进行处理,否则在第47行获取串口中尚未读取的字节数,第48行判断接收到的字节数是否为空,如是则在第49行跳出本次循环。第52行等待串口的3个事件,第53行判断接收到的串口事件类型。第55~60行处理关闭串口事件,第62~64行处理读串口事件,第67、68行处理写串口事件。
第23行的WaitCommEvent()为一个特指的通信设备等待一个事件发生,该函数所监控的事件是与该设备句柄相关联的一系列事件。
- BOOL WINAPI WaitCommEvent(
- HANDLE hFile, //指向通信设备的一个句柄
- LPDWORD lpEvtMask, //一个指向DWORD的指针
- LPOVERLAPPED lpOverlapped //指向OVERLAPPED结构体的一个指针
- );
参数lpOverlapped指向OVERLAPPED结构体的一个指针。如果hFile是用异步方式打开的(在CreateFile()函数中,该参数设置为FILE_FLAG_OVERLAPPED)。该参数不能指向一个空OVERLAPPED结构体,而是与Readfile()和WreteFile()中的OVERLAPPED参数为同一个参数。如果hFile是用异步方式打开的,而lpOverlapped 指向一个空的OVERLAPPED结构体,那么函数会错误地报告,等待的操作已经完成(而此时等待的操作可能还没有完成)。
第52行的WaitForMultipleObjects()函数可以等待Windows中的所有内核对象,函数原型如下:
- DWORD WaitForMultipleObjects(
- DWORD nCount, //指定等待事件对象的数量
- const HANDLE* lpHandles, //是等待事件数组
- BOOL bWaitAll, //是否等待所有事件对象
- DWORD dwMilliseconds //等待事件对象的超时时间
- );