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

VC6 串口通訊三大實現方案深度比較:MSComm 控件 vs 單執行緒類 vs 多執行緒架構

     編輯:VC 教學

Windows 串口程式設計基礎

  • Win32 視串口為**檔案**,透過 CreateFile、ReadFile/WriteFile、DeviceIoControl 操作;
  • 7 大結構:DCB、COMMTIMEOUTS、COMSTAT、COMMCONFIG...;
  • 26 個 API,核心:SetCommState/GetCommState、SetCommTimeouts/GetCommTimeouts、SetCommMask/WaitCommEvent、ReadFile/WriteFile (異步需 OVERLAPPED)。

方案一:MSComm ActiveX 控件 (最簡單)

優點

  • 視覺化屬性頁設定 (Port、Baud、Parity、Data/Stop bits);
  • 事件驅動:OnComm 回呼處理 comEvReceive (2)、comEvSend、comEvCTS 等;
  • 內建緩衝區管理 (InBufferCount、InputLen、InputMode)。

缺點

  • **必須放在對話框/視窗**,無法在純工作執行緒/DLL/服務中使用;
  • 部署需註冊 MSCOMM32.OCX,版本相容性風險;
  • 效能上限較低,不適合高頻/多埠並發。

關鍵代碼

// 初始化
m_Comm.SetCommPort(2);
m_Comm.SetSettings(_T("4800,N,8,1"));
m_Comm.SetInBufferSize(1024);
m_Comm.SetInBufferCount(0);
m_Comm.SetInputMode(1); // Binary
m_Comm.SetInputLen(0);  // 讀全部
m_Comm.SetPortOpen(TRUE);

// OnComm 事件
void CMyDlg::OnComm() {
    switch (m_Comm.GetCommEvent()) {
        case 2: // comEvReceive
            // m_Comm.GetInput() 讀取...
            break;
    }
}

方案二:單執行緒自訂類 CSimpleComm (靈活、可執行緒)

核心流程

  1. CreateFile 開啟,**異步旗標** FILE_FLAG_OVERLAPPED;
  2. GetCommState → 修改 DCB → SetCommState;
  3. SetCommTimeouts 設定讀寫超時;
  4. 讀寫用 ReadFile/WriteFile + OVERLAPPED + WaitForSingleObject 等待完成;
  5. 或用 SetTimer 週期性輪詢 ReadFile (簡單場景);
  6. 進階:SetCommMask(EV_RXCHAR|EV_TXEMPTY|EV_RXFLAG) + WaitCommEvent 事件驅動。

關鍵代碼節錄

BOOL CSimpleComm::Open() {
    m_hComm = CreateFile(_T("COM2"), GENERIC_READ|GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
    if (m_hComm == INVALID_HANDLE_VALUE) return FALSE;

    DCB dcb = {0}; dcb.DCBlength = sizeof(DCB);
    GetCommState(m_hComm, &dcb);
    dcb.BaudRate = CBR_4800; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT;
    SetCommState(m_hComm, &dcb);

    COMMTIMEOUTS cto = {0};
    cto.ReadIntervalTimeout = MAXDWORD;
    cto.ReadTotalTimeoutConstant = 0;
    cto.WriteTotalTimeoutMultiplier = 2*9600/dcb.BaudRate;
    cto.WriteTotalTimeoutConstant = 25;
    SetCommTimeouts(m_hComm, &cto);
    return TRUE;
}

int CSimpleComm::ReadData(char* buf, int len) {
    DWORD dwRead = 0;
    BOOL ok = ReadFile(m_hComm, buf, len, &dwRead, &m_osRead);
    if (!ok && GetLastError() == ERROR_IO_PENDING) {
        WaitForSingleObject(m_osRead.hEvent, 1000);
        GetOverlappedResult(m_hComm, &m_osRead, &dwRead, FALSE);
    }
    return (int)dwRead;
}

方案三:多執行緒監控架構 (工業級、多埠並發)

架構設計

  • **每埠一個工作執行緒** (Worker Thread),獨立監控 WaitCommEvent;
  • 執行緒間同步:Critical Section 保護共享緩衝區、**Event** 通知 UI 執行緒有新資料;
  • UI 執行緒透過 ON_MESSAGE + PostMessage 接收通知,安全更新介面。

啟動監控執行緒

CWinThread* pThread = AfxBeginThread(
    CommWatchThread,        // 執行緒函數
    (LPVOID)pPortInfo,      // 傳遞埠資訊結構
    THREAD_PRIORITY_ABOVE_NORMAL,
    0, CREATE_SUSPENDED, NULL);
pThread->ResumeThread();

監控執行緒主迴圈

UINT CommWatchThread(LPVOID pParam) {
    PortInfo* pInfo = (PortInfo*)pParam;
    DWORD dwEvtMask;
    while (!pInfo->bStop) {
        if (WaitCommEvent(pInfo->hComm, &dwEvtMask, NULL)) {
            if (dwEvtMask & pInfo->dwEvtMask) { // 關注的事件
                WaitForSingleObject(pInfo->hEventPost, INFINITE);
                ResetEvent(pInfo->hEventPost);
                ::PostMessage(pInfo->hWndNotify, pInfo->nMsgID, 0, 0); // 通知 UI
            }
        }
    }
    return 0;
}

UI 端訊息映射

BEGIN_MESSAGE_MAP(CMyView, CView)
    ON_MESSAGE(ID_COM1_DATA, OnProcessCom1Data)
    ON_MESSAGE(ID_COM2_DATA, OnProcessCom2Data)
END_MESSAGE_MAP()

LRESULT CMyView::OnProcessCom1Data(WPARAM, LPARAM) {
    // 從 CSimpleComm 實例讀取資料並處理
    // 必須在下一次事件前處理完畢,否則資料會覆蓋/丟失
}

三方案對比總表

維度MSComm 控件單執行緒類多執行緒架構
部署複雜度需註冊 OCX純 C++ 程式碼純 C++ 程式碼
執行緒親和性僅 UI 執行緒任意執行緒專用工作執行緒
多埠支援困難 (每埠一控件)可多實例原生支援 (每埠一執行緒)
即時性事件驅動 (尚可)輪詢/事件可選事件驅動 + 高優先級 (最佳)
資料處理安全單執行緒無鎖問題需自行加鎖Critical Section + Event 完整
適用場景簡單單埠工具中等複雜度、單/少埠工業控制、多埠、高可靠

作者實戰選型

溫度監控系統 (Win95/98) 採用**方案二**:單執行緒類 + SetTimer 週期讀取,運行穩定。若擴展至多儀器並發,會遷移至方案三。

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