DOS 時代透過中斷直接控制 UART,Windows 硬體抽象層 (HAL) 禁止應用程式直接操作中斷/埠口。所有序列埠操作必須透過 Win32 API,核心思想:序列埠即檔案,統一使用 CreateFile/ReadFile/WriteFile 檔案 I/O 模型,搭配 DCB (Device Control Block) 設定參數,實現跨硬體平台的可移植通訊。
| 階段 | API | 用途 |
|---|---|---|
| 開啟/關閉 | CreateFile | 開啟 COM 埠,取得通用句柄 |
CloseHandle | 關閉埠口,釋放資源 | |
| 參數設定 | GetCommState/SetCommState | 讀取/寫入 DCB 結構 (鮑率、資料位、停止位、奇偶校驗) |
BuildCommDCB | 字串解析填充 DCB (如 "9600,n,8,1") | |
GetCommTimeouts/SetCommTimeouts | 讀寫逾時參數 (關鍵:避免 ReadFile 永久阻塞) | |
| 事件驅動 | SetCommMask | 設定監視事件 (RXCHAR, TXEMPTY, CTS, DSR, RLSD, BREAK, ERR, RING) |
WaitCommEvent | 阻塞等待事件發生 | |
WaitForMultipleObjects | 同時等待通訊事件與其他物件 (如關閉事件) | |
| 資料傳輸 | ReadFile/WriteFile | 同步/非同步讀寫 (配合 OVERLAPPED 結構) |
GetOverlappedResult | 取得非同步操作結果 | |
PurgeComm | 清空輸入/輸出緩衝區、中止掛起操作 | |
| 狀態/錯誤 | ClearCommError | 更新 COMSTAT 狀態、清除硬體錯誤旗標 |
// 1. 開啟 COM1,支援重疊 (非同步) I/O
HANDLE hComm = CreateFile(
"COM1", // 埠口名稱
GENERIC_READ | GENERIC_WRITE,
0, // 不共享
NULL, // 安全屬性
OPEN_EXISTING, // 必須存在
FILE_FLAG_OVERLAPPED, // 關鍵:啟用非同步
NULL // 模板檔案
);
// 2. 設定 DCB 參數
DCB dcb = {0};
dcb.DCBlength = sizeof(DCB);
GetCommState(hComm, &dcb); // 先取得預設值
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
SetCommState(hComm, &dcb);
// 3. 設定逾時 (關鍵!避免讀取卡死)
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = 50; // 字元間最大間隔
timeouts.ReadTotalTimeoutConstant = 500; // 總計常數
timeouts.ReadTotalTimeoutMultiplier = 10; // 乘數
timeouts.WriteTotalTimeoutConstant = 500;
timeouts.WriteTotalTimeoutMultiplier = 10;
SetCommTimeouts(hComm, &timeouts);
使用 OVERLAPPED 結構 + 事件物件:
// 讀取範例
OVERLAPPED osReader = {0};
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD dwRead;
BOOL fWaitingOnRead = FALSE;
if (!ReadFile(hComm, buffer, BUFSIZE, &dwRead, &osReader)) {
if (GetLastError() == ERROR_IO_PENDING) {
fWaitingOnRead = TRUE;
// 可在此處做其他事,或 WaitForSingleObject(osReader.hEvent, INFINITE)
}
}
// 後續 GetOverlappedResult 取得實際讀取位元組數
// 設定監視字元接收事件
SetCommMask(hComm, EV_RXCHAR);
// 工作執行緒迴圈
DWORD dwEvtMask;
while (running) {
if (WaitCommEvent(hComm, &dwEvtMask, NULL)) {
if (dwEvtMask & EV_RXCHAR) {
// 有資料到達,呼叫 ReadFile 讀取
}
}
}
SetCommTimeouts 設定合理值PurgeComm(hComm, PURGE_TXCLEAR | PURGE_RXCLEAR)ClearCommError 可清除 CE_FRAME、CE_OVERRUN、CE_RXPARITY 等硬體錯誤fOutxCtsFlow、fInX 等旗標\\\\.\\COM10 格式CreateFile/CloseHandle、CreateEvent/CloseHandleWindows.Devices.SerialCommunication (WinRT API,UWP/WinUI 3 優先)libserialport、Boost.Asio (serial_port)、QtSerialPort掌握 Win32 序列埠 API 是理解 Windows I/O 子系統、裝置驅動互動的絕佳切入點。