首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C++ Builder 串口通訊實戰:從 API 到 MSComm32 控件全方位指南

     編輯:VC 教學

兩大主流路線

  1. Win32 API 原生:CreateFile/SetCommState/ReadFile/WriteFile/WaitCommEvent + Overlapped I/O,完全可控、無依賴、學習曲線陡峭。
  2. MSComm32.ocx (ActiveX):VB 經典控件,BCB 導入後以事件驅動簡化開發,但屬於 COM 組件,部署需註冊、64 位相容性差,現已不推薦新專案使用。

方案一:Win32 API 完整封裝類

class TSerialPort {
    HANDLE hComm;
    OVERLAPPED ovRead, ovWrite;
    HANDLE hEvent;
public:
    bool Open(int portNo, DWORD baud=9600, BYTE parity=NOPARITY, BYTE data=8, BYTE stop=ONESTOPBIT) {
        hComm = CreateFile(("\\\\.\\COM" + std::to_string(portNo)).c_str(),
                           GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
                           FILE_FLAG_OVERLAPPED, NULL);
        if (hComm == INVALID_HANDLE_VALUE) return false;
        DCB dcb{}; dcb.DCBlength = sizeof(dcb);
        GetCommState(hComm, &dcb);
        dcb.BaudRate = baud; dcb.Parity = parity; dcb.ByteSize = data; dcb.StopBits = stop;
        dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE;
        SetCommState(hComm, &dcb);
        // 設置緩衝區、超時、事件遮罩...
        hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        ovRead.hEvent = ovWrite.hEvent = hEvent;
        SetCommMask(hComm, EV_RXCHAR | EV_ERR);
        return true;
    }
    int Read(void* buf, int len, DWORD timeout=1000) {
        DWORD read=0; ResetEvent(hEvent);
        if (!ReadFile(hComm, buf, len, &read, &ovRead)) {
            if (GetLastError() == ERROR_IO_PENDING)
                WaitForSingleObject(hEvent, timeout), GetOverlappedResult(hComm, &ovRead, &read, FALSE);
        }
        return read;
    }
    int Write(const void* buf, int len) {
        DWORD written=0; ResetEvent(hEvent);
        WriteFile(hComm, buf, len, &written, &ovWrite);
        if (GetLastError() == ERROR_IO_PENDING)
            WaitForSingleObject(hEvent, 5000), GetOverlappedResult(hComm, &ovWrite, &written, FALSE);
        return written;
    }
    void Close() { if (hComm!=INVALID_HANDLE_VALUE) CloseHandle(hComm), hComm=INVALID_HANDLE_VALUE; }
};

方案二:MSComm32 控件用法(維護舊專案參考)

導入步驟

  1. Component → Import ActiveX Control → 選 Microsoft Comm Control 6.0 → Install。
  2. Palette → ActiveX 頁面出現 TMSComm,拖入表單。

關鍵屬性/事件

  • CommPort、Settings (如 "9600,n,8,1")、PortOpen、InBufferCount、OutBufferCount、RThreshold (接收觸發閾值)、SThreshold (發送觸發閾值)。
  • OnComm 事件:CommEvent 屬性指示事件類型(comEvReceive、comEvSend、comEvEOF...)。

收發代碼模式

// 發送 (OleVariant 數組)
OleVariant tx = VarArrayCreate(OPENARRAY(int, (0, n-1)), varByte);
for (int i=0; iOutput = tx;

// 接收 (在 OnComm 或 Timer 中)
if (MSComm1->InBufferCount > 0) {
    OleVariant rx = MSComm1->Input; // 同樣為 OleVariant 數組
    int cnt = rx.GetElement(0); // 實際結構視版本而定,需實測
    // 複製到自有緩衝區...
}

避坑指南

  • OnComm 事件不可靠,高負載易丟失,**強烈建議用 Timer (50~100ms) 主動輪詢 InBufferCount 讀取**。
  • BCB4/5/6 中 Input/Output 在 Object Inspector 不顯示,但運行時存在,類型為 OleVariant。
  • 64 位 BCB (10.4+) 無法載入 32 位 OCX,**新專案請直接用 Win32 API 或第三方純 C++ 庫(如 serialib、Boost.Asio serial_port)**。

現代替代方案推薦

庫語言特點
Boost.Asio serial_portC++11+跨平台、異步、標準庫風格、Header-only 可選
serialibC++輕量、單頭文件、Windows/Linux 同介面
QSerialPort (Qt)C++/Qt信號槽、事件循環整合、文檔豐富
Windows Implementation Library (WIL)C++RAII 封裝 HANDLE、OVERLAPPED、現代 C++ 風格

總結

新專案**首選 Win32 API 封裝或 Boost.Asio**,掌握 Overlapped I/O 即掌握 Windows 高效串口編程精髓;舊專案維護 MSComm32 時注意 OnComm 不可靠、64 位不兼容,規劃遷移路徑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved