C++串口編程


介紹

在Windows的操作系統上,將串口(通信設備)作為文件來處理,所以串口的打開、關閉、讀寫所使用的API函數與文件操作一樣。所以打開串口使用CreateFile函數,讀寫串口使用ReadFile、WirteFile函數,關閉串口使用CloseHandle函數。

CreateFile

這個函數的功能是創建或者打開一個文件或者I/O設備,通常使用的I/O形式有文件、文件流、目錄、物理磁盤、卷、終端流等。如果執行成功,則返回文件句柄,INVALID_HANDLE_VALUE表示出錯,會設置GetLastError

函數聲明定義:

WINBASEAPI
HANDLE
WINAPI
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
    );

參數列表:

參數 類型
lpFileName string,要打開的文件的名稱
dwDesiredAccess Long,如果為GENERIC_READ表示允許對設備進行讀訪問;如果未GENERIC_WRITE表示允許對設備進行寫訪問(可組合使用);如果為0,表示只允許獲取與一個設備有關的信息。
dwShareMode Long,零表示不共享;FILE_SHARE_READ和FILE_SHARE_WRITE表示允許對文件進行共享訪問。
lpSecurityAttributes SECURITY_ATTRIBUTES,指向一個SECURITY_ATTRIBUTES結構的指針,定義了文件的安全特性
dwCreationDisposition Long,下述常數之一:CREATE_NEW創建文件;如文件存在則會出錯。CREATE_ALWAYS創建文件,會改寫前一個文件。OPEN_EXISTING文件必須已經存在。OPEN_ALWAYS如文件不存在則創建它。TRUNCATE_EXISTING將現有文件縮短為零長度。
dwFlagsAndAttributes Long,一個或多個下述常數:FILE_ATTRIBUTE_ARCHIVE標記已歸檔屬性;FILE_ATTRIBUTE_COMPRESSED將文件標記為已壓縮,或者標記為文件在目錄中的默認壓縮方式;FILE_ATTRIBUTE_NORMAL默認屬性;
FILE_ATTRIBUTE_HIDEN隱藏文件或目錄;FILE_ATTRIBUTE_READONLY文件只讀;FILE_ATTRIBUTE_SYSTEM文件為系統文件;FILE_FLAG_WRITE_THROUGH操作系統不得延遲對文件的寫操作;FILE_FLAG_OVERLAPPED允許對文件進行重疊操作;FILE_FLAG_NO_BUFFERING禁止對文件進行緩沖處理。文件只能寫入磁盤卷的扇區塊;FILE_FLAG_RANDOM_ACCESS針對隨機訪問對文件緩沖進行優化;FILE_FLAG_SEQUENTIAL_SCAN針對連續訪問對文件緩沖的優化;FILE_FLAG_DELETE_ON_CLOSE關閉了上一次打開的句柄后,將文件刪除。特別適合臨時文件。
hTemplateFile Long,如果不為零,則指定一個文件句柄。新文件將從這個文件中復制擴展屬性
  1. lpFileName:指定要打開的串口邏輯名稱,用字符串表示。如COM1、COM2,分別表示串口1和串口2.
  2. dwDesiredAccess:端口屬性的訪問類型
  3. dwShareModel指定端口的共享屬性
    該參數是由那些應用程序共享文件提供。對於串口來說,是不能共享的,因此,必須設置為0,這是通信設備與文件的特殊差別。

如果當前的應用程序調用CreateFIle打開一個串口,另外一個程序已經打開了串口,此時CreateFile會返回一個錯誤代碼

然而,同一個應用程序的多個線程是可以共享CreateFile返回的端口句柄。並且根據安全屬性設置,該句柄可以打開端口的應用程序的子程序來繼承。

  1. lpSecurityAttributes:安全屬性,一般該參數為NULL,即該端口被設置為缺省的安全屬性。缺省安全屬性下,端口的句柄是不能繼承的。
  2. dwCreateDisposition:指定此端口正在被其它程序占用采取的動作,因為串口總是存在的,因此必須設置為OPEN_EXISTING,該標志告訴Windows不要創建新的端口。而是打開一個已經存在的端口。
  3. dwFlagsAndAttributes:描述了端口的各種屬性,對於文件來說有很多屬性,但是對於串口來說,唯一的意義是FILE_FLAG_OVERLAPPED屬性,當設置該屬性時,端口IO可以在后台運行,稱為異步IO重疊結構。
  4. hTemplateFIle:指定模板的文件句柄,對於串口來說,此參數必須設置為0
    用CreateFile函數打開串口COM1的示例如下:
HANDLE hCom;
DWORD dwError;
hCom = ::CreateFile(L"COM1", //這是串口號
    GENERIC_READ | GENERIC_WRITE, // 允許讀和寫
    0, // 獨占方式
    NULL,
    OPEN_EXISTING, // 打開而不是創建
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //異步I/O重疊結構 
    nullptr);
if (hCom == INVALID_HANDLE_VALUE) //判斷端口是否被正常打開
{
    dwError = ::GetLastError(); //獲取錯誤代碼
}

關閉串口

關閉串口,使用CloseHandle,函數聲明為:

BOOL CloseHandle(
  HANDLE hObject
)

函數比較簡單,參數是使用CreateFile打開的端口句柄。調用這個函數可以實現串口關閉。
示例如下:

if (::CloseHandle(hCom) == 0) //調用該函數關閉串口
  {
      // 關閉成功
  }
  else
  {
      // 關閉失敗
  }

ReadFile

從文件指針指向的位置(設備文件,通信)開始將數據讀出到一個文件中,且支持同步和異步操作,如果文件打開方式沒有指明FILE_FLAG_OVERLAPPED的話,當程序調用成功時,它將實際讀出文件的字節數保存到lpNumberOfBytesRead指明的地址空間中。FILE_FLAG_OVERLAPPED允許對文件進行重疊操作。

BOOL
WINAPI
ReadFile(
    _In_ HANDLE hFile, //文件屬性
     LPVOID lpBuffer, // 接收數據用的buffer
    _In_ DWORD nNumberOfBytesToRead, // 要讀取的字節數
    _Out_opt_ LPDWORD lpNumberOfBytesRead, // 實際讀取的字節數
    _Inout_opt_ LPOVERLAPPED lpOverlapped // OVERLAPPED結構,一般設定為NULL
    );

示例:

 char ch[1024] = { 0 };
DWORD readLen = 0;
do {
    ZeroMemory(ch, 1024);
    if (::ReadFile(hCom, ch, 1024, &readLen, nullptr))
    {
        if (readLen > 0)
        {
            cout << ch << endl;
        }
    }
} while (true);

WriteFile

將數據寫入一個文件(設備文件,通信)。該函數比fwrite函數靈活的多。也可以將這個函數應用於通信設備、管道、套接字以及郵槽的處理。返回時,TRUE(非零)表示成功,否則返回零。會設置GetLastError。

函數聲明定義:

BOOL
WINAPI
WriteFile(
    _In_ HANDLE hFile, // 文件句柄
     LPCVOID lpBuffer, //要寫入的數據buffer
    _In_ DWORD nNumberOfBytesToWrite, // 要寫入的數據長度
    _Out_opt_ LPDWORD lpNumberOfBytesWritten, // 實際寫入的字節數
    _Inout_opt_ LPOVERLAPPED lpOverlapped // OVERLAPPED結構,一般設定為NULL
    );

示例代碼:

char ch[1024] = "這是測試數據";
DWORD writeLen = 0;
do {
    DWORD sendLen = strlen(ch);
    if (::WriteFile(hCom, ch, sendLen, &writeLen, nullptr))
    {
        cout << "寫入成功,字節數:" << writeLen << endl;
    }
    Sleep(1000);
} while (true);

GetCommState

一旦串口打開,就可以對該串口的屬性進行讀取和設置。由於串口的屬性非常復雜,通常采用讀取該串口當前狀態值,然后在此基礎上進行修改的方法。

示例:

DCB dcb = { 0 }; // 設備控制塊DCB。幾乎所有的串口屬性和狀態都存儲在該結構的成員變量中
dcb.DCBlength = sizeof(DCB);

if (::GetCommState(hCom, &dcb))
{
    
}

SetCommState

設置串口屬性

示例:

 dcb.BaudRate = CBR_115200; //設置波特率為115200
    ::SetCommState(hCom, &dcb);

分配接收和發送緩存區

::SetupComm(hCom, 1024, 1024);

清空接收和發送緩沖區

在進行串口發送和接收數據操作之前,最好使用PurgeComm函數將串口發送緩沖區和接收緩沖區中的數據清空。

::PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

GetCommTimeouts

GetCommTimeouts和SetCommTimeouts用於設置串口接收發送數據的超時參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM