目录
1.案例描述
本案例使用VB.net做的一个16进制数据串口收发小工具,支持modbus协议格式数据收发。文中重点描述VB.net中16进制输入数据转换到串口Write()函数参数的过程,还有串口Read()函数读取结果转换到16进制字符串显示的过程。最终效果如下图。
案例代码:https://download.csdn.net/download/weixin_44322043/89607533
2.输入数据到串口写入数据转换
输入数据到串口写入数据转换有两种方式,方式1见下方代码,hexString(String类型)为界面输入16进制字符串(不含空格),byteArray为串口Write()函数参数。
Dim byteArray As Byte() = Enumerable.Range(0, hexString.Length).Where(Function(X) X Mod 2 = 0).Select(Function(X) Convert.ToByte(hexString.Substring(X, 2), 16)).ToArray()
方式2见下方代码,hexString(String类型)为界面输入16进制字符串(不含空格),byteArray为串口Write()函数参数。
Dim byteArray(0 To (Len(hexString) / 2 - 1)) As Byte
For i = 1 To (Len(hexString)) Step 2
byteArray((i - 1) / 2) = Val("&H" + Mid(hexString, i, 2))
Next i
3.串口数据读取与数据转换
为了使数据接收及时,使用SerialPort控件的DataReceived事件,如下图
PortDataReceived事件函数代码如下,PortReading为读数据函数。
Public Sub PortDataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived '接受函数
Me.BeginInvoke(New EventHandler(AddressOf PortReading)) '调用读数据函数
End Sub
读数据函数PortReading代码和处理逻辑如下
Public Sub PortReading(ByVal sender As Object, ByVal e As EventArgs)
Try
If SerialPort1.BytesToRead > 0 Then
Dim byteToRead As Int16 = SerialPort1.BytesToRead
Dim ReadByte(byteToRead) As Byte
Dim bytesRead As Int16 = 0
Dim indata As String = ""
bytesRead = SerialPort1.Read(ReadByte, 0, byteToRead)
For i As Int16 = 0 To bytesRead - 1
indata = indata & DecToHex(ReadByte(i))
Next
Dim timeStr As String = DateTime.Now.ToString("HH.mm.ss.") + AddZero(DateTime.Now.Millisecond.ToString) + " R: " + indata.Trim + vbCrLf
TextBox2.Text += timeStr
End If
SerialPort1.DiscardInBuffer()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Public Function DecToHex(ByVal DecNumber As Byte) As String '转换成十六进制字符串,添加空格
If DecNumber <= 15 Then
DecToHex = " 0" & Hex(DecNumber)
Else
DecToHex = " " & Hex(DecNumber)
End If
End Function
4.完整代码展示
Public Class Form1
Private Sub BtnConnect_Click(sender As Object, e As EventArgs) Handles BtnConnect.Click '打开/关闭串口按钮
Try
If BtnConnect.Text = "打开串口" Then
SerialPort1.PortName = CBComName.Text
SerialPort1.BaudRate = 115200
SerialPort1.StopBits = IO.Ports.StopBits.One
SerialPort1.Parity = IO.Ports.Parity.None
SerialPort1.DataBits = 8
SerialPort1.ReadBufferSize = 5120
SerialPort1.ReadTimeout = 1000
SerialPort1.Open()
Else
SerialPort1.Close()
End If
If SerialPort1.IsOpen Then
BtnConnect.Text = "关闭串口"
Else
BtnConnect.Text = "打开串口"
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Public Function RemoveSpace(ByVal strText As String) As String '移除空格
Return System.Text.RegularExpressions.Regex.Replace(strText, " ", String.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
Private Sub WriteData(hexStringO As String) '写数据转换与写数据到串口
'去除空格
Dim hexString As String = RemoveSpace(hexStringO)
'转换方式1
Dim byteArray As Byte() = Enumerable.Range(0, hexString.Length).Where(Function(X) X Mod 2 = 0).Select(Function(X) Convert.ToByte(hexString.Substring(X, 2), 16)).ToArray()
'转换方式2
'Dim byteArray(0 To (Len(hexString) / 2 - 1)) As Byte
'For i = 1 To (Len(hexString)) Step 2
' byteArray((i - 1) / 2) = Val("&H" + Mid(hexString, i, 2))
'Next i
If SerialPort1.IsOpen Then
BtnConnect.Text = "关闭串口"
SerialPort1.DiscardOutBuffer()
SerialPort1.Write(byteArray, 0, byteArray.Length)
Dim timeStr As String = DateTime.Now.ToString("HH.mm.ss.") + AddZero(DateTime.Now.Millisecond.ToString) + " W: " + hexStringO + vbCrLf
TextBox2.Text += timeStr
Else
BtnConnect.Text = "打开串口"
End If
End Sub
Public Sub PortDataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived '接受函数
Me.BeginInvoke(New EventHandler(AddressOf PortReading)) '调用读数据函数
End Sub
Public Function DecToHex(ByVal DecNumber As Byte) As String '转换成十六进制字符串,添加空格
If DecNumber <= 15 Then
DecToHex = " 0" & Hex(DecNumber)
Else
DecToHex = " " & Hex(DecNumber)
End If
End Function
Public Sub PortReading(ByVal sender As Object, ByVal e As EventArgs) '读串口与数据处理
Try
If SerialPort1.BytesToRead > 0 Then
Dim byteToRead As Int16 = SerialPort1.BytesToRead
Dim ReadByte(byteToRead) As Byte
Dim bytesRead As Int16 = 0
Dim indata As String = ""
bytesRead = SerialPort1.Read(ReadByte, 0, byteToRead)
For i As Int16 = 0 To bytesRead - 1
indata = indata & DecToHex(ReadByte(i))
Next
Dim timeStr As String = DateTime.Now.ToString("HH.mm.ss.") + AddZero(DateTime.Now.Millisecond.ToString) + " R: " + indata.Trim + vbCrLf
TextBox2.Text += timeStr
End If
SerialPort1.DiscardInBuffer()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Function AddZero(strMs As String) As String 'ms显示补齐3位
AddZero = strMs
If strMs.Length < 3 Then
For num = 0 To 3 - strMs.Length - 1
AddZero = "0" & AddZero
Next
End If
End Function
Private Sub BtnSend1_Click(sender As Object, e As EventArgs) Handles BtnSend1.Click '发送按钮点击事件
WriteData(TextBox1.Text.Trim)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim portNames() As String = IO.Ports.SerialPort.GetPortNames() '获取所有串口名称
For Each port In portNames
CBComName.Items.Add(port) '将串口名称添加到串口下拉选择框
Next
If portNames.Length > 0 Then
CBComName.SelectedIndex = 0
End If
End Sub
Private Sub CBTime1_CheckedChanged(sender As Object, e As EventArgs) Handles CBTime1.CheckedChanged '定时发送开启关闭勾选框
If CBTime1.Checked Then
Timer1.Interval = Val(TBTime1.Text)
Timer1.Start()
Else
Timer1.Stop()
End If
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick '定时发送计时器
WriteData(TextBox1.Text.Trim)
End Sub
Private Sub BtnClear_Click(sender As Object, e As EventArgs) Handles BtnClear.Click '清除显示
TextBox2.Text = ""
End Sub
End Class