生活随笔
收集整理的這篇文章主要介紹了
Win32 串口编程(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
3 串口狀態
有兩種獲取通信端口狀態的方法。第一種方法是設置事件掩碼,當指定事件發生時應用程序會收到通知。SetCommMask函數用于設置事件掩碼,WaitCommEvent用于等待指定的事件發生。它們與16位Windows中的SetCommEventMask和EnableCommNotification類似,只是它們不發送WM_COMMNOTIFY消息。第二種方法是不時地調用另一些狀態函數來獲取通信端口的狀態。當然,輪詢是低效的,不建議使用。
3.1 通信事件
通信事件在使用通信端口時可能隨時發生。接收通信事件需要兩個步驟:
- 用SetCommMask設定需要接收通知的事件
- 用WaitCommEvent提交狀態檢查請求,請求可以是重疊的或者非重疊的,與讀寫操作一樣。
下面是使用SetCommMask的示例:
DWORD?dwStoredFlags; dwStoredFlags?=?EV_BREAK?|?EV_CTS???|?EV_DSR?|?EV_ERR?|?EV_RING?|??????????????? ??????????????? EV_RLSD?|?EV_RXCHAR?|?EV_RXFLAG?|?EV_TXEMPTY?; if?(!SetCommMask(hComm,?dwStoredFlags))??? ?? //?error?setting?communications?mask |
?
?
下表描述了每種事件類型。
?
| 事件標志 | 描述 |
| EV_BREAK | 檢測到輸入中的break |
| EV_CTS | CTS(Clear?To?Send)信號狀態改變。要取得CTS線路狀態,應使用GetCommModemStatus函數。 |
| EV_DSR | DSR(Data?Set?Ready)信號狀態改變。要取得DSR線路狀態,應使用GetCommModemStatus函數。 |
| EV_ERR | 某線路狀態錯誤發生。線路狀態錯誤包括CE_FRAME、CE_OVERRUN和CE_RXPARITY。要取得具體錯誤種類,需調用ClearCommError函數。 |
| EV_RING | 檢測到振鈴指示 |
| EV_RLSD | RLSD(Receive?Line?Signal?Detect)信號狀態改變。要取得RLSD線路狀態,需調用GetCommModemStatus函數。注意,RLSD通常被稱作CD(carrier?detect)。 |
| EV_RXCHAR | 接收到一個字符并且已放入輸入緩沖區。請參考下面的“警告”節對此標志的詳細討論。 |
| EV_RXFLAG | 接收到一個事件字符并且已放入輸入緩沖區。事件字符由下文討論的DCB結構EvtChar字段指定。下面的“警告”節也討論了這個標志。 |
| EV_TXEMPTY | 輸出緩沖區中最后一個字符被發送到串口設備了。如果使用硬件緩沖區,此標志僅表示所有數據已經發送到硬件了。如果不與設備驅動交互,是無法確定硬件緩沖區空的。 |
?
指定事件掩碼后,使用WaitCommEvent函數檢測事件發生。如果以非重疊方式打開端口,則WaitCommEvent不需要OVERLAPPED結構體,函數阻塞調用線程直到某事件發生。如果沒有事件發生,調用線程將無限阻塞。
下面的代碼片段展示了如何在以非重疊方式打開的端口上等待EV_RING事件。
???DWORD?dwCommEvent; ???if?(!SetCommMask(hComm,?EV_RING))?????? ???????//?Error?setting?communications?mask?????? ?????? return?FALSE; ???if?(!WaitCommEvent(hComm,?&dwCommEvent,?NULL)) ?????? //?An?error?occurred?waiting?for?the?event. ???????return?FALSE; ?? else ?????? //?Event?has?occurred. ?????? return?TRUE; |
?
?
?
?
如果沒有事件發生,上面的代碼將無限阻塞調用線程。解決方法是以重疊方式打開端口,用下面的方式等待狀態事件:
?
| ?? #define?STATUS_CHECK_TIMEOUT??????500???//?Milliseconds ???DWORD??????dwRes; ???DWORD??????dwCommEvent; ???DWORD??????dwStoredFlags; ???BOOL??????fWaitingOnStat?=?FALSE; ???OVERLAPPED?osStatus?=?{0}; ???dwStoredFlags?=?EV_BREAK?|?EV_CTS?|?EV_DSR?|?EV_ERR?|?EV_RING?|\ ??????????????????EV_RLSD?|?EV_RXCHAR?|?EV_RXFLAG?|?EV_TXEMPTY?; ???if?(!SetCommMask(comHandle,?dwStoredFlags)) ??????//?error?setting?communications?mask;?abort ??????return?0; ???osStatus.hEvent?=?CreateEvent(NULL,?TRUE,?FALSE,?NULL); ???if?(osStatus.hEvent?==?NULL) ??????//?error?creating?event;?abort ??????return?0; ???for?(?;?;?)?{ ??????//?Issue?a?status?event?check?if?one?hasn't?been?issued?already. ??????if?(!fWaitingOnStat)?{ ?????????if?(!WaitCommEvent(hComm,?&dwCommEvent,?&osStatus))?{ ????????????if?(GetLastError()?==?ERROR_IO_PENDING) ???????????????bWaitingOnStatusHandle?=?TRUE; ????????????else ???????????????//?error?in?WaitCommEvent;?abort ???????????????break; ?????????} ?????????else ????????????//?WaitCommEvent?returned?immediately. ????????????//?Deal?with?status?event?as?appropriate. ????????????ReportStatusEvent(dwCommEvent);? ??????} ??????//?Check?on?overlapped?operation. ??????if?(fWaitingOnStat)?{ ?????????//?Wait?a?little?while?for?an?event?to?occur. ?????????dwRes?=?WaitForSingleObject(osStatus.hEvent,?STATUS_CHECK_TIMEOUT); ?????????switch(dwRes) ?????????{ ?????????????//?Event?occurred. ?????????????case?WAIT_OBJECT_0:? ?????????????????if?(!GetOverlappedResult(hComm,?&osStatus,?&dwOvRes,?FALSE)) ????????????????????//?An?error?occurred?in?the?overlapped?operation; ????????????????????//?call?GetLastError?to?find?out?what?it?was ????????????????????//?and?abort?if?it?is?fatal. ?????????????????else ????????????????????//?Status?event?is?stored?in?the?event?flag ????????????????????//?specified?in?the?original?WaitCommEvent?call. ????????????????????//?Deal?with?the?status?event?as?appropriate. ????????????????????ReportStatusEvent(dwCommEvent); ?????????????????//?Set?fWaitingOnStat?flag?to?indicate?that?a?new ?????????????????//?WaitCommEvent?is?to?be?issued. ?????????????????fWaitingOnStat?=?FALSE; ?????????????????break; ?????????????case?WAIT_TIMEOUT: ?????????????????//?Operation?isn't?complete?yet.?fWaitingOnStatusHandle?flag? ?????????????????//?isn't?changed?since?I'll?loop?back?around?and?I?don't?want ?????????????????//?to?issue?another?WaitCommEvent?until?the?first?one?finishes. ?????????????????// ?????????????????//?This?is?a?good?time?to?do?some?background?work. ????????????????DoBackgroundWork(); ?????????????????break;??????????????????????? ?????????????default: ?????????????????//?Error?in?the?WaitForSingleObject;?abort ?????????????????//?This?indicates?a?problem?with?the?OVERLAPPED?structure's ?????????????????//?event?handle. ????????????????CloseHandle(osStatus.hEvent); ????????????????return?0; ?????????} ??????} ???} ???CloseHandle(osStatus.hEvent); |
上面的代碼片段與重疊讀取操作的代碼非常相似。實際上,MTTTY使用WaitForMultipleObjects在同一個線程中等待讀取完成或者狀態改變事件發生。
SetCommMask和WaitCommEvent有兩種很有意思的邊際效應。第一,如果以非重疊方式打開通信端口,WaitCommEvent將阻塞直到某事件發生。如果其他線程調用SetCommMask設置新的事件掩碼,則線程將阻塞在SetCommMask調用上,原因是第一個線程的WaitCommEvent調用仍在執行中。SetCommMask將一直阻塞調用線程,直到第一個線程的WaitCommEvent調用返回。這種邊際效應對于以非重疊方式打開的端口是通用的。如果某線程阻塞在任何通信函數上,則第二個線程對任何通信函數的調用都將阻塞,直到第一個線程的函數調用返回。第二種邊際效應是關于以重疊方式打開的端口的。如果使用SetCommMask設置新的事件掩碼,則未決的WaitCommEvent調用將成功完成,導致調用完成的事件掩碼將是NULL。
?
總結
以上是生活随笔為你收集整理的Win32 串口编程(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。