串口数据接收事件的一点感悟
刚才在看串口数据的接收问题。
这里的话,最开始的时候需要在打开串口后,对串口使用SetCommEvent函数去设置通知事件。
这里又涉及一个问题,就是一般SetCommEvent函数的第二个事件参数为
EV_RXCHAR
第一个参数不用想了,就是文件句柄。
响应这个事件的函数是:
WaitCommEvent
在一个已经完成了的串口类中,也是调用这个函数去响应消息的,而且在后台线程函数中,这个函数同时调用了两个时间等待函数。
第一个等待事件响应的就是这个函数,第二个则是著名的waitmultipleobjects函数。
然后在其代码注释中,那位大神说这个函数在调用之后不会持续等待,而是立刻返回,原因就是这个串口是以异步的方式打开的。
waitcommevent函数的返回值是一个BOOL值,其注释原文如下:
1 // If WaitCommEvent() returns TRUE, check to be sure there are 2 // actually bytes in the buffer to read. 3 // 4 // If you are reading more than one byte at a time from the buffer 5 // (which this program does not do) you will have the situation occur 6 // where the first byte to arrive will cause the WaitForMultipleObjects() 7 // function to stop waiting. The WaitForMultipleObjects() function 8 // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state 9 // as it returns. 10 // 11 // If in the time between the reset of this event and the call to 12 // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again 13 // to the signeled state. When the call to ReadFile() occurs, it will 14 // read all of the bytes from the buffer, and the program will 15 // loop back around to WaitCommEvent(). 16 // 17 // At this point you will be in the situation where m_OverlappedStruct.hEvent is set, 18 // but there are no bytes available to read. If you proceed and call 19 // ReadFile(), it will return immediatly due to the async port setup, but 20 // GetOverlappedResults() will not return until the next character arrives. 21 // 22 // It is not desirable for the GetOverlappedResults() function to be in 23 // this state. The thread shutdown event (event 0) and the WriteFile() 24 // event (Event2) will not work if the thread is blocked by GetOverlappedResults(). 25 // 26 // The solution to this is to check the buffer with a call to ClearCommError(). 27 // This call will reset the event handle, and if there are no bytes to read 28 // we can loop back through WaitCommEvent() again, then proceed. 29 // If there are really bytes to read, do nothing and proceed. 30 31 bResult = ClearCommError(port->m_hComm, &dwError, &comstat); 32 33 if (comstat.cbInQue == 0) 34 continue;
其意思我大概翻译一下:
如果BResult函数返回值为真,则必须要检测缓冲区中是否有数据。
如果你一次性的从缓冲区中读出多个数据,那么下面的这种情况就会出现:第一个将要到来数据会导致waitmultipleobjects函数停止等待。然后这个函数会在其返回的时候会重置位于OVERLAPPED结构中的事件句柄,将其置为未触发状态。
如果在重置了事件并且调用readfile函数时有更多的数据来临了,OVERLAPPEED结构中的event事件会被再次触发。此时调用readfile函数会把所有的数据全部都读取进来,然后再循环到waitcommevent函数(因为触发了的事件)。
在这个时候你会面临一个问题,就是,数据接收事件已经触发,但是缓冲区内无数据可读。此时运行并调用readfile函数,此函数会立即因为串口是异步的而返回,但是GetOverlappedResult函数并不会返回而是等待下一次字符的到来。
对于GetOverlappedResult函数来说,这个并不是我们想要的结果。如果线程被阻塞在这个函数,那么线程关闭时间和写事件就都无法响应了(当然~)
对这个问题的解决方法是调用ClearCommError函数来检查缓冲区这个函数会重置事件,如果缓冲区中没有数据可读,那么我们就重新到waitcommevent函数去等待(就是跳过waitmultipleobjects函数)
-------------------分割线----------------------------
原文就在那里,我自己翻译的可能会有点问题,但是大致的意思应该是对的。
不过现在还是在奇怪,既然waitcommevent函数不等待,那么如果只检查了一次就跳到waitformultipleobjects函数,那么在这个函数等待的时候,如果来了字符串该怎么办???我还是不很清楚这两个时间是怎么关联起来的。
不过目前看的话,应该是和OVERLAPPED结构有很大的关系。