c
作者:付林林
網上已經有CE下串口通信的文章了。我之所以發表同樣內容的文章是因爲我的文章是一系列的,不會因爲別人寫過我就不寫了。另外我對串口通信有着自己的觀點。
現在大多數的筆記本電腦都沒有外置串口,這不奇怪,因爲有更快更穩定的接口代替了串口。不過基於 Windows CE 的設備仍然保留着串口,而且目前看來串口的地位暫時不會動搖。目前流行的基於CE的設備很多都具有像導航、打電話等功能,而GPS、GSM/GPRS模塊都是外置串口的終端設備,你想不用串口都不行。
上面我說了我有着自己的觀點,我的觀點就是不要把串口通信封裝成類。我不明白爲什麼有些人總要把串口封裝成類呢。把一個事物封裝成類,那這個事物就一定是不易改變的,如果每次編寫都要修改,那封裝成類就一點意義都沒有了。設想如果MFC類總要改變的話,那我們用MFC編的程序也要修改同樣次數了。如果編寫超級終端一類的程序倒是可以將串口封裝成類,因爲超級終端只管輸入命令和顯示輸出數據,不對輸出數據進行處理,那讀串口的函數就可以一直使用而不必更改。但事實上串口通信大多數用來與終端設備進行通信,需要對終端設備返回的數據進行處理。而返回的數據在什麼時間返回、數據量的大小不是確定的,非要封裝成類難度很大。
正如CE的幫助文檔所說,串口通信是最簡單的通信之一。稍麻煩的是在讀數據方面。
一、打開串口
hSerial = CreateFile(L"COM1:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(m_hSerial == NULL) { ///L"串口打開失敗"; return; } ///配置串口 DCB PortDCB; PortDCB.DCBlength = sizeof(DCB); // 默認串口參數 GetCommState(hSerial, &PortDCB); PortDCB.BaudRate = 115200; // baud PortDCB.ByteSize = 8; // Number of bits/byte, 4-8 PortDCB.Parity = NOPARITY; PortDCB.StopBits = ONESTOPBIT; if (! SetCommState(hSerial, &PortDCB)) { ///L"配置串口失敗"; return; } ////配置超時值 COMMTIMEOUTS CommTimeouts; GetCommTimeouts(m_hSerial, &CommTimeouts); CommTimeouts.ReadIntervalTimeout = MAXDWORD; CommTimeouts.ReadTotalTimeoutMultiplier = 10; CommTimeouts.ReadTotalTimeoutConstant = 10; CommTimeouts.WriteTotalTimeoutMultiplier = 50; CommTimeouts.WriteTotalTimeoutConstant = 100; if (!SetCommTimeouts(hSerial, &CommTimeouts)) { ///L"不能設置超時參數"; return; }
CE的串口驅動不支持重疊,這個大家都知道的。這樣的話收和發就要分開。要接收串口數據就必須創建一個線程專門用於接收數據。串口的配置不需要設置很多參數,默認的配置大部分是不需要修改的。一般改動就是波特率、位數、奇偶校檢等幾項。超時值是需要改動的。ReadIntervalTimeout是指兩個字符傳送之間的超時時間。一次寫操作的超時時間等於WriteTotalTimeoutMultiplier 乘以 要發送的字符數 加上WriteTotalTimeoutConstant。 單位是毫秒。讀操作的超時和寫類似。所以設置超時是一個關鍵。設置太小可能丟失數據。
二、關閉串口
關閉串口用關閉句柄函數。
if(hSerial != NULL) { CloseHandle(hSerial); hSerial = NULL; }
三、向串口發送數據
WriteFile (hSerial, // 句柄 &Byte, // 數據緩衝區地址 nByte, // 數據大小 &dwNumBytes, // 返回發送出去的字節數 NULL // 不支持重疊 );
向串口發送數據一般都會成功。需要注意的是如果終端設備需要一定處理時間或者稱反應時間的話,那麼兩個寫操作之間一定要注意時間間隔不能太小。具體的時間由終端設備的反應時間和緩衝區大小有關。
四、讀取串口數據
串口麻煩就麻煩在讀取數據上。除了考慮及時的讀取數據外,還要解決接收到的數據的處理工作。如果在讀取串口數據的線程中安置數據處理工作,那麼可能會丟失數據(終端設備發送數據但是沒收到),也有可能不會丟失(終端設備發送的數據的時間、大小都是確定的)。如果肯定接收的數據在處理工作結束後終端設備才發送數據,那麼完全可以將數據處理工作放在讀取串口的線程中。對於及時的讀取數據,下面提供了一種解決辦法:
*** 假設接收的都是字符 *** UINT ReadThread(LPVOID pParam) ?////接收串口數據線程 { HANDLE hPort = *(HANDLE*)pParam; BYTE Byte; int iCounter = 0; DWORD dwBytes; char ReceiveBuf[1000]; ///緩衝區的大小 SetCommMask (hPort, EV_RXCHAR); ///只接收字符 while (hPort != INVALID_HANDLE_VALUE) { DWORD dwCommStatus; WaitCommEvent(hPort, &dwCommStatus, 0); SetCommMask (hPort, EV_RXCHAR); ///重新設置要等待的信號 //// 接收數據 do { ReadFile(hPort, &Byte, 1, &dwBytes, 0); if(dwBytes == 1) { ReceiveBuf[iCounter++] = Byte; if(iCounter == 1000) { ///L"接收緩衝區已滿"; return -1; } } } while (dwBytes == 1); if(iCounter == 0) ?////沒接到數據 { continue; } //////保存數據 char* pTmp = new char[iCounter + 1]; if(pTmp == NULL) { ///L"內存不足,接收串口數據線程關閉"; return -1; } memcpy(pTmp, ReceiveBuf, iCounter); pTmp[iCounter] = NULL; ////字符串結尾 ////////創建新線程處理數據 ////在ProcessData函數中處理數據。別忘了delete[] pTmp; AfxBeginThread(ProcessData, pTmp); iCounter = 0; ////清空計數器 } ///////end while return 0; }
寫作時間:2004-08-22
未經本文作者同意,不準擅自轉載本篇文章。聯繫作者請郵至 [email protected] 或[email protected]
MSN Messenger:[email protected]