VB.net写一个简易串口RS485调试助手

最近在调试带rs485串口通讯的设备,项目上主要是用PLC和串口通讯,因为PLC有集成好的串口块,使用起来比较容易,为了方便测试,就想着用上位机写一个简易的串口通讯程序,用于调试。
在网上查找了一些资料后,基本上选择了两个方式,VB.net和python,python来写串口通讯程序,我在另一篇博客里面已经发了:
https://blog.csdn.net/normer123456/article/details/124402399
本文中介绍一下使用vb.net来写串口程序的示例。
VB.net写一个简易串口RS485调试助手_第1张图片

图片是UI界面,vb.net相对来说,界面比python要友好一点,控件可以直接拖放到窗体,而python制作界面,需要利用pyqt这类UI模块,有点麻烦。
软件:Microsoft Visual Studio Community 2019 版本 16.11.3
硬件:windows10电脑
rs485串口设备(流量计)

串口通讯在逻辑步骤上,基本上差不多,无非是初始化参数,打开串口,读写数据,关闭串口,就不多赘述了。

直接看程序吧。

01 初始化:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim baud_installs() As String = New String() _
        {"9600", "19200", "38400", "115200"}

        baudcombox.Items.AddRange(baud_installs)
        baudcombox.Text = baudcombox.Items(0)

        databitcombox.Items.AddRange({"8", "7"})
        databitcombox.Text = databitcombox.Items(0)


        stopbitcombox.Items.AddRange({"0", "1"})
        stopbitcombox.Text = stopbitcombox.Items(0)

        paritycombox.Items.AddRange({"无", "偶校验", "奇校验"})
        paritycombox.Text = paritycombox.Items(0)


        ToolStripStatusLabel1.Text = "当前无可用串口。。。"

        huayuan(PictureBox1, Color.Gray)

    End Sub

这里参数利用combox控件来进行选择,根据所选择不同,传入不同的值来进行初始化,所以,程序启动后,必须先设置参数值,然后才能点击“打开按钮,否则会提示错误。

02 打开串口:

 Private Sub portopen()
        Try
            SerialPort1.Open()
            Call portstart()
            If SerialPort1.IsOpen Then

                ToolStripStatusLabel1.Text = SerialPort1.PortName + "已打开"
                ToolStripStatusLabel1.ForeColor = Color.Green
                huayuan(PictureBox1, Color.Green)
                Console.WriteLine(SerialPort1.PortName)

                Console.WriteLine("ok!")
            End If


        Catch ex As UnauthorizedAccessException

            MsgBox("串口被占用或串口错误!", MsgBoxStyle.Information, "tips!")

        End Try
    End Sub

打开串口就是serial.open即可。

03 写入数据:

Private Sub comsend()

        Dim senddata As String
        Dim senddata_byte(8) As Byte

        'datestr = Format(Now(), "yyyy/MM/dd H:mm:ss ffff")
        datestr = Format(Now(), "yyyy/MM/dd H:mm:ss")

        'TextBox1.Clear()

        'senddata_byte(0) = &H1    '一种表示16进制数的方式
        'senddata_byte(1) = &H3
        'senddata_byte(2) = &H0
        'senddata_byte(3) = &H10
        'senddata_byte(4) = &H0
        'senddata_byte(5) = &H2
        'senddata_byte(6) = &HC5
        'senddata_byte(7) = &HCE


        senddata_byte = strtohex(TextBox1.Text)
        senddata = ""

        Try
            SerialPort1.Write(senddata_byte, 0, 8)
            TextBox1.AppendText(senddata)
            TextBox2.AppendText(vbCrLf + "[" + datestr + "]" + " " + senddata + vbCrLf)

            comrec()

            Console.WriteLine("send ok!")

        Catch ex As Exception

            MsgBox(ex.Message, MsgBoxStyle.YesNoCancel, "tips!")

        End Try
    End Sub

写入数据或者说发送数据,就是serial.write,这里需要注意的是,发送的数据是字节数组形式,因此,需要进行字符串到字节的转换。
关于字符串和字节数组之间的互相转换,我在测试的时候,在网上找了不少资料,许多博客虽然写了,但大多是抄来的,或者就是不够实用,很多人是利用字符转成ASCII码,在对应转16进制,程序比较麻烦。
然后我找了半天,发现一个利用正则表达式来进行转换的, 比较简单有效,感谢网络。

string to byte 转换程序:

Private Function strtohex(s As String) '将字符串转成16进制数值

        Dim mc As MatchCollection = Regex.Matches(s, "(?i)[\da-f]{2}")  '使用正则表达式从输入文本框的字符串中提取16进制数
        Dim buf As New List(Of Byte)()
        Dim bt As Byte()


        For Each m As Match In mc

            buf.Add(Byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber))

        Next
        bt = buf.ToArray()
        Return bt
        'Console.WriteLine(bt)



    End Function

至于16进制转字符串比较简单, vb.net有个Hex函数直接就可以转换,不多说了。

04 读取数据:

Private Sub comrec()
        Dim rxstr As Integer
        Dim recstr As String
        Dim recbyte(20) As Byte
        datestr = Format(Now(), "yyyy/MM/dd H:mm:ss")
        Try
            rxstr = SerialPort1.Read(recbyte, 0, 10)
            For i = 0 To rxstr - 1
                recstr = recstr + hextostr(recbyte(i)) + " "
            Next
            TextBox2.AppendText(vbCrLf + "[" + datestr + "]" + " " + recstr + vbCrLf)
            Console.WriteLine(recstr)
            Application.DoEvents()
            'TextBox1.AppendText(recstr)

        Catch ex As Exception
            MsgBox(ex.Message + "or 无可用串口", MsgBoxStyle.YesNo, "tips!")
            'rxstr = SerialPort1.ReadExisting
            'TextBox1.AppendText(vbCrLf + "[" + datestr + "]" + " " + rxstr + vbCrLf)
            'Application.DoEvents()

        End Try
    End Sub

读取就是使用serial.read,或者readall、readline都行。read的话,需要设置缓冲区、偏移量、接收长度,比较简单。

读写完成后,如果不想一直读写。可以关闭串口:

Private Sub portclose()
        Try
            If SerialPort1.IsOpen Then
                SerialPort1.Close()
                If SerialPort1.IsOpen = 0 Then
                    ToolStripStatusLabel1.Text = SerialPort1.PortName + "已关闭"
                    ToolStripStatusLabel1.ForeColor = Color.Red
                    huayuan(PictureBox1, Color.Gray)
                End If
            Else
                MsgBox("无可用串口", MsgBoxStyle.Information, "tips!")

            End If


        Catch ex As Exception
            MsgBox("串口未打开或串口异常!", MsgBoxStyle.Information, "tips!")
        End Try
    End Sub

serial.close即可。

关于程序的一些细节,我这边就不多说了,基本上都是在网上找了很多资料,然后自己一点点试出来的,网上虽然有很多资料,但很少有直接拿过来能用的,想要满足自己使用,还是得自己摸索半天。我把完整程序也发出来,需要说明的是,程序是经过我测试,完全可用的,但我不确定如果有朋友想直接使用,是否是和我一样的。

完整程序:

Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Net

