問題現象
- 環境:VS2008,CSerialPort 類,USB 轉 RS232 線連接兩台 Win7 電腦。
- 現象:只能發送一條指令,隨後阻塞等待接收;收到字符後才能發送下一條。直連(無轉接線)則可正常連續收發。
- 已排除:USB 轉接線硬件故障、驅動問題。
根本原因:線程同步機制導致的「發送-接收」串行化
CSerialPort 內部通常採用 發送線程 + 接收線程 架構,並使用 事件/信號量 同步:
- 發送數據前,發送線程等待「接收完成」信號。
- 接收線程收到數據後,觸發「接收完成」信號,喚醒發送線程。
- 此機制強制規定「發一條、收一條」,導致無法連續發送多條指令。
解決思路:修改同步邏輯,實現全雙工異步收發
方案一:註釋掉接收線程同步等待(快速驗證)
- 找到接收線程創建代碼,暫時註釋掉(僅保留發送功能)。
- 找到發送函數中等待「接收信號」的代碼(如
WaitForSingleObject),註釋掉。
- 測試連續發送是否正常。
方案二:重構為生產者-消費者模式(推薦生產環境)
- 發送隊列:主線程將指令入隊,發送線程循環取隊發送,無需等待接收。
- 接收回調:接收線程收到數據後,通過回調/事件通知上層業務,不阻塞發送。
- 發送函數增加參數
bool needResponse:需應答的指令走「發送-等待應答」流程,無需應答的直接入隊返回。
關鍵代碼調整示例
// 發送函數修改
BOOL WriteData(const BYTE* data, int len, bool waitForResponse = false) {
if (waitForResponse) {
// 原有同步邏輯:發送 -> 等待接收事件 -> 返回
} else {
// 新異步邏輯:加入發送隊列 -> 立即返回 TRUE
sendQueue.push(DataPacket(data, len));
SetEvent(hSendEvent); // 通知發送線程
return TRUE;
}
}
調試建議
- 使用串口監控工具(如 PortMon、Serial Port Monitor)抓包分析時序。
- 在發送/接收線程關鍵點加日誌,輸出線程 ID、時間戳、數據內容。
- 確認 USB 轉串口芯片(FT232/CH340/CP2102)驅動版本匹配 Win7 x64。
總結
CSerialPort 預設同步模式不適合「主動輪詢/連續下發」場景。通過剝離發送與接收的同步依賴,改為異步隊列模式,即可解決 Win7 下 USB轉串口無法連續發送的問題。