DOS 時代透過中斷直接控制序列埠,Windows 則完全接管硬體資源,禁止直接操作中斷,改提供功能強大的 Win32 API 進行串列通訊。本文系統整理常用 API、DCB 設定、逾時控制、同步/非同步讀寫模式,並提供可直接複用的串列埠控制類別架構。
| 函數 | 功能 |
|---|---|
CreateFile | 開啟序列埠(同樣用於檔案、管道等) |
GetCommState / SetCommState | 獲取/設定裝置控制區塊 (DCB) |
BuildCommDCB | 依字串格式填充 DCB(如 "9600,N,8,1") |
GetCommTimeouts / SetCommTimeouts | 獲取/設定通訊逾時參數 |
SetCommMask | 設定監控事件(收發字元、CTS 變化等) |
WaitCommEvent | 等待監控事件發生 |
ReadFile / WriteFile | 讀取/寫入資料 |
GetOverlappedResult | 取得非同步操作結果 |
PurgeComm | 清空緩衝區、終止掛起操作 |
ClearCommError | 更新狀態、清除硬體錯誤 |
CloseHandle | 關閉序列埠控制代碼 |
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;
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 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);
WaitCommEvent (搭配 OVERLAPPED) 等待事件。EV_RXCHAR,呼叫 ReadFile 讀取資料。GetOverlappedResult 等待讀取完成。PostMessage 傳送給主視窗處理。因發送資料量通常較小,可採用同步 WriteFile 簡化實作;大量傳輸時改用非同步 + GetOverlappedResult。
檔案結構:
COM.h / COM.cpp:主控制類別 TSerialPortCOMThread.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);
hEvent,非同步操作的同步核心。GetLastError() 取得錯誤碼。PurgeComm、CloseHandle、終止監控執行緒。掌握 Win32 串列通訊 API,配合非同步事件驅動架構,能構建高效、穩定的工業控制、儀器通訊、嵌入式設備互聯等應用。本文提供的類別封裝大幅降低開發複雜度,開發者可專注於協議邏輯而非底層通訊細節。