Public Class Form1

    Dim ser_br As Integer
    Dim ser_db As Integer
    Dim ser_stopbit As Integer
    Dim ser_parity As Integer

    Dim datestr As String = ""

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim baud_installs() As String = New String() _
        {"9600", "19200", "38400", "115200"}

        baudcombox.Items.AddRange(baud_installs)
        baudcombox.Text = baudcombox.Items(0)

        databitcombox.Items.AddRange({"8", "7"})
        databitcombox.Text = databitcombox.Items(0)


        stopbitcombox.Items.AddRange({"0", "1"})
        stopbitcombox.Text = stopbitcombox.Items(0)

        paritycombox.Items.AddRange({"无", "偶校验", "奇校验"})
        paritycombox.Text = paritycombox.Items(0)


        ToolStripStatusLabel1.Text = "当前无可用串口。。。"

        huayuan(PictureBox1, Color.Gray)

    End Sub

    Private Sub portstart()


        SerialPort1.BaudRate = ser_br
        SerialPort1.DataBits = ser_db
        SerialPort1.StopBits = ser_stopbit
        SerialPort1.Parity = ser_parity
        SerialPort1.ReadTimeout = 1000
        SerialPort1.NewLine = vbCrLf
    End Sub

    Private Sub getserialportname()
        For Each sp As String In My.Computer.Ports.SerialPortNames
            ComboBox1.Items.Add(sp)
        Next
        ComboBox1.Text = ComboBox1.Items(0)
        'Console.WriteLine(ComboBox1.Text)
    End Sub
    Private Sub portopen()
        Try
            SerialPort1.Open()
            Call portstart()
            If SerialPort1.IsOpen Then

                ToolStripStatusLabel1.Text = SerialPort1.PortName + "已打开"
                ToolStripStatusLabel1.ForeColor = Color.Green
                huayuan(PictureBox1, Color.Green)
                Console.WriteLine(SerialPort1.PortName)

                Console.WriteLine("ok!")
            End If


        Catch ex As UnauthorizedAccessException

            MsgBox("串口被占用或串口错误!", MsgBoxStyle.Information, "tips!")

        End Try
    End Sub
    Private Sub portclose()
        Try
            If SerialPort1.IsOpen Then
                SerialPort1.Close()
                If SerialPort1.IsOpen = 0 Then
                    ToolStripStatusLabel1.Text = SerialPort1.PortName + "已关闭"
                    ToolStripStatusLabel1.ForeColor = Color.Red
                    huayuan(PictureBox1, Color.Gray)
                End If
            Else
                MsgBox("无可用串口", MsgBoxStyle.Information, "tips!")

            End If


        Catch ex As Exception
            MsgBox("串口未打开或串口异常!", MsgBoxStyle.Information, "tips!")
        End Try
    End Sub
    Private Sub comrec()
        Dim rxstr As Integer
        Dim recstr As String
        Dim recbyte(20) As Byte
        datestr = Format(Now(), "yyyy/MM/dd H:mm:ss")
        Try
            rxstr = SerialPort1.Read(recbyte, 0, 10)
            For i = 0 To rxstr - 1
                recstr = recstr + hextostr(recbyte(i)) + " "
            Next
            TextBox2.AppendText(vbCrLf + "[" + datestr + "]" + " " + recstr + vbCrLf)
            Console.WriteLine(recstr)
            Application.DoEvents()
            'TextBox1.AppendText(recstr)

        Catch ex As Exception
            MsgBox(ex.Message + "or 无可用串口", MsgBoxStyle.YesNo, "tips!")
            'rxstr = SerialPort1.ReadExisting
            'TextBox1.AppendText(vbCrLf + "[" + datestr + "]" + " " + rxstr + vbCrLf)
            'Application.DoEvents()

        End Try
    End Sub
    Private Sub comsend()

        Dim senddata As String
        Dim senddata_byte(8) As Byte

        'datestr = Format(Now(), "yyyy/MM/dd H:mm:ss ffff")
        datestr = Format(Now(), "yyyy/MM/dd H:mm:ss")

        'TextBox1.Clear()

        'senddata_byte(0) = &H1    '一种表示16进制数的方式
        'senddata_byte(1) = &H3
        'senddata_byte(2) = &H0
        'senddata_byte(3) = &H10
        'senddata_byte(4) = &H0
        'senddata_byte(5) = &H2
        'senddata_byte(6) = &HC5
        'senddata_byte(7) = &HCE


        senddata_byte = strtohex(TextBox1.Text)
        senddata = ""

        Try
            SerialPort1.Write(senddata_byte, 0, 8)
            TextBox1.AppendText(senddata)
            TextBox2.AppendText(vbCrLf + "[" + datestr + "]" + " " + senddata + vbCrLf)

            comrec()

            Console.WriteLine("send ok!")

        Catch ex As Exception

            MsgBox(ex.Message, MsgBoxStyle.YesNoCancel, "tips!")

        End Try
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        getserialportname()

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Try
            SerialPort1.PortName = ComboBox1.SelectedItem()
            Console.WriteLine("you choose:" & SerialPort1.PortName)
            portopen()
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.YesNoCancel, "tips!")
        End Try


    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        portclose()

    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
        ToolStripStatusLabel1.Text = "当前选择串口号:" + ComboBox1.SelectedItem()

        'Console.WriteLine(ComboBox1.Text)
    End Sub

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        comsend()

    End Sub

    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
        comrec()


    End Sub

    Private Sub paritycombox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles paritycombox.SelectedIndexChanged

        Select Case paritycombox.Text
            Case "无"
                ser_parity = 0
            Case "偶校验"

                ser_parity = 1
            Case "奇校验"
                ser_parity = 2
        End Select
        'Console.WriteLine(ser_parity)


    End Sub

    Private Sub baudcombox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles baudcombox.SelectedIndexChanged
        Select Case baudcombox.Text
            Case "9600"
                ser_br = 9600
            Case "19200"
                ser_br = 19200
            Case "38400"
                ser_br = 38400
            Case "115200"
                ser_br = 115200
        End Select
        'Console.WriteLine(ser_br)
    End Sub

    Private Sub databitcombox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles databitcombox.SelectedIndexChanged
        Select Case databitcombox.Text
            Case "8"
                ser_db = 8
            Case "7"
                ser_db = 7
        End Select
    End Sub

    Private Sub stopbitcombox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles stopbitcombox.SelectedIndexChanged
        Select Case stopbitcombox.Text
            Case "0"
                ser_stopbit = 0
            Case "1"
                ser_stopbit = 1
        End Select
    End Sub

    ''' 
    ''' 16进制转字符函数
    ''' 本函数为自定义函数
    ''' 
    ''' 字节

    Private Function hextostr(h As Byte) '将16进制数值转成字符串,且二者等效转换

        Dim x As String

        If h < 10 Then
            x = "0" + Hex(h)
        Else
            x = Hex(h)
        End If
        Return x

    End Function
    ''' 
    ''' 字符转16进制函数
    ''' 本函数为自定义函数
    ''' 
    ''' 字符串

    Private Function strtohex(s As String) '将字符串转成16进制数值

        Dim mc As MatchCollection = Regex.Matches(s, "(?i)[\da-f]{2}")  '使用正则表达式从输入文本框的字符串中提取16进制数
        Dim buf As New List(Of Byte)()
        Dim bt As Byte()


        For Each m As Match In mc

            buf.Add(Byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber))

        Next
        bt = buf.ToArray()
        Return bt
        'Console.WriteLine(bt)



    End Function


    ''' 
    ''' 画圆函数
    ''' 本函数为自定义函数
    ''' 
    ''' 图形容器
    ''' 颜色
    Private Sub huayuan(pb As PictureBox, c As Color) '在picturebox中绘制圆形的函数

        Dim b As Bitmap = New Bitmap(pb.Width, pb.Height)
        Dim g As Graphics = Graphics.FromImage(b)
        Dim mybrush As New SolidBrush(c)
        g.FillEllipse(mybrush, 0, 0, pb.Width, pb.Height)
        g.Dispose()
        pb.Image = b



    End Sub

    Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
        Dim buf As Byte()
        Dim n As Integer

        Console.WriteLine(strtohex(TextBox1.Text))
    End Sub
End Class

如果有朋友有什么问题,可以评论区问,我知道的,会回复,不懂的,就没办法了。

你可能感兴趣的:(工业自动化编程,VB.net实例应用,python)