串口 (COM) 在工控、儀器、POS、嵌入式通訊中極為普遍。Windows 提供 CreateFile/ReadFile/WriteFile 等 API,但直接使用繁瑣且易出錯。本文提供一個經多平台 (BC/BCB/VC/BCBX/GCC) 驗證的 C++ 串口類庫,採分層架構:
_base_com:抽象基類,定義純虛擬介面,便於擴充。_sync_com:同步阻塞 I/O,適合簡單輪詢/指令回應場景。_asyn_com:非同步重疊 I/O (OVERLAPPED),適合高效能、NT 核心系統。_thread_com:含監控執行緒的非同步類,支援視窗訊息通知與繼承擴充,適合複雜 GUI 應用。class _base_com {
public:
virtual bool open(int port, const char* param = "9600,8,n,1") = 0;
virtual void close() = 0;
virtual int write(const void* buf, int len) = 0;
virtual int read(void* buf, int maxlen) = 0;
virtual ~_base_com() {}
};
class _sync_com : public _base_com { /* 同步實作 */ };
class _asyn_com : public _base_com { /* 非同步實作 */ };
class _thread_com : public _asyn_com { /* 執行緒監控 + 訊息通知 */ };
#include "com_class.h"
char str[] = "com_class test";
_sync_com com1;
com1.open(1); // COM1, 9600,8,n,1
for (int i = 0; i < 100; ++i) {
Sleep(500);
com1.write(str, strlen(str));
}
com1.close();
_asyn_com com2;
com2.open(2, "115200,8,n,1");
// 非同步寫入立即返回
com2.write(txBuf, txLen);
// 非同步讀取需配合 GetOverlappedResult 或事件等待
// 通常搭配 _thread_com 使用
class CMyComm : public _thread_com
{
protected:
virtual void OnDataReceived(const BYTE* data, int len)
{
// 收到資料,發送自訂訊息到主視窗
::PostMessage(m_hNotifyWnd, WM_USER_RX_DATA, (WPARAM)len, (LPARAM)data);
}
virtual void OnError(DWORD errCode)
{
::PostMessage(m_hNotifyWnd, WM_USER_COMM_ERROR, errCode, 0);
}
};
// 使用
CMyComm comm;
comm.SetNotifyWnd(m_hWnd); // 設定接收訊息視窗
comm.open(1, "9600,8,n,1");
// 主視窗訊息映射處理 WM_USER_RX_DATA / WM_USER_COMM_ERROR
// 程式結束
comm.close();
| 特性 | 同步 | 非同步 | 執行緒監控 |
|---|---|---|---|
| 阻塞模式 | 是 | 否 | 否 |
| CPU 佔用 | 高 (輪詢) | 低 (事件驅動) | 低 |
| 收發緩衝 | 自管 | 系統/自管 | 自管 + 迴圈緩衝 |
| 錯誤處理 | 返回碼 | 事件/返回碼 | 虛擬函式回呼 |
| 跨平台 | 全支援 | Win32 (NT核心) | Win32 |
"baud,parity,data,stop" 字串 → BuildCommDCB → SetCommState。SetCommTimeouts 設定 ReadIntervalTimeout, ReadTotalTimeoutMultiplier 等,避免永久阻塞。WaitCommEvent + OVERLAPPED 監聽 EV_RXCHAR, EV_TXEMPTY, EV_ERR。SetCommMask(0) 取消事件等待。CloseHandle 串口、事件、執行緒控制碼,析構函式自動釋放。完整原始碼 com_class.h/cpp 含四層類別實作、參數解析、錯誤代碼定義、測試主程式,可直接整合至專案。