簡介
MSComm 作為一個串列通訊控制項。在為程式設計師串口通訊編程節省了很多時間基於對話框的套用中加入一個MSComm控制項非常簡單。只需進行以下操作即可:
打開“Project->Add To Project->Components and Controls->Registered Activex Controls”(工程/部件/控制項),然後選擇控制項:Microsoft Communication Control,version 6.0(Microsoft Comm Control 6.0)插入到當前的工程中。這樣就將類 CMSComm 的相關檔案 mscomm.cpp 和 mscomm.h 一併加入到了工程中。編程時只需將控制項對話中的 MSComm 控制項拖至你的套用對話框中就OK了。
兩種方法
MSComm控制項提供了兩種處理通信的方法:
事件驅動
事件驅動通信,是一種功能很強的處理串口活動的方法。例如,當在CD(Carrier Detect)線或RTS(Request To Send)線上有字元到達或發生了改變,在這種情況下,可以使用MSComm控制項的OnComm事件捕獲和處理這些通信事件。OnComm也可以捕獲和處理通信中的錯誤。
檢測屬性
可以在每個重要的程式功能之後檢查CommEvent屬性的值來檢測事件和通信錯誤。
使用的每個MSComm控制項都與一個串口對應。如果在應用程式中需要訪問多個串口,必須使用多個MSComm控制項,可以在Windows 控制臺中修改串口地址的中斷地址。
1、MSComm 控制項有很多重要的屬性,
CommPort 屬性 : 設定並返回通訊連線埠號。
語法 : object.CommPort[value ] (value 一整型值,說明連線埠號。)
說明 : 在設計時,value 可以設定成從 1 到 16 的任何數(預設值為 1)。但是如果用 PortOpen 屬性打開一個並不存在的連線埠時,MSComm 控制項會產生錯誤 68(設備無效)。
2、RThreshold 屬性:在MSComm控制項設定CommEvent屬性為comEReceive並產生 OnComm 之前,設定並返回的要接收的字元數。
語法:
object.Rthreshold [ = value ](value 整型表達式,說明在產生 OnComm 事件之前要接收的字元數。 )
說明 :當接收字元後,若 Rthreshold 屬性設定為 0(預設值)則不產生 OnComm 事件。例如,設定 Rthreshold 為 1,接收緩衝區收到每一個字元都會使 MSComm 控制項產生 OnComm 事件。
3、CTSHolding 屬性:確定是否可通過查詢 Clear To Send (CTS) 線的狀態傳送數據。Clear To Send 是數據機傳送到相聯計算機的信號,指示傳輸可以進行。該屬性在設計時無效,在運行時為唯讀。
語法 : object.CTSHolding(Boolean)
Mscomm 控制項的 CTSHolding 屬性設定值:
1.True Clear To Send 線為高電平。
2.False Clear To Send 線為低電平。
說明:如果 Clear To Send 線為低電平 (CTSHolding = False) 並且逾時時,MSComm控制項設定CommEvent屬性為comEventCTSTO(Clear To Send Timeout)並產生OnComm事件。。
Clear To Send 線用於 RTS/CTS (Request To Send/Clear To Send) 硬體握手。如果需要確定 Clear To Send 線的狀態,CTSHolding 屬性給出一種手工查詢的方法。
4、SThreshold屬性:在MSComm控制項設定CommEvent屬性為comEvSend 並產生 OnComm 事件之前,設定並返回傳輸緩衝區中允許的最小字元數。
語法 : object.SThreshold [ = value ] value整形表達式,代表在 OnComm 事件產生之前在傳輸緩衝區中的最小字元數。
說明:若設定 Sthreshold 屬性為 0(預設值),數據傳輸事件不會產生 OnComm 事件。若設定 Sthreshold 屬性為 1,當傳輸緩衝區完全空時,MSComm 控制項產生 OnComm 事件。如果在傳輸緩衝區中的字元數小於 value,CommEvent 屬性設定為 comEvSend,並產生 OnComm 事件。comEvSend 事件僅當字元數與 Sthreshold 交叉時被激活一次。例如,如果 Sthreshold 等於 5,僅當在輸出佇列中字元數從 5 降到 4 時,comEvSend 才發生。如果在輸出佇列中從沒有比 Sthreshold 多的字元,comEvSend 事件將絕不會發生。
comInputModeText 0 (預設)通過 Input 屬性以文本方式取回數據。
comInputModeBinary 1 通過 Input 屬性以二進制方式檢取回數據。
5、CDHolding 屬性:通過查詢 Carrier Detect (CD) 線的狀態確定當前是否有傳輸。Carrier Detect 是從數據機傳送到相聯計算機的一個信號,指示數據機正在在線上。該屬性在設計時無效,在運行時為唯讀。
語法 object.CDHolding
設定值:CDHolding 屬性的設定值為:
設定 描述
True Carrier Detect 線為高電平
False Carrier Detect 線為低電平
說明:注意當 Carrier Detect 線為高電平 (CDHolding = True) 且逾時時,MSComm 控制項設定CommEvent 屬性為 comEventCDTO(Carrier Detect 逾時錯誤),並產生 OnComm 事件。
在主機應用程式中捕獲一個丟失的傳輸是特別重要的,例如一個公告板,因為呼叫者可以隨時掛起(放棄傳輸)。
Carrier Detect 也被稱為 Receive Line Signal Detect (RLSD)。 數據類型 Boolean
6、DSRHolding 屬性:確定 Data Set Ready (DSR) 線的狀態。Data Set Ready 信號由數據機傳送到相連計算機,指示作好操作準備。該屬性在設計時無效,在運行時為唯讀。
語法:object.DSRHolding
object 所在處表示對象表達式,其值是“套用於”列表中的對象。
DSRHolding 屬性返回以下值:
值 描述
True Data Set Ready 線高
False Data Set Ready 線低
說明:當 Data Set Ready 線為高電平 (DSRHolding = True) 且逾時時,MSComm 控制項設定 CommEvent 屬性為 comEventDSRTO(數據準備逾時)並產生 OnComm 事件。
當為Data Terminal Equipment (DTE) 機器寫 Data set Ready/Data Terminal Ready握手例程時該屬性十分有用。
數據類型:Boolean
7、Settings 屬性: 設定並返回波特率、奇偶校驗、數據位、停止位參數。
語法: object.Settings[ = value]
說明:當連線埠打開時,如果 value 非法,則 MSComm 控制項產生錯誤 380(非法屬性值)。
Value 由四個設定值組成,有如下的格式:
"BBBB,P,D,S "
BBBB 為波特率,P為奇偶校驗,D為數據位數,S為停止位數。value 的預設值是: "9600,N,8,1 "
8、InputLen 屬性:設定並返回 Input 屬性從接收緩衝區讀取的字元數。
語法 : object.InputLen [ = value] InputLen 屬性語法包括下列部分: value 整型表達式,說明 Input 屬性從接收緩衝區中讀取的字元數。
說明:
InputLen 屬性的預設值是 0。設定 InputLen 為 0 時,使用 Input 將使 MSComm 控制項讀取接收緩衝區中全部.
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 奇偶校驗錯。硬體檢測到奇偶校驗錯誤7
ComEventTxFull 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 檢取連線埠設備控制塊時出現內部錯誤
搞清楚
以上基本屬性後,就可以開始編寫通信許程式了。在VB5.0/6.0中新建一個工程檔案。添加Microsoft Comm Control 5.0組
件,在簡體Form1中加入Command命令按鈕並取名為CmdTest,MSComm控制項取名為MSComm1,加入如下程式代碼。
Private Sub cmdTestClick ( ) '打開串口
MSComml.CommPort =2 '設定Com2
If MSComml.PortOpen = False Then
MSComm1.Settings = "9600,n,8,1" '9600波特率,無校驗,8位數據位,1位停止位
MSComm1.PortOpen = True '打開串口
End if
MSComm1.OutBufferCount = 0 '清空傳送緩衝區
MSComm1.InBufferCount = 0 '清空接收緩衝區
'傳送字元數據時注意必須用回車符(vbcr)結束
MSComm1.Output="This is a qood book ! " &vbCr
'潑打電話號碼或傳送AT命令
MSComm1.Output = "ATDT , & vbCr
'傳送字元數組數據時注意ByteArray必須事先定義賦值
Dim ByteArray as byte( )
'定義動態數組
ReDim ByteArray(1)
'重定義數組大小
ByteArray ( 0 ) =0
ByteArray ( 1 ) = 1
MSComm1.Output = ByteArray
End Sub
private Sub MScommEvent( )
Select Case MSComm1.CommEvent
Case comEvReceive
Dim Buffer As Variant
MSComm1.InputLen = 0
'接收二進制數據
MSComm1.InputMode= ComInputModeBinary
Buffer=MSComm1.Input
'接收字元數據
MSComm1.InputMode=comInputModeText
Buffer = MSComml.Input
Case else
End Select
End sub
( 程式1)
中文Win 95/98下的通信問題與解決方法
接收的數據少於傳送的數據
如果通過MSComm控制項一次性傳送較多的二進制數據,那么,很可能收到的數據不足。例如在設定為24oobps傳輸率的情況下,一次性可以傳輸2048個字元數據 那么在大多數情況下。一次只能收到1200個字元左右,這址出為新版的MSComm32.OCX中存在一個影響傳輸二進制數據的臭蟲(bug).注意這不是特性。
32位Windows API函式(以下簡稱API)使用了幾個用COMMTIMEOUTS結構表示的限時變數,WriteTotalTimeOutConstant 即是其中的一個,它被Windows內部設定為5000(即5秒),這個常量決定了在通信驅動程式停止傳輸之前花費在傳送緩衝區中數據的時間的長短,5秒鐘意味著通信速度為1200bps情況下僅能傳送600個字元,24oobps情況下僅能傳送1200個左右的字元。事實上,在一個緩衝區內一次性傳送更多的數據是非常可能的。這個bug同樣也能引發問題,甚至在高速串口門通信情況下,即使系統在使用流控制,無論叢軟體流(Xon/XofI)還是硬體流(CTS/RTS)。假如數據在傳送緩衝區中時,流控制停止了傳輸,如果停止時間超過5秒鐘.則數據就會丟失。在某些環境下,5秒鐘可能相當短.不過也不必擔心, VB 5.0/6.0版本的MSComm控制項有一個新增的重要的屬性稱為CommID, CommID指的是當串口被打開時,被API所調用的串口句柄或稱標誌,這也意味著能利用API接口函式去修改這個常量。每次串口關閉後,Windows會自動將之恢復為5000,所以,每次打開串口後需要重斬設定以下API聲明,其代碼見下程式。
Type COMMTIMEOUTS
ReadIntervalTimeout As Long
ReadTotalTimeoutMultiplier As Long
ReadTotalTimeoutConstant As Long
WriteTotalTimeoutMultiplier As Long
WriteTotalTimeoutConstant As Long
End Type
Declare Function SetCommTimeouts Lib "Kernel32"
(BYVal hFile As Long, lpComm TimeoutsAs COMMTIMEOUTS) As Long
Declare Function GetCommTimeouts Lib "Kernel32"
(ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
Dim timeouts As COMMEOUTS
Dim Ret As Long
If Comm1.PortOpen = False Then
Comm1.PortOpen = True
End if
Ret=GetCommTimeouts ( Comm1.CommID , timeouts )
'Set some default timeouts
timeOuts.ReadIntervalTimeout = 1
timeouts.ReadTotalTimeoutMultiplier =1
timeouts.ReadTotalTimeoutConstant =1
timeouts.WriteTotalTimeoutMultiplier =1
timeouts.
WriteTotalTimeoutConstant=
( Comm1.OutBufferSize\Val(Comm1.Settings))*10000+1000
Ret=SetCommTimeouts( Comm1.CommID , timeouts )
( 程式2)
如何傳送大於128的字元數據
在通信程式中,以單字元方式逐個傳送數據時,每一個數據範圍 0-255(即十六進制的00-FF)。在單字元版本的英文Win95或
DOS版的BASIC程式中,只需要將相應的數據轉換成相應的字元傳送到通信連線埠即可。但在中文Win95/98下卻行不通,假設在中文
Win95/98下運行以下程式:
Dim i
For i=0 to 255
MSComm1.Output=chr(i)
Next i
希望在接收端得到預期的0-255之間的數據,結果卻是:前129個數據接收正確,為0-128,後面127個數據為126個0和一個255,造成這種結果的原因在於中文Windows使用的是雙位元組字元集(DBCS)系統。DBCS系統使用0-128之間的數字表示ASCII字元,大於128的數字僅作為前導字元,它只是顯示是一個非拉丁語系的字元,而並不代表實際意義。上述程式在調用CHR()函式時用到了DBCS字元集,岡此產生了此類錯誤。那么,如何傳送大於128的數據呢?答案是使用字元數組,將以上程式改為:
Dim cc(255) As Byte
For i = 0 To 255
cc(i) = i
Next i
MSComm1.Output = cc
Do
DoEvents
Loop Until MSComm1.OutBufferCount = 0
'接收過程 MSComm1_OnComm()
Select Case MSComm1.CommEvent
Case comEvReceive
Dim Buffer As Variant, b1,i
MSComm1.InputMode=comInputModeBinery
MSComm1.InputLen = 0
Buffer = MSComm1.Input
For i=LBound (Buffer) To UBound (Buffer )
Debug.Print Buffer ( i ) ;
Next i
Case . . . . .
3.如何傳送0字元(00H,NULL)
在VisuaI C++中使用串口控制項傳送0字元有些麻煩,但在VB5.0/6.0中只要注意以下兩點即可:
(1)設定MSComm控制項的屬性 NullDiscard=False;。
(2)使用二進制接收,即用 MSComm1.InputMode=ComInputModeBinary便可以解決問題;
4.如何傳送遞中文字元串(DBcS字元)
VB5.0/6.0的各種參考書上均指明MSComm通信控制項不能傳送或接收雙位元組字元集系統DBCS)的二進制數據,這對於我國及亞洲一些使用DBCS字元集的國家不能不說是一大人遺憾。但是我在實踐中發現,用MSComm控制項也可以傳送中文字元,具體方法有以下兩種:
(1)直接傳送
直接傳送即把中文字元等同於英文字元。如:MSComm1.Intput= " 這是一行中文數據!" ,但這種方法傳送的中文數據不能太長,傳送緩衝區和接收緩衝區的大小需設定為中文字元的兩倍以上,而且傳送與接收系統所處的作業系統版本最好要一致,否則會出現接收或傳送緩衝區溢出之類的錯誤。這種方法時用於一般要求不太高的場合。
(2)間接傳送
在傳送端將漢字或字元轉換為機器內碼或區位碼數據數組,然後將詠轉換後的數據傳送到串口,在接收端接收到數據後,按照相反的順序得到的數據轉換為相應的漢字或字元,在轉換過程中.要用到位運算,如取得漢字的內碼後需要將高位元組和低位元組分開,而VB5.0/6.0中並沒有提供此類函式,以下是求整數高、低位元組的函式。
Public Function HiByte(a As Integer )
Dim b
b= a And &HFF00
b = b / 256
If b<0 Then b = b + 256
HiByte = b
End Function
Public Function LowByte(a As Integ`er)
Dim b
b = a And &HFF
LowByte = b
End Function
5.如何用單機進行通信測試
通常在寫好了通信程式後需要兩台PC或一台Pc、一台單片機.將通信口連線後進行測試,但很多時候因條件限制僅有單台PC機,測試項目很簡單,那么能否測試呢?當然可以,而且方法也很簡單。對於九針的串口,找一個廢棄的串口滑鼠,剝外滑鼠線,將連線2、3針的線對接即可;對於25針的串口,找一枚曲別針(最好有塑膠外套的)將它扯直,剝削去兩頭的塑膠後在兩頭各彎一個圓圈,中間對忻後直接套接在串口的2、3針上即可。如果但心不夠安全,則可以將5針按地。
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
關於mscomm的用法,提高篇......[mgwmj]©
MSCOMM控制項是個好東西,如果您能夠充分了解他,他會為您衷心的效勞。
大致看了一下下午有關討論MSCOMM的話題,覺得有必要說說我的心得,我一般只做硬體,沒有系統的學過軟體,只是業餘時間學學用用,多少掌握了一點,也在此拿出來玩玩,不知有錯沒有,我可是以為我已經做的很好了^_^這是一個VB通用串口事件驅動接收程式。一次性接收一個數據包,數據包可以為任意位元組,保證不會丟失一個數據!
Private Sub MSComm_OnComm()
Dim S() As Byte
Dim SS(1024) As Byte
Static N As Long
Static T As Variant
If (MSComm.CommEvent = comEvReceive) Then
S = MSComm.Input '只要有數據就收進來,哪怕只是一個
If (Timer - T > 0.01) Then '間隔10MS以上就認為是一個新的包
text1="" 'text1用於蒐集和顯示接收(HEX格式)
N = 0
End If
T = Timer
For i = 0 To UBound(S) '一個數據包可能產生若干個oncomm事件
Text1.Text = Text1.Text & Right("0" & Hex(S(i)) & "H", 3) + " "
SS(N+i)=S(i) '接收數據包快取於SS()
N=N+UBound(S)
Next i
End If
End Sub