串口通信模块3:串口通信编程基础(读写、关闭)
上一節(jié)總結(jié)了如何打開串口并討論了如何配置串口,本節(jié)是在上一節(jié)的基礎(chǔ)上,進(jìn)一步討論串口編程的基礎(chǔ)——如何進(jìn)行文件讀寫?如何關(guān)閉串口?
1. 讀寫串口
串口的讀寫操作和文件的讀寫操作是一樣的,也是通過ReadFile()及WriteFile()函數(shù)來實現(xiàn)的。這兩個函數(shù)的原型分別如下:
寫文件函數(shù)原型及說明:
BOOL WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped, ); 該函數(shù)包含5各參數(shù),其具體意義為:
hFile:打開串口時返回的句柄。
lpBuffer:寫入的數(shù)據(jù)存儲的地址,即以該指針得值為首地址的nNumberOfBytesToWrite個字節(jié)的數(shù)據(jù),將要寫入串口的發(fā)送數(shù)據(jù)緩沖區(qū)。
nNumberOfBytesToWrite:要寫入的數(shù)據(jù)的字節(jié)數(shù)
lpNumberOfByteWritten:指向一個DWORD數(shù)值,該數(shù)值返回實際寫入的字節(jié)數(shù)。
lpOverlapped:重疊操作時,該參數(shù)指向一個OVERLAPPED結(jié)構(gòu),同步操作時,該參數(shù)為NULL.
讀文件函數(shù)原型及說明:
再用ReadFile()和WriteFile()函數(shù)讀寫串口時,即可以同步執(zhí)行也可以重疊執(zhí)行。再同步執(zhí)行時,函數(shù)直到操作完成后才返回。這意味著同步執(zhí)行時線程會被阻塞,從而導(dǎo)致效率下降。在重疊操作時,即時操作還未完成,這兩個函數(shù)也會立即返回,費(fèi)事的I/O操作在后臺運(yùn)行。
而在調(diào)用CreateFile()函數(shù)打開串口時,就已經(jīng)決定了ReadFile()和WriteFile()函數(shù)對串口的操作是同步還是異步。如果在調(diào)用CreateFile()函數(shù)創(chuàng)建打開串口時指定了FILE_FLAG_OVERLAPPED標(biāo)志,那么調(diào)用ReadFile()和WriteFile()函數(shù)對該打開串口時返回的句柄進(jìn)行的操作就是重疊的。如果沒有指定重疊標(biāo)志,那么讀寫操作就應(yīng)該是同步的。這里強(qiáng)調(diào)的是:ReadFile()和WriteFile()函數(shù)的同步或異步選擇應(yīng)該和CreateFile()函數(shù)相一致。
說明:ReadFile()函數(shù)只要在串口輸入緩沖區(qū)中讀入指定數(shù)量的字符,就算完成了工作。然而,WriteFile()函數(shù)不但要把指定數(shù)量的字符復(fù)制到輸出緩沖區(qū),而且要等這些字符從創(chuàng)航口送出去才算完成操作。
由于同步讀寫串口的實現(xiàn)很簡單,先研究同步串口讀寫的代碼:
//同步讀串口代碼 bool ReadCom(char * str, int len) {DWORD wCount; //讀取的字節(jié)數(shù)BOOL bReadStat;bReadStat = ReadFile( hCom, str, len, &wCount, NULL);if (!bReadStat){AfxMessageBox(" 讀串口失敗! ");return FALSE;}return TRUE; }
異步讀寫串口的實現(xiàn)就比較靈活了,即可以實現(xiàn)非阻塞讀寫,也可以實現(xiàn)阻塞讀寫。有兩種方法可以等待操作完成而實現(xiàn)阻塞讀寫。
# 應(yīng)用像WaitForSingleObject()等待函數(shù)一樣來等待OVERLAPPED結(jié)構(gòu)的hEvent成員。
# 調(diào)用GetOverlappedResult()函數(shù)等待
在OVERLAPPED結(jié)構(gòu)中包含了重疊I/O的一些信息,它的詳細(xì)定義如下:
typedef struct _OVERLAPPED {DWORD Internal; //操作系統(tǒng)保留,指出一個和系統(tǒng)相關(guān)的狀態(tài)DWORD InternalHigh;//指出發(fā)送或接收的數(shù)據(jù)長度DWORD Offset; //文件傳送的開始位置DWORD OffsetHigh; //文件傳送字節(jié)變一輛的高字節(jié)HANDLE hEvent; //指定一個I/O操作完成后觸發(fā)的事件 }OVERLAPPED;在使用ReadFile()和WriteFile()函數(shù)進(jìn)行異步重疊操作時,線程需要創(chuàng)建OVERLAPPED結(jié)構(gòu)以供這兩個函數(shù)使用。線程通過OVERLAPPED結(jié)構(gòu)獲得當(dāng)前的操作狀態(tài),該結(jié)構(gòu)的成員是hEvent。 hEvent是讀寫事件,當(dāng)串口使用異步通信時,函數(shù)返回時可能還沒有完成,程序可以通過檢查該事件的值是否讀寫完畢。當(dāng)調(diào)用ReadFile()或WriteFile()函數(shù)的時候,該成員會自動被指為無信號狀態(tài);當(dāng)重疊操作完成后,該成員變量會自動被置為有信號狀態(tài)。
而GetOverlappedResult()函數(shù)返回重疊操作結(jié)束有點(diǎn)不同,他是通過判斷OVERLAPPED結(jié)構(gòu)中的hEvent是否被置位,來判斷異步操作是否完成,函數(shù)原型如下:
BOOL GetOverlappedResults(HANDLE hFile, //串口的句柄LPOVERLAPPED lpOverlapped, //重疊操作開始時指定的OVERLAPPED結(jié)構(gòu)LPWORD lpNumberOfBytesTransferred, //實際讀寫操作傳輸?shù)淖止?jié)數(shù)BOOL bWait //用于指定函數(shù)是否一直等到重疊操作結(jié)束 );在異步操作前應(yīng)先使用ClearCommError()函數(shù)獲取尚未讀取的字節(jié)數(shù),函數(shù)原型如下:
BOOL ClearComError(HANDLE hFile, //串口句柄LPDWORD lpErrors, //指向接受錯誤碼的變量LPCOMSTAT lpStat //指向通信狀態(tài)緩存區(qū) );根據(jù)以上信息可以編寫異步讀串口的程序:
bool ReadCom(char* str, DWORD *len) {COMSTAT ComStat;DWORD dwErrorFlags;OVERLAPPED m_osRead;memset(&m_osRead,0,sizeof(OVERLAPPED));m_osRead.hEvent = CreateEveent(NULL, TRUE, FALSE, NULL);ClearCommError(hCom, &dwErrorFlags, &ComStat);dwBytesRead = min(len, (DWORD)ComStat.cbInQue);//獲取尚未讀取的字節(jié)數(shù)if (!dwBytesRead)return FALSE;BOOL bReadStatus;bReadStatus = ReadFile(hCom, str, len, &len, &m_osRead);//讀取數(shù)據(jù)if (!bReadStatus){//錯誤處理if (GetLastError == ERROR_IO_PENDING){ //串口正在進(jìn)行讀操作//等到讀操作完成或延時已經(jīng)達(dá)到2秒WaitForSingleObject(m_osRead.hEvent,2000);PurgeComm(hCom,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);}//清空串口緩沖return false;}//清空串口緩存區(qū)PurgeComm(hCom,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);return true; }
2. 關(guān)閉串口
利用API函數(shù)關(guān)閉串口是非常簡單的活兒,只需要使用CreateFile()函數(shù)返回的句柄作為參數(shù)調(diào)用CloseHandle()函數(shù)即可。CloseHandle()函數(shù)如下:
BOOL CloseHandle(HANDLE hObject; ); 到此,串口編程的基礎(chǔ)就OK了,明天繼續(xù)研究自定義串口類,以及界面設(shè)計的幾點(diǎn)敲門,晚安!!
總結(jié)
以上是生活随笔為你收集整理的串口通信模块3:串口通信编程基础(读写、关闭)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国企业即时通讯
- 下一篇: 【绿色版】飞鸽传书2011绿色版