1. 程式人生 > >Windows下串口編程

Windows下串口編程

abcd 函數 lpcstr char normal 讀寫權限 進程 設置 數據

造冰箱的大熊貓@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則是將所有語言的編碼進行統一,用同一個編碼空間覆蓋所有語言文字。從下面的代碼中可以清楚地看出三個函數的關系

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

實際上,在前面CreateFile()示例中,TEXT宏的用途就是根據當前操作系統的編碼格式對字符串"COM6"進行適當的格式轉換。

二是對於串口號大於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;

SetComm(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

[2] 函數CreateFileW()說明 @ Microsoft

[3] 結構DCB說明 @ Microsoft

[4] 函數PurgeComm()說明 @ Microsoft

Windows下串口編程