小記:VB.NET的串口通信用了很長(cháng)時(shí)間了,也只用Write和Read這樣的方法,以前都是用這種方式做上位機軟件,如此足矣。而前幾天研究GSM模塊時(shí)對串口返回的數據總是把握不好,參考開(kāi)發(fā)板附送的例程,發(fā)現采用SerialPort的DataReceived事件,可以實(shí)現中斷觸發(fā)式的數據接收。于是想到要自己做一個(gè)串口調試助手,在實(shí)現基本功能的前提下增加一些方便自己調試的功能。經(jīng)過(guò)斷斷續續的編寫(xiě),就做成了下面這個(gè)小軟件:

這個(gè)軟件能夠實(shí)現串口調試助手的全部功能,經(jīng)過(guò)通信測試,數據接收性能不亞于呼嘯工作室的SComAssistant2.2,通過(guò)加大輸入緩沖區,可以滿(mǎn)足大量數據接收。
VB.NET的串口通信主要使用VS自帶的SerialPort控件,而不是早先的MSComm,更具有兼容性,這也是很久以前就放棄VB改用.NET的直接原因。該控件的主要方法、屬性如下(該數據來(lái)自VS的MSDN幫助庫):
方法 | 說(shuō)明 |
Open | 打開(kāi)一個(gè)新的串行端口連接。 |
Close | 關(guān)閉端口連接,將 IsOpen 屬性設置為 false,并釋放內部 Stream 對象。 |
Read | 已重載。 從 SerialPort 輸入緩沖區中讀取。 |
ReadByte | 從 SerialPort 輸入緩沖區中同步讀取一個(gè)字節。 |
ReadChar | 從 SerialPort 輸入緩沖區中同步讀取一個(gè)字符。 |
ReadExisting | 在編碼的基礎上,讀取 SerialPort 對象的流和輸入緩沖區中所有立即可用的字節。 |
ReadLine | 一直讀取到輸入緩沖區中的 NewLine 值。 |
ReadTo | 一直讀取到輸入緩沖區中的指定 value 的字符串。 |
Write | 已重載。 將數據寫(xiě)入串行端口輸出緩沖區。 |
WriteLine | 將指定的字符串和 NewLine 值寫(xiě)入輸出緩沖區。 |
DiscardInBuffer | 丟棄來(lái)自串行驅動(dòng)程序的接收緩沖區的數據。 |
DiscardOutBuffer | 丟棄來(lái)自串行驅動(dòng)程序的傳輸緩沖區的數據。 |
GetPortNames | 獲取當前計算機的串行端口名稱(chēng)數組。 |
屬性 | 說(shuō)明 |
PortName | 獲取或設置通信端口,包括但不限于所有可用的 COM 端口。 |
BaudRate | 獲取或設置串行波特率。 |
DataBits | 獲取或設置每個(gè)字節的標準數據位長(cháng)度。 |
Parity | 獲取或設置奇偶校驗檢查協(xié)議。 |
StopBits | 獲取或設置每個(gè)字節的標準停止位數。 |
IsOpen | 獲取一個(gè)值,該值指示 SerialPort 對象的打開(kāi)或關(guān)閉狀態(tài)。 |
BytesToRead | 獲取接收緩沖區中數據的字節數。 |
BytesToWrite | 獲取發(fā)送緩沖區中數據的字節數。 |
Encoding | 獲取或設置傳輸前后文本轉換的字節編碼。 |
ReadBufferSize | 獲取或設置 SerialPort 輸入緩沖區的大小。 |
ReceivedBytesThreshold | 獲取或設置 DataReceived 事件發(fā)生前內部輸入緩沖區中的字節數。 |
WriteBufferSize | 獲取或設置串行端口輸出緩沖區的大小。 |
想要通過(guò)串口收發(fā)數據,就需要對串口進(jìn)行配置,包括設置端口、波特率、數據格式(如COM1端口、9600bps、8位數據位、無(wú)校驗位、1位停止位)等屬性,之后通過(guò)Open方法打開(kāi)串口。打開(kāi)串口可通過(guò)手動(dòng)指定,也可以使用GetPortNames方法獲取計算機中存在的串口。如果打開(kāi)出錯,則可能是串口不存在或者已被占用。下面是相應代碼:
Private Sub SerialPortOpen()
On Error GoTo Err
If SerialPort.IsOpen = True Then SerialPort.Close() '避免重復打開(kāi)端口
SerialPort.Open()
LabelCOMStatus.Text = "串口已打開(kāi)"
Exit Sub
Err: MsgBox("串口不存在或已被占用!" + vbNewLine + ErrorToString()) '出現錯誤,顯示錯誤信息
End Sub
如果想要在串口中支持中文字符收發(fā),則可在初始化時(shí)設置串口控件的編碼:
SerialPort.Encoding = System.Text.Encoding.Default
發(fā)送數據通過(guò)Write方法來(lái)完成,由于串口調試助手需要支持文本和16進(jìn)制,需要加入轉換代碼:
Private Sub ButtonSendData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSendData.Click
On Error GoTo Err
Dim outDataBuf As String = TextBoxSend.Text
If outDataBuf = "" Then Exit Sub '如果輸入文本框中沒(méi)有數據則不發(fā)送
If SerialPort.IsOpen = True Then '判斷串口是否打開(kāi)
If HexSendFlag = True Then
'-----------十六進(jìn)制發(fā)送------------
outDataBuf = outDataBuf.Replace(" ", "") '清除空格與回車(chē)
outDataBuf = outDataBuf.Replace(vbNewLine, "")
'十六進(jìn)制數據位數為偶數,例如:FF 00 15 AC 0D
If outDataBuf.Length Mod 2 <> 0 Then
MsgBox("請輸入正確的十六進(jìn)制數,用空格和回車(chē)隔開(kāi)。")
Exit Sub
End If
Dim outBytes(outDataBuf.Length / 2 - 1) As Byte
For I As Integer = 1 To outDataBuf.Length - 1 Step 2
outBytes((I - 1) / 2) = Val("&H" + Mid(outDataBuf, I, 2)) 'VB的十六進(jìn)制表示方法,例如0x1D表示為&H1D
Next
SerialPort.Write(outBytes, 0, outDataBuf.Length / 2)
BarCountTx.Text = Val(BarCountTx.Text) + outDataBuf.Length / 2
Else
'-------------文本發(fā)送--------------
SerialPort.Write(outDataBuf)
BarCountTx.Text = Val(BarCountTx.Text) + outDataBuf.Length '發(fā)送字節計數
End If
Else
MsgBox("串口未打開(kāi),請先打開(kāi)串口。")
End If
Exit Sub
Err: MsgBox("數據輸入或發(fā)送錯誤!" + vbNewLine + ErrorToString())
End Sub
接收數據采用DataReceived事件,該事件在串口輸入緩沖區中的字節數滿(mǎn)足設置條件時(shí)觸發(fā),并執行事件中的代碼。事件觸發(fā)的字節數在ReceivedBytesThreshold屬性中設置,默認為1字節。由于DataReceived事件采用了獨立的線(xiàn)程,無(wú)法對軟件界面中的控件進(jìn)行直接操作,因而在現實(shí)時(shí)需要采用委托實(shí)例的方法。首先建立委托:
Delegate Sub RecieveRefreshMethodDelegate(ByVal [text] As String) '聲明委托
Dim RecieveRefresh As New RecieveRefreshMethodDelegate(AddressOf RecieveRefreshMethod) '定義數據顯示委托實(shí)例
Sub RecieveRefreshMethod(ByVal str As String) '定義一個(gè)數據顯示委托實(shí)例的方法
ShowRecieveData(str)
End Sub
其中ShowRecieveData函數將str字符串顯示到TextBox控件中。
下面是DataReceived事件中對十六進(jìn)制數據的處理。同發(fā)送數據一樣,讀取數據時(shí)也要根據不同的顯示方式使用不同的方法。VB.NET通過(guò)Read方法,根據緩沖區中存在的字節數讀取十六進(jìn)制數據,而文本顯示則簡(jiǎn)單的多,只需ReadExisting即可。最后通過(guò)Invoke方法調用委托,顯示數據。
Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
If HexRecieveFlag Then
'-----------十六進(jìn)制顯示------------
Dim inDataLen As Integer = SerialPort.BytesToRead() '獲取可讀取的字節數
If inDataLen > 0 Then
Dim inBytes(inDataLen - 1) As Byte, bytes As Byte
Dim strHex As String = ""
SerialPort.Read(inBytes, 0, inDataLen) '讀取數據
For Each bytes In inBytes
strHex = strHex + [String].Format("{0:X2} ", bytes) '格式化成十六進(jìn)制(不含&H)
Next
TextBoxRecieve.Invoke(RecieveRefresh, strHex) '調用委托,顯示接收的數據
BarCountRx.Text = (Val(BarCountRx.Text) + inDataLen).ToString '接收字節計數
End If
Else
'-------------文本顯示--------------
Dim str As String
str = SerialPort.ReadExisting '讀取全部可用字符串
TextBoxRecieve.Invoke(RecieveRefresh, str)
BarCountRx.Text = (Val(BarCountRx.Text) + str.Length).ToString '接收字節計數
End If
End Sub
至此就實(shí)現了串口收發(fā)的基本功能,另外的定時(shí)收發(fā)(使用Timer控件)、文件發(fā)送(使用FileSystem)參見(jiàn)附帶的源文件代碼。
(附件功能完全不給力呀,終于傳上來(lái)了……)
在完成串口調試助手的功能后,還可以根據個(gè)人的使用習慣或需求,添加相應的功能。
聯(lián)系客服