首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Win32 API 實現串列通訊完整指南:從開啟埠到非同步收發

     編輯:關於C++

DOS 時代透過中斷直接控制序列埠,Windows 則完全接管硬體資源,禁止直接操作中斷,改提供功能強大的 Win32 API 進行串列通訊。本文系統整理常用 API、DCB 設定、逾時控制、同步/非同步讀寫模式,並提供可直接複用的串列埠控制類別架構。

核心 API 函數總覽

函數功能
CreateFile開啟序列埠(同樣用於檔案、管道等)
GetCommState / SetCommState獲取/設定裝置控制區塊 (DCB)
BuildCommDCB依字串格式填充 DCB(如 "9600,N,8,1")
GetCommTimeouts / SetCommTimeouts獲取/設定通訊逾時參數
SetCommMask設定監控事件(收發字元、CTS 變化等)
WaitCommEvent等待監控事件發生
ReadFile / WriteFile讀取/寫入資料
GetOverlappedResult取得非同步操作結果
PurgeComm清空緩衝區、終止掛起操作
ClearCommError更新狀態、清除硬體錯誤
CloseHandle關閉序列埠控制代碼

開啟序列埠:CreateFile 參數詳解

HANDLE hComm = CreateFile(
    "COM1",                       // lpFileName: 埠名
    GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess: 讀寫權限
    0,                            // dwShareMode: 序列埠不支援共享
    NULL,                         // lpSecurityAttributes
    OPEN_EXISTING,                // dwCreationDisposition: 必須為開啟現有
    FILE_FLAG_OVERLAPPED,         // dwFlagsAndAttributes: 非同步模式關鍵旗標
    NULL                          // hTemplateFile
);

成功返回控制代碼,失敗返回 INVALID_HANDLE_VALUE (0xFFFFFFFF)。

序列埠參數配置:DCB 與逾時

DCB 關鍵欄位

DCB dcb;
GetCommState(hComm, &dcb); // 先取得目前設定
dcb.BaudRate = 9600;       // 鮑率
dcb.ByteSize = 8;          // 資料位
dcb.Parity = NOPARITY;     // 無奇偶校驗
dcb.StopBits = ONESTOPBIT; // 1 停止位
SetCommState(hComm, &dcb); // 套用設定

或使用 BuildCommDCB("9600,N,8,1", &dcb) 一次完成。

COMMTIMEOUTS 結構與策略

COMMTIMEOUTS cto = {0};
cto.ReadIntervalTimeout = 1000;        // 字元間最大間隔
cto.ReadTotalTimeoutMultiplier = 1000; // 讀取總時間乘數
cto.ReadTotalTimeoutConstant = 1000;   // 讀取總時間常數
cto.WriteTotalTimeoutMultiplier = 1000;
cto.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(hComm, &cto);

關鍵行為:若 ReadIntervalTimeout = MAXDWORD 且其他兩者為 0,ReadFile 立即返回已收資料(非阻塞輪詢模式)。

事件驅動非同步收發架構

監控事件設定

DWORD dwCommEvents = EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_BREAK | EV_ERR;
SetCommMask(hComm, dwCommEvents);

讀取執行緒流程

  1. 呼叫 WaitCommEvent (搭配 OVERLAPPED) 等待事件。
  2. 事件觸發後,檢查事件類型。
  3. 若為 EV_RXCHAR,呼叫 ReadFile 讀取資料。
  4. 使用 GetOverlappedResult 等待讀取完成。
  5. 將接收資料透過 PostMessage 傳送給主視窗處理。

寫入策略

因發送資料量通常較小,可採用同步 WriteFile 簡化實作;大量傳輸時改用非同步 + GetOverlappedResult。

完整串列埠控制類別設計

檔案結構:

  • COM.h / COM.cpp:主控制類別 TSerialPort
  • COMThread.h / COMThread.cpp:接收執行緒類別

使用範例

// 1. 建立實例並初始化
TSerialPort *SerialPort = new TSerialPort();
SerialPort->InitPort(this, 1, 9600); // 埠號 1 (COM1), 9600,N,8,1
SerialPort->StartMonitoring();       // 啟動監控執行緒

// 2. 映射接收訊息 (於視窗類別宣告)
void __fastcall OnComRx(TMessage &Message);
BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_COMM_RXCHAR, TMessage, OnComRx)
END_MESSAGE_MAP(TForm)

// 3. 實作接收處理
void __fastcall TMyForm::OnComRx(TMessage &Message) {
    unsigned char ucRxData = (unsigned char)Message.WParam;
    // 處理接收位元組...
}

// 4. 發送資料
SerialPort->WriteToPort(0x55); // 發送單一位元組
// 或批次發送
SerialPort->WriteBuffer(buffer, length);

關鍵實作細節

  • OVERLAPPED 結構:包含手動重設事件 hEvent,非同步操作的同步核心。
  • 錯誤處理:每個 API 呼叫後檢查返回值,失敗時呼叫 GetLastError() 取得錯誤碼。
  • 資源清理:解構函式中呼叫 PurgeComm、CloseHandle、終止監控執行緒。
  • 跨平台驗證:Win95/98/2000 測試通過,無需修改即可移植至其他 BCB 專案。

總結

掌握 Win32 串列通訊 API,配合非同步事件驅動架構,能構建高效、穩定的工業控制、儀器通訊、嵌入式設備互聯等應用。本文提供的類別封裝大幅降低開發複雜度,開發者可專注於協議邏輯而非底層通訊細節。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved