明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

使用ActiveX控件開發(fā)串口通信軟件

[摘要]摘要:本文介紹了在Microsoft Visual C++ 6.0環(huán)境下通過(guò)對(duì)Active X控件的編程來(lái)實(shí)現(xiàn)串口的通信的一般方法。  一、 引言  當(dāng)我們?cè)赪indows操作系統(tǒng)下開發(fā)串行通信程序時(shí)通常不得不面對(duì)許多復(fù)雜的API函數(shù),因?yàn)樵赪indows操作系統(tǒng)下不能直接對(duì)設(shè)備端口進(jìn)行操作,也不...
摘要:本文介紹了在Microsoft Visual C++ 6.0環(huán)境下通過(guò)對(duì)Active X控件的編程來(lái)實(shí)現(xiàn)串口的通信的一般方法。

  一、 引言

  當(dāng)我們?cè)赪indows操作系統(tǒng)下開發(fā)串行通信程序時(shí)通常不得不面對(duì)許多復(fù)雜的API函數(shù),因?yàn)樵赪indows操作系統(tǒng)下不能直接對(duì)設(shè)備端口進(jìn)行操作,也不能在系統(tǒng)級(jí)(Ring 3級(jí)別)使用任何DOS或BIOS中斷,如要對(duì)端口進(jìn)行編程則只能以文件的形式來(lái)對(duì)端口進(jìn)行操作,這就使開發(fā)人員不得不面對(duì)非常煩瑣的API函數(shù)編程。本文對(duì)此提出了另外一種封裝性很好的使用Microsoft Visual C++ 6.0自帶的"Microsoft Communications Control,version 6.0"Active X控件的編程方法,通過(guò)對(duì)該控件的正確使用,我們可以比較輕松地編寫出所需的串行通信程序。

  下面,我們將結(jié)合一個(gè)實(shí)際的程序示例來(lái)對(duì)此方法進(jìn)行說(shuō)明。本程序的編程環(huán)境是Windows 98和Microsoft Visual C++ 6.0。在本程序示例中對(duì)為避免阻塞而對(duì)線程的使用以及在使用中遇到的一些問(wèn)題也做了詳細(xì)的介紹。

  二、 程序的設(shè)計(jì)實(shí)現(xiàn)

  在開始進(jìn)行代碼編程前,首先以在工程中插入組件或控件的方式將Active X控件"Microsoft Communications Control,version 6.0"加入到工程中來(lái),此時(shí)將會(huì)在工程中添加一個(gè)關(guān)于此控件的新類。使用該控件的一些方法和屬性時(shí)不能象使用類一樣簡(jiǎn)單的聲明一個(gè)實(shí)例對(duì)象,而要通ClassWizard為該控件和一個(gè)成員變量建立起綁定關(guān)系,在此我們將該控件同變量m_Comm相綁定后就可以通過(guò)該控件提供的方法來(lái)對(duì)串口的各種通訊參數(shù)進(jìn)行設(shè)置了。為了編程方便起見,也可以在資源視圖中直接對(duì)該控件的屬性進(jìn)行設(shè)置,如無(wú)特別要求,對(duì)下表所列屬性進(jìn)行設(shè)置就基本可以滿足編程要求了,F(xiàn)將常用的屬性列表如下:


屬性 設(shè)定值 屬性說(shuō)明
CommPort 1 串口號(hào),一般從1到4
InBufferSize 30720 接收緩沖區(qū)大小,為保持程序的穩(wěn)定,建議設(shè)得值足夠大
InputMode 0-Text 接收數(shù)據(jù)的類型,0表示文本類型,1表示二進(jìn)制類型
InputLen 0 從接收緩沖區(qū)讀取的字節(jié)數(shù),0表示全部讀取
OutBufferSize 512 發(fā)送緩沖區(qū)大小
Settings 4800,n,8,1 串口的參數(shù)設(shè)置,依次為波特率、奇偶校驗(yàn)(n-無(wú)校驗(yàn),e-偶校驗(yàn),o-奇校驗(yàn))、數(shù)據(jù)位數(shù)、停止位數(shù)
RThreshold 1 設(shè)定當(dāng)接收幾個(gè)字符時(shí)觸發(fā)OnComm事件,0表示不產(chǎn)生事件,
1表示每接收一個(gè)字符就產(chǎn)生一個(gè)事件
SThreshold 0 設(shè)定在觸發(fā)OnComm事件前,發(fā)送緩沖區(qū)內(nèi)所允許的最少的字符數(shù),
0表示發(fā)送數(shù)據(jù)時(shí)不產(chǎn)生事件,1表示當(dāng)發(fā)送緩沖區(qū)空時(shí)產(chǎn)生OnComm事件


  我們要求能在程序啟動(dòng)的同時(shí)就打開串口以便即時(shí)對(duì)從串口到達(dá)的數(shù)據(jù)進(jìn)行接收、處理。一般來(lái)說(shuō)可以將下面的打開端口的代碼寫在OnCreate()、OnInitialUpdate()、InitInstance ()等程序入口函數(shù)中:

