關於MSCOMM控制元件的一些說明(轉貼)

youhello發表於2008-01-27
關於MSCOMM控制元件的一些說明 VB5.0/6.的MSComm通訊控制元件提供了一系列標準通訊命令的介面,它允許建立串列埠連線,可以連線到其他通訊裝置(如Modem).
還可以傳送命令、進行資料交換以及監視和響應在通訊過程中可能發生的各種錯誤和事件,從而可以用它建立全雙工 、事件驅
動的、高效實用的通訊程式。但在實際通訊軟體設計過程中,MSComm控制元件並非像想像中那樣完美和容易控制.特別是在中文Wln
95/98下通訊時更會出現問題。下面就從基礎開始介紹,然後逐步討淪MSComm控制元件在程式設計中出現的問題以及程式設計技巧。[@more@]一、用MSComm控制元件通訊
1.串列埠通訊基礎知識
一般悅來,計算機都有一個或多個串列埠,它們依次為com1、Com2、…,這些串列埠還提供了外部裝置與pC進行資料傳輸和
皿信的通道。這些串列埠在CPU和外設之間充當直譯器的角色。當字元資料從CPU傳送給外設時,這些字元資料將被轉換成序列位元
流資料;當接收資料時,位元流資料被轉換為字元資料傳遞給CPU,再進一步說,在作業系統方面,Windows用通訊驅動程式
(COMM.DRV)呼叫API函式傳送和接收資料,當用通訊控制元件或宣告呼叫API函式時,它門由COMM. DRV解釋並傳遞給裝置驅動程式,
作為一個vB程式設計師,要編寫通訊程式.只需知道通訊控制元件提供給Windows通訊AP1函式的介面即可.換句話說,只需設定和監視通
信控制元件的屬性和事件即可。
2.使用Mscomm控制元件
在開始使用MSComm控制元件之前。需要先了解其屬性、事件或錯誤
屬性 描述
CommPort 設定或返回通訊埠號
Settings 以字串的形式設定或返回波特率、奇偶校驗、資料位和停止位
PortOpen 設定或返回通訊埠的狀態。也可以開啟和關閉埠
Input 返回和刪除接收緩衝區中的字元
Output 將字串寫入傳送緩衝區

CommEvent屬性為通訊事件或錯誤返回下列值之一。在該控制元件的物件庫中也可以找到這些常量。
常量 值 描述
ComEventBreak 1001 收到了斷開訊號
ComEventCTSTO 1002 Clear To Send Timeout。在傳送字元時,在系統指定的事1件內,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檢測到響鈴訊號。一些URAT(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 05778191898 , & 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下的通訊問題與解決方法
1.接收的資料少於傳送的資料
如果透過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.OutBufferSizeVal(Comm1.Settings))*10000+1000
Ret=SetCommTimeouts( Comm1.CommID , timeouts )
( 程式2)

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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/79126/viewspace-998531/,如需轉載,請註明出處,否則將追究法律責任。

相關文章