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