……
if(!m_Comm.GetPortOpen()) //檢測(cè)是否已經(jīng)打開過(guò)端口
m_Comm.SetPortOpen(TRUE); //如沒(méi)有打開則將端口打開
……
接下來(lái)的工作就是對(duì)數(shù)據(jù)的發(fā)送與接收了,這也是本文所要介紹的重點(diǎn)所在。發(fā)送數(shù)據(jù)的代碼原則上是可以寫到一個(gè)成員函數(shù)中被直接調(diào)用的,但這并不是一個(gè)良好的編程習(xí)慣:我們應(yīng)當(dāng)把比較耗時(shí)的操作,如文件拷貝、打印、端口傳輸?shù)裙ぷ鞣诺揭粋(gè)單獨(dú)的線程當(dāng)中,以避免其在工作時(shí)會(huì)引起整個(gè)進(jìn)程的阻塞,以提高整個(gè)系統(tǒng)對(duì)CPU的利用率。例如我們可以在視類中菜單或按鈕的響應(yīng)函數(shù)中用AfxBeginThread(WriteProc,this)函數(shù)來(lái)開啟一個(gè)名為"WriteProc"的線程,由于在線程中還需要使用視類的函數(shù)和變量,為了不產(chǎn)生新的視類的實(shí)例對(duì)象,我們通過(guò)該函數(shù)的第二個(gè)參數(shù)將指向當(dāng)前的視類的指針this作為參數(shù)傳遞給線程。在線程中可以用如下兩種方法之中的一種調(diào)用視類的成員函數(shù):

((COLECommView*) pParam)->DoSendProc();

  或是:

COLECommView* view=(COLECommView*) pParam;
View->DoSendProc();


  其中從pParam傳來(lái)的變量就是指向視類的指針。在線程中通過(guò)調(diào)用視類中的DoSendProc函數(shù)來(lái)完成對(duì)數(shù)據(jù)的發(fā)送,正是由于該函數(shù)是被全局的線程所調(diào)用的,我們就不可以使用取編輯框上的數(shù)據(jù)時(shí)通常所用的UpdateData()函數(shù)了,取而帶之的是API 函數(shù)GetDlgItemText(),取到輸入的數(shù)據(jù)后通過(guò)控件的SetOutput() 方法就把數(shù)據(jù)從串口發(fā)出去了,其中發(fā)送數(shù)據(jù)必須經(jīng)ColeVariant類將其轉(zhuǎn)換為通用的VARIANT型變量。實(shí)現(xiàn)
主要代碼如下:

……
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));
……

  至于數(shù)據(jù)的接收,我們可以通過(guò)讓MS Comm控件響應(yīng)其OnComm事件來(lái)完成,通過(guò)ClassWizard加入其對(duì)事件的響應(yīng)后,通過(guò)下面的事件映射,當(dāng)有字符到達(dá)時(shí)便會(huì)通知 OnComm()函數(shù)去處理,從而實(shí)現(xiàn)數(shù)據(jù)的異步接收:

……
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)//接收緩沖區(qū)內(nèi)有字符
{
Input=m_Comm.GetInput();//讀取緩沖區(qū)內(nèi)的數(shù)據(jù)
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;
}
}


  當(dāng)數(shù)據(jù)被接收到接收緩沖區(qū)后,對(duì)于字符可以從VARIANT型結(jié)構(gòu)變量的bstrVal成員變量中獲取,VARIANT數(shù)據(jù)結(jié)構(gòu)相當(dāng)復(fù)雜,并牽扯到COM(Component Object Model,組件對(duì)象模型)中的一些概念,具體詳情請(qǐng)參閱Microsoft Corpration發(fā)布的MSDN中的有關(guān)論述。

  三、 測(cè)試與實(shí)驗(yàn)

  編譯運(yùn)行程序之前有必要對(duì)機(jī)器的端口做一番檢查,以確保端口的完好,可以用常見的DOS程序Comdebug來(lái)檢查。在確認(rèn)串口工作正常后,可用串口線將兩臺(tái)機(jī)器的串口相連,同時(shí)在兩臺(tái)機(jī)子上運(yùn)行該程序,如果沒(méi)有條件也可只用一臺(tái)微機(jī),將其串口的2腳和3腳短接,使其處于自發(fā)自收狀態(tài)。經(jīng)過(guò)數(shù)據(jù)的傳輸實(shí)驗(yàn)證明該程序是可靠、正確的。

  小結(jié):利用通訊控件可以很容易的編寫出串行通信程序。但相對(duì)來(lái)說(shuō)通訊控件在VC中的使用要比在VB、Delphi中復(fù)雜的多,要想對(duì)串口通訊開發(fā)出更多更靈活的使用方法還需要不斷的實(shí)踐中摸索。本程序在
Windows 98下,由Microsoft Visual C++ 6.0編譯通過(guò)。