造冰箱的大熊貓@cnblogs 2019/1/27
將Windows下串口編程相關信息進行下簡單小結,以備后用。
1、打開串口
打開串口使用CreateFile()函數。以打開COM6為例:
HANDLE hComm; hComm = CreateFile( TEXT("COM6"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
其中:
- "COM6",待打開串口的串口名。
- GENERIC_READ | GENERIC_WRITE,串口讀寫權限。
- 0,固定值。
- NULL,指向SECURITY_ATTRIBUTES的指針。通常設置為NULL,此時CreateFile()函數返回的句柄不能被子進程繼承。
- OPEN_EXISTING,固定值。
- FILE_ATTRIBUTE_NORMAL,文件屬性。
- NULL,固定值。
- hComm,函數返回的句柄。如果打開串口成功,則在后續操作中使用該句柄訪問串口。如果打開串口失敗,函數返回句柄為INVALID_HANDLE_VALUE。
這里兩點需要說明:
一是CreateFile()、CreateFileA()[1]和CreateFileW()[2]的區別。在大部分說明如何使用Win32 API打開串口的文檔中都介紹用CreateFile()函數打開串口,但某些文檔中卻使用CreateFileA()或CreateFileW()函數。實際上三個函數的功能是相同的,只是所采用的字符串編碼格式不同。CreateFileA()函數名中的A代表ANSI,而CreateFileW()中的W代表UNICODE。所謂ANSI編碼,是各國根據自己的語言定義的字符編碼格式,其中0~0x7F與ASCII字符相同,其余則與具體語言相關。因此,中文ANSI編碼(GB2312)和日文ANSI編碼無法互通。UNICODE則是將所有語言的編碼進行統一,用同一個編碼空間覆蓋所有語言文字。從下面的代碼中可以清楚地看出三個函數的關系。 在前面CreateFile()示例中,TEXT宏的用途就是根據當前操作系統的編碼格式對字符串"COM6"進行適當的格式轉換。
HANDLE CreateFileA( __in LPCSTR lpFileName, __in DWORD dwDesiredAccess, __in DWORD dwShareMode, __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, __in DWORD dwCreationDisposition, __in DWORD dwFlagsAndAttributes, __in_opt HANDLE hTemplateFile ); HANDLE CreateFileW( __in LPCWSTR lpFileName, __in DWORD dwDesiredAccess, __in DWORD dwShareMode, __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, __in DWORD dwCreationDisposition, __in DWORD dwFlagsAndAttributes, __in_opt HANDLE hTemplateFile ); #ifdef UNICODE #define CreateFile CreateFileW #else #define CreateFile CreateFileA #endif
二是對於串口號大於9的串口(例如COM12),在CreateFile()函數中串口名應寫作"\.\COM12"。
2、關閉串口
關閉串口則使用CloseHandle()函數。示例如下:
CloseHandle(hComm);
3、配置串口工作參數
以設置串口為波特率115200,數據位8bit,停止位1bit為例:
DCB dcb; GetComm(hComm, &dcb); dcb.BaudRate = CBR_115200; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; SetCommState(hComm, &dcb);
4、寫串口
以發送字符串"abcd"為例:
char buf[] = "abcd"; DWORD buf_len = 4; // 待寫入串口的字節數 DWORD written_cnt; // 實際寫入串口的字節數 WreteFile( hComm, (void *)buf, buf_len, &written_cnt, NULL );
5、讀串口
以讀取12個字符為例:
char buf[128]; DWORD toread_cnt = 12; // 要從串口讀入的字節數 DWORD read_cnt; // 實際從串口讀入的字節數 ReadFile( hComm, (void *)buf, toread_cnt, &read_cnt, NULL );
6、清除串口緩沖區
當串口接收到一個字節時,串口驅動程序將接收到的字節寫入內存的某個位置(輸入緩沖區)。當應用程序讀取串口時,操作系統按照“先進先出”的原則從輸入緩沖區取出數據交給應用程序。在某些應用場景下,應用程序需要舍棄輸入緩沖區內當前數據。這可通過PurgeComm()函數實現。
PurgeComm( hComm, PURGE_RXCLEAR );
7、其它
在Windows操作系統中,計算機上實際存在的或者虛擬的通信端口,包括串口和並口等,統稱為通信資源(Communication Resource)。本文總結的串口編程信息對通信資源也是適用的。
本文只涉及簡單的串口讀寫操作,對於流量控制、異步讀寫、讀寫操作超時等復雜的串口控制,請參考相關函數微軟文檔中的詳細說明。
參考資料:
[1] 函數CreateFileA()說明 @ Microsoft