MSCOMM
VB5.0/6.的MSComm通信控制項提供了一系列標準通信命令的接口,它允許建立
串口連線,可以連線到其他通信設備(如Modem).還可以傳送命令、進行數據交換以及監視和回響在通信過程中可能發生的各種錯誤和事件,從而可以用它創建全雙工 、事件驅動的、高效實用的通信程式。但在實際通信軟體設計過程中,MSComm控制項並非像想像中那樣完美和容易控制.特別是在中文Wln 95/98下通信時更會出現問題。下面就從基礎開始介紹,然後逐步討論MSComm控制項在編程中出現的問題以及編程技巧。
控制項設定
在開始使用MSComm控制項之前。需要先了解其屬性、事件或錯誤
屬性描述
CommPort 設定或返回通信連線埠號
Output 將字元串寫入傳送緩衝區
CommEvent屬性為通信事件或錯誤返回下列值之一。在該控制項的對象庫中也可以找到這些
常量。
常量值描述
ComEventBreak 1001 收到了斷開信號
ComEventCTSTO 1002 Clear To Send Timeout。在傳送字元時,在系統指定的事件內,CTS(Clear To Send)線是低電平
ComEventDSRTO 1003 Data Set Ready Timeout。在傳送字元時,在系統指定的事件內,DSR(Data Set Ready)線是低電平
ComEventFrame 1004
數據幀錯誤。硬體檢測到一個數據幀錯誤
ComEventOverrun 1006 連線埠溢出。硬體中的字元尚未讀,下一個字元又到達,並且丟失
ComEventCDTO 1007 Carrier Detect Time。在傳送字元時,在系統指定的事件內,CD(Carrier Detect)線是低電平。CD 也稱為RLSD(Receive Line Singal Detect,接收線信號檢測)ComEventRxOver 1008 接收
緩衝區溢出。在接收
緩衝區中沒有空間ComEventRxParity 1009
奇偶校驗錯。硬體檢測到奇偶校驗錯誤7ComEventTxFull 1010 傳送緩衝區滿。在對傳送字元排隊時,傳送緩衝區滿ComEventDCB 1011 檢取連線埠DCB(Device Control Blick)時發生了沒有預料到的錯誤
通信事件包含了下面的設定:
常量 值 描述ComEvSend 1 傳送緩衝區中的字元數比Sthreshold值低ComEvReceive 2 接收到了Rthreshold個字元。持續產生該事件,直到使用了Input屬性刪除了接收
緩衝區中的數據ComEvCTS 3 CTS(Clear To Send)線改變ComEvDSR 4 DSR(Data Set Ready)線改變。當DSR從1到0改變時,該事件發生ComEvCD 5 CD(Carrier Detect)線改變ComEvRing6檢測到響鈴信號。一些
UART(Universal AsynchronousReciver- -Transmitters,
通用異步收發器)不支持該事件ComEvEOF 7 收到了EOF字元(ASCII字元26)
Error訊息(MSComm控制項)下表列出了MSComm控制項可捕獲的錯誤訊息:
常量 值 描述ComInvalidPropertyValue 380 無效的屬性值ComSetNotSupported 383 屬性唯讀ComGetNotSupported 394 屬性唯讀ComPortOpen 8000 連線埠打開時該存在
無效 8001 逾時設定必須比0值大ComPortInvalid 8002 無效的連線埠號 8003 屬性只在運行時有效 8004 屬性在運行時是唯讀的ComPortAleadyOpen 8005 連線埠已經打開 8006 設備
標識符無效或不支持 8007 不支持設備的
波特率 8008 指定的位元組大小無效 8009
預設參數錯誤 8010 硬體不可用(被其他設備鎖住) 8011 函式不能分配佇列ComNoOpen 8012 設備沒有打開 8013 設備已經打開 8014 不能使用通信通知ComSetCommStateFailed 8015 不能設定通信狀態 8016 不能設定通信事件禁止ComPortNotOpen 8018 該存在只在連線埠打開是有效 8019 設備忙ComReadError 8020 通信設備讀錯誤ComDCBError 8021 檢取連線埠設備控制塊時出現內部錯誤
控制項方法
MSComm控制項提供了兩種處理通信的方法,如下:
串口活動法
1.事件驅動通信,是一種功能很強的處理串口活動的方法。在大多數情況下,用戶需要獲知事件發生的時間,例如,在CD(Carrier Detect)線或RTS(Request To Send)線上有字元到達或發生了改變等。在這種情況下,使用MSComm控制項的OnComm事件捕獲和處理這些通信事件。OnComm也可以捕獲和處理通信中的錯誤。要獲取所有事件和通信錯誤的完整清單,請參閱CommEvent屬性。
程式檢測法
2.用戶也可以在每個重要的程式功能之後檢查CommEvent屬性的值來檢測事件和通信錯誤。這對小的自含程式可能比較常用。例如,如果編寫一個簡單的電話撥號程式,那么在接收了每個字元後都產生一個事件並沒有意義,因為你只打算從數據機中接收OK回響信息。
使用的每個MSComm控制項都與一個串口對應。如果在應用程式中需要訪問多個串口,必須使用多個MSComm控制項。可以在Windows 控制臺中修改串口地址的中斷地址。
方法
以VC++為例:
首先,在對話框中創建通信控制項,若Control
工具列中缺少該控制項,可通過選單Project --> Add to Project --> Components and Control插入即可,再將該控制項從
工具箱中拉到對話框中。此時,你只需要關心控制項提供的對 Windows 通訊
驅動程式的 API 函式的接口。 換句話說,只需要設定和監視MSComm控制項的屬性和事件。
打開所需串口後,需要考慮
串口通信的時機。在接收或傳送數據過程中,可能需要監視並回響一些事件和錯誤,所以
事件驅動是處理
串列連線埠互動作用的一種非常有效的方法。使用 OnComm 事件和 CommEvent 屬性捕捉並檢查通訊事件和錯誤的值。發生通訊事件或錯誤時,將觸發 OnComm 事件,CommEvent 屬性的值將被改變,應用程式檢查 CommEvent 屬性值並作出相應的反應
// 若是在SDI中使用該控制項則要調用下兩句,在對話框程式中該語句有MFC自己創建
// 所以不用人為添加
DWORD style=WS_VISIBLE;
m_MSComm.Create(NULL,style,CRect(0,0,0,0),this,IDC_MSCOMM1);
// 串口控制項的初始化
DWORD style=WS_VISIBLE;
m_MSComm.Create(NULL,style,CRect(0,0,0,0),this,IDC_MSCOMM1);
if(m_MSComm.GetPortOpen()) //如果串口是打開的,則行關閉串口
{
m_MSComm.SetPortOpen(FALSE);
}
m_MSComm.SetCommPort(1); //選擇COM1
if(!m_MSComm.GetPortOpen())//如果串口沒有打開則打開
m_MSComm.SetPortOpen(TRUE);//打開串口
else
m_MSComm.SetOutBufferCount(0);
m_MSComm.SetInBufferSize(1024); //接收
緩衝區m_MSComm.SetOutBufferSize(1024);//傳送緩衝區
m_MSComm.SetInputLen(0);//設定當前接收區數據長度為0,表示全部讀取
m_MSComm.SetInputMode(1);//以二進制方式讀寫數據
m_MSComm.SetRThreshold(1);//接收緩衝區有1個及1個以上字元時,將引發接收數據的OnComm事件
m_MSComm.SetSettings("9600,n,8,1");//
波特率9600無檢驗位,8個
數據位,1個停止位
// 控制項事件的回響聲明
// *.h
//{{AFX_MSG(CGolfView)
afx_msg BOOL OnComm();
DECLARE_EVENTSINK_MAP()
//}}AFX_MSG
// *.cpp
BEGIN_EVENTSINK_MAP(CGolfView, CView)
//{{AFX_EVENTSINK_MAP(CAboutDlg)
ON_EVENT(CGolfView, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
// 控制項事件的回響
BOOL CGolfView::OnComm()
{
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[2048]; //設定BYTE
數組An 8-bit integerthat is not signed.
CString strtemp;
CString recd;
switch(m_MSComm.GetCommEvent())
{
case 1: // comEvSend傳送數據
break;
case 2: // comEvReceive讀取數據
// MessageBox(_T("讀取數據事件"), _T("TRACE"), MB_OK);
variant_inp=m_MSComm.GetInput(); //讀
緩衝區safearray_inp=variant_inp; //VARIANT型變數轉換為ColeSafeArray型變數
len=safearray_inp.GetOneDimSize(); //得到有效數據長度
// 接受數據
for(k=0; k<len;k++) {
safearray_inp.GetElement(&k,rxdata+k); //轉換為BYTE型
數組BYTE bt=*(char*)(rxdata+k); //字元型
strtemp.Format("%c",bt); //將字元送入臨時變數strtemp存放
recd+=strtemp;
}
// UpdateData(TRUE);
break;
default: // 傳輸事件出錯
m_MSComm.SetOutBufferCount(0);
break;
}
UpdateData(FALSE); //更新圖象內容
return TRUE;
}