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

C++ Builder 6 串口通訊程式設計:Windows API 完整實作指南

     編輯:關於C++

背景:從 DOS 到 Windows 的串口程式設計範式轉移

在 DOS/Win9x 時代,程式可直接透過 inport()/outport() 操作硬體 I/O 埠,擁有對串口的完全控制權。自 Windows 2000 起,作業系統實施硬體保護策略,所有硬體存取必須經過核心模式驅動程式中介。開發者必須使用 Windows 通訊 API,達成「裝置獨立性」:程式只需表達意圖(如設定鮑率、讀寫資料),由作業系統轉譯為具體硬體操作。

核心 API 函式詳解

1. CreateFile() - 開啟串口

HANDLE CreateFile(
    LPCTSTR lpFileName,        // "COM1", "COM2"...
    DWORD dwDesiredAccess,     // GENERIC_READ | GENERIC_WRITE
    DWORD dwShareMode,         // 0 (獨佔)
    LPSECURITY_ATTRIBUTES lpSecurityAttributes, // NULL
    DWORD dwCreationDisposition, // OPEN_EXISTING
    DWORD dwFlagsAndAttributes,  // FILE_FLAG_OVERLAPPED (非同步)
    HANDLE hTemplateFile       // NULL
);

範例:

HANDLE hComm = CreateFile("COM1",
    GENERIC_READ | GENERIC_WRITE,
    0, NULL, OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED, 0);

2. CloseHandle() - 關閉串口

BOOL CloseHandle(HANDLE hObject);

3. GetCommState() / SetCommState() - 取得/設定裝置控制區塊 (DCB)

DCB 結構包含鮑率、奇偶校驗、資料位、停止位等參數。標準流程:

DCB dcb;
GetCommState(hComm, &dcb);        // 取得目前設定
dcb.BaudRate = 9600;              // 修改參數
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(hComm, &dcb);        // 套用設定

4. WriteFile() - 寫入資料(非同步)

BOOL WriteFile(
    HANDLE hFile,
    LPCVOID lpBuffer,
    DWORD nNumberOfBytesToWrite,
    LPDWORD lpNumberOfBytesWritten,
    LPOVERLAPPED lpOverlapped
);

範例:

OVERLAPPED ovWrite = {0};
ovWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD bytesSent;
BYTE sendBuf[5] = {1,2,3,4,5};
WriteFile(hComm, sendBuf, 5, &bytesSent, &ovWrite);
// 若非同步待決,需 GetOverlappedResult 等待完成

5. ReadFile() - 讀取資料(非同步)

BOOL ReadFile(
    HANDLE hFile,
    LPVOID lpBuffer,
    DWORD nNumberOfBytesToRead,
    LPDWORD lpNumberOfBytesRead,
    LPOVERLAPPED lpOverlapped
);

讀取前通常先呼叫 ClearCommError() 取得輸入緩衝區資料量:

COMSTAT comStat; DWORD dwError;
ClearCommError(hComm, &dwError, &comStat);
DWORD toRead = comStat.cbInQue;
ReadFile(hComm, buf, toRead, &bytesRead, &ovRead);

6. ClearCommError() - 清除錯誤/取得狀態

回傳 COMSTAT 結構,關鍵欄位:cbInQue(接收緩衝區位元組數)、cbOutQue(發送緩衝區位元組數)。錯誤代碼包含 CE_FRAME、CE_OVERRUN、CE_RXPARITY 等。

7. PurgeComm() - 清除緩衝區

PurgeComm(hComm,
    PURGE_TXABORT | PURGE_RXABORT |
    PURGE_TXCLEAR | PURGE_RXCLEAR);

8. SetCommMask() / WaitCommEvent() - 事件通知機制

兩種讀取模式:

  • 輪詢法:主動定時呼叫 ClearCommError() 檢查 cbInQue
  • 事件通知法(推薦):設定監視事件,專用執行緒呼叫 WaitCommEvent() 等待事件發生,再通知主視窗處理
SetCommMask(hComm, EV_RXCHAR | EV_TXEMPTY); // 監視接收字元、發送緩衝區空

// 監視執行緒
OVERLAPPED os = {0}; os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD dwMask;
if (!WaitCommEvent(hComm, &dwMask, &os)) {
    if (GetLastError() == ERROR_IO_PENDING) {
        GetOverlappedResult(hComm, &os, &dwTrans, TRUE); // 等待事件
        switch (dwMask) {
            case EV_RXCHAR: PostMessage(hwnd, WM_COMM_RXCHAR, 0, 0); break;
            case EV_TXEMPTY: PostMessage(hwnd, WM_COMM_TXEMPTY, 0, 0); break;
            case EV_ERR: /* 處理錯誤 */ break;
        }
    }
}

完整程式架構:雙執行緒模型

主執行緒(UI 執行緒)

  1. 開啟視窗 → WM_CREATE
  2. 呼叫 CreateFile() 開啟串口
  3. 設定 DCB 參數(鮑率、校驗、資料位、停止位)
  4. 呼叫 SetCommMask() 設定監視事件
  5. 建立監視執行緒(CreateThread())
  6. 進入訊息迴圈,處理:使用者發送指令、參數變更、監視執行緒通知訊息(WM_COMM_RXCHAR 等)
  7. 關閉視窗 → WM_DESTROY → 清理資源

監視執行緒

  1. 呼叫 WaitCommEvent() 進入等待狀態
  2. 事件發生 → GetOverlappedResult() 確認完成
  3. 分析 dwMask 判斷事件類型
  4. PostMessage() 通知主視窗
  5. 循環回步驟 1

關鍵實作細節與常見坑點

  • OVERLAPPED 結構初始化:必須歸零並建立有效 hEvent,否則非同步操作會失敗。
  • DCB 結構大小:呼叫 Get/SetCommState 前務必設定 dcb.DCBlength = sizeof(DCB)。
  • 非同步讀寫完整性檢查:務必比對 lpNumberOfBytesWritten/Read 與請求長度,處理部分完成情況。
  • 執行緒同步:共享資料(如緩衝區)需用 Critical Section 或 Mutex 保護。
  • 錯誤處理:每個 API 呼叫後檢查回傳值,失敗時呼叫 GetLastError() 診斷。
  • 資源洩漏防範:所有 CreateEvent()、CreateFile()、執行緒控制代碼必須在結束時 CloseHandle()。

現代化建議

雖然 Win32 串口 API 仍是基礎,但現代專案建議考慮:

  • 使用 C++ 封裝類別(RAII 管理 HANDLE、OVERLAPPED、事件)
  • 採用 I/O 完成連接埠 取代單純事件通知,提升擴展性
  • 考慮跨平台庫如 Boost.Asio(支援串口)、Qt SerialPort
  • 引入 單元測試 模擬串口行為(虛擬串口驅動程式)

總結

Windows 串口程式設計的核心在於掌握 DCB 參數設定、非同步 I/O 機制、事件驅動模型。透過 CreateFile 取得控制代碼、SetCommState 設定參數、SetCommMask+WaitCommEvent 實現高效事件通知、雙執行緒分離 UI 與通訊邏輯,即可建立穩定、高效的串口應用程式。本文涵蓋的 API 組合與架構模式,是 Win32 串口開發的標準範式。

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