|
摘要:本文介紹了在Microsoft Visual C++ 6.0環境下通過對Active X控件的編程來實現串口的通信的一般方法。
一、 引言
當我們在Windows操作系統下開發串行通信程序時通常不得不面對許多復雜的API函數,因為在Windows操作系統下不能直接對設備端口進行操作,也不能在系統級(Ring 3級別)使用任何DOS或BIOS中斷,如要對端口進行編程則只能以文件的形式來對端口進行操作,這就使開發人員不得不面對非常煩瑣的API函數編程。本文對此提出了另外一種封裝性很好的使用Microsoft Visual C++ 6.0自帶的"Microsoft Communications Control,version 6.0"Active X控件的編程方法,通過對該控件的正確使用,我們可以比較輕松地編寫出所需的串行通信程序。
下面,我們將結合一個實際的程序示例來對此方法進行說明。本程序的編程環境是Windows 98和Microsoft Visual C++ 6.0。在本程序示例中對為避免阻塞而對線程的使用以及在使用中遇到的一些問題也做了詳細的介紹。
二、 程序的設計實現
在開始進行代碼編程前,首先以在工程中插入組件或控件的方式將Active X控件"Microsoft Communications Control,version 6.0"加入到工程中來,此時將會在工程中添加一個關于此控件的新類。使用該控件的一些方法和屬性時不能象使用類一樣簡單的聲明一個實例對象,而要通ClassWizard為該控件和一個成員變量建立起綁定關系,在此我們將該控件同變量m_Comm相綁定后就可以通過該控件提供的方法來對串口的各種通訊參數進行設置了。為了編程方便起見,也可以在資源視圖中直接對該控件的屬性進行設置,如無特別要求,對下表所列屬性進行設置就基本可以滿足編程要求了。現將常用的屬性列表如下:
屬性 設定值 屬性說明 CommPort 1 串口號,一般從1到4 InBufferSize 30720 接收緩沖區大小,為保持程序的穩定,建議設得值足夠大 InputMode 0-Text 接收數據的類型,0表示文本類型,1表示二進制類型 InputLen 0 從接收緩沖區讀取的字節數,0表示全部讀取 OutBufferSize 512 發送緩沖區大小 Settings 4800,n,8,1 串口的參數設置,依次為波特率、奇偶校驗(n-無校驗,e-偶校驗,o-奇校驗)、數據位數、停止位數 RThreshold 1 設定當接收幾個字符時觸發OnComm事件,0表示不產生事件, 1表示每接收一個字符就產生一個事件 SThreshold 0 設定在觸發OnComm事件前,發送緩沖區內所允許的最少的字符數, 0表示發送數據時不產生事件,1表示當發送緩沖區空時產生OnComm事件
我們要求能在程序啟動的同時就打開串口以便即時對從串口到達的數據進行接收、處理。一般來說可以將下面的打開端口的代碼寫在OnCreate()、OnInitialUpdate()、InitInstance ()等程序入口函數中:
…… if(!m_Comm.GetPortOpen()) //檢測是否已經打開過端口 m_Comm.SetPortOpen(TRUE); //如沒有打開則將端口打開 …… 接下來的工作就是對數據的發送與接收了,這也是本文所要介紹的重點所在。發送數據的代碼原則上是可以寫到一個成員函數中被直接調用的,但這并不是一個良好的編程習慣:我們應當把比較耗時的操作,如文件拷貝、打印、端口傳輸等工作放到一個單獨的線程當中,以避免其在工作時會引起整個進程的阻塞,以提高整個系統對CPU的利用率。例如我們可以在視類中菜單或按鈕的響應函數中用AfxBeginThread(WriteProc,this)函數來開啟一個名為"WriteProc"的線程,由于在線程中還需要使用視類的函數和變量,為了不產生新的視類的實例對象,我們通過該函數的第二個參數將指向當前的視類的指針this作為參數傳遞給線程。在線程中可以用如下兩種方法之中的一種調用視類的成員函數:
((COLECommView*) pParam)->DoSendProc();
或是:
COLECommView* view=(COLECommView*) pParam; View->DoSendProc();
其中從pParam傳來的變量就是指向視類的指針。在線程中通過調用視類中的DoSendProc函數來完成對數據的發送,正是由于該函數是被全局的線程所調用的,我們就不可以使用取編輯框上的數據時通常所用的UpdateData()函數了,取而帶之的是API 函數GetDlgItemText(),取到輸入的數據后通過控件的SetOutput() 方法就把數據從串口發出去了,其中發送數據必須經ColeVariant類將其轉換為通用的VARIANT型變量。實現 主要代碼如下:
…… char a[255]; HWND hwnd=GetSafeHwnd(); ::GetDlgItemText(hwnd,IDC_EDIT1,a,255); int i=0; CString str; while(a[i]!='\0') { str.Format("%c",a[i]); m_SendData+=str; i++; } str.Format("%c",10); m_SendData+=str; m_Comm.SetOutput(COleVariant(m_SendData)); ……
至于數據的接收,我們可以通過讓MS Comm控件響應其OnComm事件來完成,通過ClassWizard加入其對事件的響應后,通過下面的事件映射,當有字符到達時便會通知 OnComm()函數去處理,從而實現數據的異步接收:
…… BEGIN_EVENTSINK_MAP(COLECommView, CFormView) //{{AFX_EVENTSINK_MAP(COLECommView) ON_EVENT(COLECommView, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE) //}}AFX_EVENTSINK_MAP END_EVENTSINK_MAP() …… void COLECommView::OnComm() { VARIANT Input; if(m_Comm.GetCommEvent()==2)//接收緩沖區內有字符 { Input=m_Comm.GetInput();//讀取緩沖區內的數據 CString msg=Input.bstrVal; CString str; str.Format("%c",10); if(msg.Right(1)==str) { m_RecvData+=msg; m_History.AddString(m_RecvData); m_RecvData=""; } else m_RecvData+=msg; } }
當數據被接收到接收緩沖區后,對于字符可以從VARIANT型結構變量的bstrVal成員變量中獲取,VARIANT數據結構相當復雜,并牽扯到COM(Component Object Model,組件對象模型)中的一些概念,具體詳情請參閱Microsoft Corpration發布的MSDN中的有關論述。
三、 測試與實驗
編譯運行程序之前有必要對機器的端口做一番檢查,以確保端口的完好,可以用常見的DOS程序Comdebug來檢查。在確認串口工作正常后,可用串口線將兩臺機器的串口相連,同時在兩臺機子上運行該程序,如果沒有條件也可只用一臺微機,將其串口的2腳和3腳短接,使其處于自發自收狀態。經過數據的傳輸實驗證明該程序是可靠、正確的。
小結:利用通訊控件可以很容易的編寫出串行通信程序。但相對來說通訊控件在VC中的使用要比在VB、Delphi中復雜的多,要想對串口通訊開發出更多更靈活的使用方法還需要不斷的實踐中摸索。本程序在 Windows 98下,由Microsoft Visual C++ 6.0編譯通過。
|