Windows 串口操作基於核心 API,掌握以下 6 個函數即可覆蓋 90% 應用場景:
| 函數 | 用途 |
|---|---|
CreateFile | 打開串口,獲取句柄 |
GetCommState | 獲取當前串口參數(波特率、數據位、校驗位等) |
SetCommState | 設置串口參數 |
ReadFile | 讀取串口數據 |
WriteFile | 寫入串口數據 |
CloseHandle | 關閉串口句柄 |
HANDLE hCom; // 全局串口句柄
bool OpenPort(const char* portName = "COM1") {
hCom = CreateFile(
portName, // 串口名
GENERIC_READ | GENERIC_WRITE, // 讀寫權限
0, // 獨佔模式
NULL, // 安全屬性
OPEN_EXISTING, // 打開現有設備
0, // 同步方式(非重疊 I/O)
NULL
);
if (hCom == INVALID_HANDLE_VALUE) {
AfxMessageBox("打開串口失敗!");
return false;
}
return true;
}
bool SetupPort(DWORD baudRate = CBR_9600, BYTE byteSize = 8, BYTE parity = NOPARITY, BYTE stopBits = ONESTOPBIT) {
DCB dcb;
if (!GetCommState(hCom, &dcb)) return false;
dcb.BaudRate = baudRate;
dcb.ByteSize = byteSize;
dcb.Parity = parity;
dcb.StopBits = stopBits;
dcb.fBinary = TRUE;
dcb.fParity = (parity != NOPARITY);
return SetCommState(hCom, &dcb);
}
bool WritePort(const void* buffer, DWORD length, DWORD* bytesWritten = nullptr) {
COMSTAT comStat;
DWORD errors;
ClearCommError(hCom, &errors, &comStat); // 清除錯誤狀態
DWORD written = 0;
BOOL result = WriteFile(hCom, buffer, length, &written, NULL);
if (!result) {
AfxMessageBox("寫入串口失敗!");
return false;
}
if (bytesWritten) *bytesWritten = written;
return true;
}
DWORD ReadPort(void* buffer, DWORD maxLength, OVERLAPPED* overlapped = nullptr) {
COMSTAT comStat;
DWORD errors;
ClearCommError(hCom, &errors, &comStat);
if (comStat.cbInQue == 0) return 0; // 無數據可讀
DWORD toRead = min(maxLength, comStat.cbInQue);
DWORD read = 0;
BOOL result = ReadFile(hCom, buffer, toRead, &read, overlapped);
if (!result) {
DWORD lastError = GetLastError();
if (lastError == ERROR_IO_PENDING && overlapped) {
// 等待重疊操作完成
GetOverlappedResult(hCom, overlapped, &read, TRUE);
return read;
}
return 0;
}
return read;
}
void ClosePort() {
if (hCom != INVALID_HANDLE_VALUE) {
CloseHandle(hCom);
hCom = INVALID_HANDLE_VALUE;
}
}
GetLastError() 定位問題ClearCommError 獲取 cbInQue 避免無效等待SetCommTimeouts 配置讀寫超時,避免無限阻塞