VB.NET串口通信例子

VB.NET 专栏收录该内容
52 篇文章 2 订阅


这是我3年前的一个例子,最近翻出来回忆一下。

串口是计算机上一种非常通用设备通信的协议。大多数计算机包含两个基于RS232的串口,现在配电脑好像只有一个。串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS-232口。同时,串口通信协议也可以用于获取远程采集设备的数据。串口通信在工控领域用途很广。

串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。

典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配:
a,波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。
c,停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位位1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。

串口通信还有一个参数是单工、半双工和双工。

如果在通信过程的任意时刻,信息只能由一方A传到另一方B,则称为单工。

如果在任意时刻,信息既可由A传到B,又能由B传A,但只能由一个方向上的传输存在,称为半双工传输。

如果在任意时刻,线路上存在A到B和B到A的双向信号传输,则称为全双工。

电话线就是二线全双工信道。 由于采用了回波抵消技术,双向的传输信号不致混淆不清。双工信道有时也将收、发信道分开,采用分离的线路或频带传输相反方向的信号,如回线传输。

在调试时可以用串口助手和windows的超级终端,不要带电插拔串口,容易烧毁。

在VB.NET中提供了IO.Ports类,是我们的编程变得很简单,下面是我的例子:

Form1.vb

  1. Imports System.IO.Ports  
  2.   
  3. Public Class Form1  
  4.   
  5.     Dim WithEvents RS232 As SerialPort  
  6.     Delegate Sub SetTextCallback(ByVal InputString As String)       '声明一个代理  
  7.   
  8.     Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load  
  9.         For Each sp As String In SerialPort.GetPortNames()  
  10.             cmbCom.Items.Add(sp)  
  11.         Next  
  12.         cmbCom.Sorted = True  
  13.         cmbCom.SelectedIndex = 0  
  14.     End Sub  
  15.   
  16.     Private Sub btnStart_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnStart.Click  
  17.         Dim mBaudRate As Integer  
  18.         Dim mParity As IO.Ports.Parity  
  19.         Dim mDataBit As Integer  
  20.         Dim mStopBit As IO.Ports.StopBits  
  21.         Dim mPortName As String  
  22.   
  23.         mPortName = cmbCom.SelectedItem.ToString  
  24.         mBaudRate = 9600  
  25.         mParity = Parity.None  
  26.         mDataBit = 8  
  27.         mStopBit = StopBits.One  
  28.   
  29.         RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopBit)  
  30.   
  31.         If Not RS232.IsOpen Then  
  32.             RS232.Open()  
  33.             btnSend.Enabled = True  
  34.             RS232.ReceivedBytesThreshold = 1        '设置引发事件的门限值  
  35.         Else  
  36.             MsgBox("通讯端口打开错误!", MsgBoxStyle.Critical)  
  37.         End If  
  38.     End Sub  
  39.   
  40.   
  41.     Private Sub RS232_DataReceived(ByVal sender As ObjectByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles RS232.DataReceived  
  42.         Dim InByte() As Byte, ReadCount As Integer, strRead As String  
  43.         If RS232.BytesToRead <= 0 Then Exit Sub  
  44.         ReDim InByte(RS232.BytesToRead - 1)  
  45.         ReadCount = RS232.Read(InByte, 0, RS232.BytesToRead)  
  46.         strRead = ""  
  47.         If ReadCount = 0 Then  
  48.             Exit Sub  
  49.         Else  
  50.             For Each bData As Byte In InByte  
  51.                 strRead += bData.ToString & vbCrLf     '若有数据则加到接收文本框  
  52.                 DisplayText(strRead)  
  53.             Next  
  54.         End If  
  55.   
  56.   
  57.     End Sub  
  58.     '*************************************************  
  59.     '代理子程序  
  60.     '处理上述通信端口的接收事件  
  61.     '由于欲将数据显示到接收文本框中,因此必须检查  
  62.     '是否由另外得Thread所调用的,若是,则必须先  
  63.     '建立代理对象  
  64.     'Invoke用于在拥有控件基础窗口控制代码的线程上  
  65.     '运行代理  
  66.     '*************************************************  
  67.     Private Sub DisplayText(ByVal comData As String)  
  68.         '如果调用txtReceive的另外的线程,返回true  
  69.         If Me.txtReceive.InvokeRequired Then  
  70.             '利用代理类型建立对象,并指定代理的函数  
  71.             Dim d As New SetTextCallback(AddressOf DisplayText)  
  72.             Me.Invoke(d, New Object() {comData})    '以指定的自变量列表调用函数  
  73.         Else '相同的线程  
  74.             'showstring(comData)     '将收到的数据填入接收文本框中  
  75.             Me.txtReceive.Text += comData  
  76.         End If  
  77.     End Sub  
  78.   
  79.     Private Sub btnClose_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnClose.Click  
  80.         If RS232 Is Nothing OrElse Not RS232.IsOpen Then   '尚未打开  
  81.             MsgBox("通讯端口尚未打开", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel)  
  82.         Else  
  83.             RS232.Close()  
  84.             btnStart.Enabled = False  
  85.             btnClose.Enabled = False  
  86.             RS232 = Nothing  
  87.         End If  
  88.     End Sub  
  89.   
  90.     Private Sub btnEnd_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnEnd.Click  
  91.         If Not RS232 Is Nothing Then  
  92.             If RS232.IsOpen Then RS232.Close()  
  93.         End If  
  94.         End  
  95.     End Sub  
  96.   
  97.     Private Sub btnSend_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnSend.Click  
  98.         Dim bDataOut(0) As Byte  
  99.         Try  
  100.             bDataOut(0) = CType(Me.txtSend.Text, Byte)        '将类型转换为字节  
  101.             RS232.Write(bDataOut, 0, 1)  
  102.         Catch ex As Exception  
  103.             MessageBox.Show("输入数值错误:" + ex.ToString, "错误通知:", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)  
  104.         End Try  
  105.     End Sub  
  106.   
  107.     Private Sub cmbCom_KeyPress(ByVal sender As ObjectByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCom.KeyPress  
  108.         e.KeyChar = ChrW(0)             '禁止用户在其中输入任何文字  
  109.     End Sub  
  110.   
  111.     Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click  
  112.         Me.Hide()  
  113.         Form2.Show()  
  114.     End Sub  
  115. End Class  
Imports System.IO.Ports

Public Class Form1

    Dim WithEvents RS232 As SerialPort
    Delegate Sub SetTextCallback(ByVal InputString As String)       '声明一个代理

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each sp As String In SerialPort.GetPortNames()
            cmbCom.Items.Add(sp)
        Next
        cmbCom.Sorted = True
        cmbCom.SelectedIndex = 0
    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        Dim mBaudRate As Integer
        Dim mParity As IO.Ports.Parity
        Dim mDataBit As Integer
        Dim mStopBit As IO.Ports.StopBits
        Dim mPortName As String

        mPortName = cmbCom.SelectedItem.ToString
        mBaudRate = 9600
        mParity = Parity.None
        mDataBit = 8
        mStopBit = StopBits.One

        RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopBit)

        If Not RS232.IsOpen Then
            RS232.Open()
            btnSend.Enabled = True
            RS232.ReceivedBytesThreshold = 1        '设置引发事件的门限值
        Else
            MsgBox("通讯端口打开错误!", MsgBoxStyle.Critical)
        End If
    End Sub


    Private Sub RS232_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles RS232.DataReceived
        Dim InByte() As Byte, ReadCount As Integer, strRead As String
        If RS232.BytesToRead <= 0 Then Exit Sub
        ReDim InByte(RS232.BytesToRead - 1)
        ReadCount = RS232.Read(InByte, 0, RS232.BytesToRead)
        strRead = ""
        If ReadCount = 0 Then
            Exit Sub
        Else
            For Each bData As Byte In InByte
                strRead += bData.ToString & vbCrLf     '若有数据则加到接收文本框
                DisplayText(strRead)
            Next
        End If


    End Sub
    '*************************************************
    '代理子程序
    '处理上述通信端口的接收事件
    '由于欲将数据显示到接收文本框中,因此必须检查
    '是否由另外得Thread所调用的,若是,则必须先
    '建立代理对象
    'Invoke用于在拥有控件基础窗口控制代码的线程上
    '运行代理
    '*************************************************
    Private Sub DisplayText(ByVal comData As String)
        '如果调用txtReceive的另外的线程,返回true
        If Me.txtReceive.InvokeRequired Then
            '利用代理类型建立对象,并指定代理的函数
            Dim d As New SetTextCallback(AddressOf DisplayText)
            Me.Invoke(d, New Object() {comData})    '以指定的自变量列表调用函数
        Else '相同的线程
            'showstring(comData)     '将收到的数据填入接收文本框中
            Me.txtReceive.Text += comData
        End If
    End Sub

    Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
        If RS232 Is Nothing OrElse Not RS232.IsOpen Then   '尚未打开
            MsgBox("通讯端口尚未打开", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel)
        Else
            RS232.Close()
            btnStart.Enabled = False
            btnClose.Enabled = False
            RS232 = Nothing
        End If
    End Sub

    Private Sub btnEnd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnd.Click
        If Not RS232 Is Nothing Then
            If RS232.IsOpen Then RS232.Close()
        End If
        End
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Dim bDataOut(0) As Byte
        Try
            bDataOut(0) = CType(Me.txtSend.Text, Byte)        '将类型转换为字节
            RS232.Write(bDataOut, 0, 1)
        Catch ex As Exception
            MessageBox.Show("输入数值错误:" + ex.ToString, "错误通知:", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Private Sub cmbCom_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCom.KeyPress
        e.KeyChar = ChrW(0)             '禁止用户在其中输入任何文字
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Hide()
        Form2.Show()
    End Sub
End Class
Form2.vb

  1. '**************************************************************  
  2. '时间:2008-11-08  
  3. '作者:lincyang  
  4. '实际应用中,串行通信的数据可能一次发送大量的数据,  
  5. '发送之前就必须将数据先编码,  
  6. '将其编成我们需要的字节数组数据,  
  7. '才能将这些数据以字节的方式发送出去  
  8. '目前操作系统使用的字符数据是Unicode:所有的字符均使用  
  9. '两个字节来表示一个字符  
  10. '**************************************************************  
  11.   
  12. Imports System.IO.Ports  
  13. Imports System.Text  
  14. Public Class Form2  
  15.     Dim RS232 As SerialPort  
  16.     Private Sub Form2_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load  
  17.         For Each sp As String In SerialPort.GetPortNames()  
  18.             cmbCom.Items.Add(sp)  
  19.         Next  
  20.         cmbCom.Sorted = True  
  21.         cmbCom.SelectedIndex = 0  
  22.     End Sub  
  23.   
  24.     Private Sub btnStart_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnStart.Click  
  25.         Dim mBaudRate As Integer  
  26.         Dim mParity As IO.Ports.Parity  
  27.         Dim mDataBit As Integer  
  28.         Dim mStopBit As IO.Ports.StopBits  
  29.         Dim mPortName As String  
  30.   
  31.         mPortName = cmbCom.SelectedItem.ToString  
  32.         mBaudRate = 9600  
  33.         mParity = Parity.None  
  34.         mDataBit = 8  
  35.         mStopBit = StopBits.One  
  36.   
  37.         RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopBit)  
  38.   
  39.         If Not RS232.IsOpen Then  
  40.             RS232.Open()  
  41.             btnSend.Enabled = True  
  42.             Timer1.Interval = 100  
  43.             Timer1.Enabled = True  
  44.         Else  
  45.             MsgBox("通讯端口打开错误!", MsgBoxStyle.Critical)  
  46.         End If  
  47.     End Sub  
  48.   
  49.     Private Sub Timer1_Tick(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Timer1.Tick  
  50.         Dim InByte() As Byte, ReadCount As Integer  
  51.         If RS232.BytesToRead <= 0 Then Exit Sub  
  52.         ReDim InByte(RS232.BytesToRead - 1)  
  53.         ReadCount = RS232.Read(InByte, 0, RS232.BytesToRead)  
  54.   
  55.         If ReadCount = 0 Then  
  56.             Exit Sub  
  57.         Else  
  58.             For Each bData As Byte In InByte  
  59.                 Me.txtReceive.Text += bData.ToString & vbCrLf     '若有数据则加到接收文本框  
  60.   
  61.             Next  
  62.         End If  
  63.     End Sub  
  64.   
  65.     Private Sub btnClose_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnClose.Click  
  66.         If RS232 Is Nothing OrElse Not RS232.IsOpen Then   '尚未打开  
  67.             MsgBox("通讯端口尚未打开", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel)  
  68.         Else  
  69.             RS232.Close()  
  70.             btnStart.Enabled = False  
  71.             btnClose.Enabled = False  
  72.             Timer1.Enabled = False  
  73.             RS232 = Nothing  
  74.         End If  
  75.     End Sub  
  76.   
  77.     Private Sub btnSend_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnSend.Click  
  78.         Dim bDataOut() As Byte, Buf As String  
  79.         Dim iSentCount As Integer  
  80.         Dim Encode1 As Encoding = Encoding.ASCII         '声明编码对象,使用ASCII  
  81.   
  82.         Try  
  83.             Buf = txtSend.Text.Trim()  
  84.             bDataOut = Encode1.GetBytes(Buf)      '将字符串转换为字节数组  
  85.             iSentCount = bDataOut.GetLength(0)     '发送总字节数  
  86.             '显示出总字节数  
  87.             lblSentCount.Text = "总传输量:" & iSentCount.ToString & "字节"  
  88.             RS232.Write(bDataOut, 0, iSentCount)  
  89.         Catch ex As Exception  
  90.             MessageBox.Show("输入数值错误:" + ex.ToString, "错误通知", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)  
  91.         End Try  
  92.     End Sub  
  93.   
  94.     Private Sub btnEnd_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles btnEnd.Click  
  95.         If Not RS232 Is Nothing Then  
  96.             If RS232.IsOpen Then RS232.Close()  
  97.         End If  
  98.         End  
  99.     End Sub  
  100.   
  101.     Private Sub cmbCom_KeyPress(ByVal sender As ObjectByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCom.KeyPress  
  102.         e.KeyChar = ChrW(0)             '禁止用户在其中输入任何文字  
  103.     End Sub  
  104. End Class  
'**************************************************************
'时间:2008-11-08
'作者:lincyang
'实际应用中,串行通信的数据可能一次发送大量的数据,
'发送之前就必须将数据先编码,
'将其编成我们需要的字节数组数据,
'才能将这些数据以字节的方式发送出去
'目前操作系统使用的字符数据是Unicode:所有的字符均使用
'两个字节来表示一个字符
'**************************************************************

Imports System.IO.Ports
Imports System.Text
Public Class Form2
    Dim RS232 As SerialPort
    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each sp As String In SerialPort.GetPortNames()
            cmbCom.Items.Add(sp)
        Next
        cmbCom.Sorted = True
        cmbCom.SelectedIndex = 0
    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        Dim mBaudRate As Integer
        Dim mParity As IO.Ports.Parity
        Dim mDataBit As Integer
        Dim mStopBit As IO.Ports.StopBits
        Dim mPortName As String

        mPortName = cmbCom.SelectedItem.ToString
        mBaudRate = 9600
        mParity = Parity.None
        mDataBit = 8
        mStopBit = StopBits.One

        RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopBit)

        If Not RS232.IsOpen Then
            RS232.Open()
            btnSend.Enabled = True
            Timer1.Interval = 100
            Timer1.Enabled = True
        Else
            MsgBox("通讯端口打开错误!", MsgBoxStyle.Critical)
        End If
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim InByte() As Byte, ReadCount As Integer
        If RS232.BytesToRead <= 0 Then Exit Sub
        ReDim InByte(RS232.BytesToRead - 1)
        ReadCount = RS232.Read(InByte, 0, RS232.BytesToRead)

        If ReadCount = 0 Then
            Exit Sub
        Else
            For Each bData As Byte In InByte
                Me.txtReceive.Text += bData.ToString & vbCrLf     '若有数据则加到接收文本框

            Next
        End If
    End Sub

    Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
        If RS232 Is Nothing OrElse Not RS232.IsOpen Then   '尚未打开
            MsgBox("通讯端口尚未打开", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel)
        Else
            RS232.Close()
            btnStart.Enabled = False
            btnClose.Enabled = False
            Timer1.Enabled = False
            RS232 = Nothing
        End If
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Dim bDataOut() As Byte, Buf As String
        Dim iSentCount As Integer
        Dim Encode1 As Encoding = Encoding.ASCII         '声明编码对象,使用ASCII

        Try
            Buf = txtSend.Text.Trim()
            bDataOut = Encode1.GetBytes(Buf)      '将字符串转换为字节数组
            iSentCount = bDataOut.GetLength(0)     '发送总字节数
            '显示出总字节数
            lblSentCount.Text = "总传输量:" & iSentCount.ToString & "字节"
            RS232.Write(bDataOut, 0, iSentCount)
        Catch ex As Exception
            MessageBox.Show("输入数值错误:" + ex.ToString, "错误通知", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Private Sub btnEnd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnd.Click
        If Not RS232 Is Nothing Then
            If RS232.IsOpen Then RS232.Close()
        End If
        End
    End Sub

    Private Sub cmbCom_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCom.KeyPress
        e.KeyChar = ChrW(0)             '禁止用户在其中输入任何文字
    End Sub
End Class


一不小心看到一高手写的C#串中操作系列的文章,很不错,可惜我辈不懂C#,于是顺便改成用VB.NET2010

\加载中...

其中几乎都有注解。

顺便说明,再发送16进制不是很完善,有懂的兄弟,说明一下

001. Imports System
002. Imports System.Collections.Generic
003. Imports System.ComponentModel
004. Imports System.Data
005. Imports System.Drawing
006. Imports System.Linq
007. Imports System.Text
008. Imports System.IO.Ports
009. Imports System.Text.RegularExpressions
010.  
011.  
012. Public Class Form1
013.  
014.     WithEvents Comm As SerialPort = New SerialPort
015.     Private Builder As StringBuilder = New StringBuilder '避免在事件处理方法中反复的创建,所以定义到外面
016.     Private ReceiveCount As Long = 0     '接收计数
017.     Private SendCount As Long = 0        '发送计数
018.  
019.     Private Listening As Boolean = False  '是否没有执行完invoke相关操作
020.     Private Closingg As Boolean = False     '是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke  
021.  
022.     Public Delegate Sub UpdateData(ByVal mByte() As Byte)
023.  
024.     Public Sub ShowData(ByVal mByte() As Byte)
025.         Console.WriteLine(mByte)
026.         ReceiveCount += mByte.Length
027.         Builder.Clear()
028.  
029.         If CheckBoxHex.Checked Then
030.             For Each b As Byte In mByte
031.                 Builder.Append(b.ToString("X2") + " ")
032.             Next
033.  
034.         Else
035.  
036.             Builder.Append(Encoding.ASCII.GetString(mByte))
037.  
038.         End If
039.         TxtGet.AppendText(Builder.ToString)
040.         labelGetCount.Text = "Get:" + ReceiveCount.ToString
041.     End Sub
042.  
043.     Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
044.  
045.         '初始化下拉串口名称列表框
046.         Dim Ports() As String = SerialPort.GetPortNames
047.         Array.Sort(Ports)
048.         ComboPortName.Items.AddRange(Ports)
049.         ComboPortName.SelectedIndex = IIf(ComboPortName.Items.Count > 0, 0, -1)
050.         ComboBaudrate.SelectedIndex = ComboBaudrate.Items.IndexOf("9600")
051.         '初始化Serialport对象
052.         Comm.NewLine = vbCrLf
053.         Comm.RtsEnable = True
054.  
055.         'AddHandler Obj.Ev_Event, AddressOf EventHandler
056.         'RemoveHandler Obj.Ev_Event, AddressOf EventHandler
057.         'AddHandler Comm.DataReceived, AddressOf Comm_DataReceived
058.  
059.     End Sub
060.  
061.     Private Sub Comm_DataReceived(sender As Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles Comm.DataReceived
062.         If Closingg Then Return '如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环  
063.  
064.         Try
065.             Listening = True                    '设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。
066.             Dim n As Long = Comm.BytesToRead    '先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致  
067.             Dim Buf(n - 1) As Byte              '声明一个临时数组存储当前来的串口数据
068.  
069.             Comm.Read(Buf, 0, n)                '读取缓冲数据
070.             Builder.Clear()                     '清除字符串构造器的内容
071.  
072.             Dim b As UpdateData = New UpdateData(AddressOf ShowData)
073.             Me.BeginInvoke(b, Buf)
074.  
075.         Catch ex As Exception
076.             Err.Clear()
077.         Finally
078.             Listening = False                    '我用完了,ui可以关闭串口了。
079.         End Try
080.     End Sub
081.  
082.     Private Sub ShowMsg(ByVal buffer() As Byte)
083.         If CheckBoxHex.Checked Then
084.             For Each b As Byte In Buffer
085.                 Builder.Append(b.ToString("X2") + " ")
086.             Next
087.         Else
088.             Builder.Append(Encoding.ASCII.GetString(buffer))
089.         End If
090.         Me.TxtGet.AppendText(Builder.ToString())
091.         labelGetCount.Text = "Get:" + ReceiveCount.ToString
092.     End Sub
093.  
094.     Private Sub BtnXOpen_Click(sender As System.Object, e As System.EventArgs) Handles BtnXOpen.Click
095.         '根据当前串口对象,来判断操作
096.         If Comm.IsOpen Then
097.             Closingg = True '
098.             While Listening
099.                 Application.DoEvents()
100.             End While
101.             '打开时点击,则关闭串口
102.             Comm.Close()
103.             Closingg = False
104.         Else
105.             Comm.PortName = ComboPortName.Text
106.             Comm.BaudRate = Integer.Parse(ComboBaudrate.Text)
107.             Try
108.                 Comm.Open()
109.             Catch ex As Exception
110.                 '捕获到异常信息,创建一个新的comm对象,之前的不能用了。
111.                 Comm = New SerialPort
112.                 '现实异常信息给客户。
113.                 MessageBox.Show(ex.Message)
114.             End Try
115.         End If
116.  
117.         '设置按钮的状态  
118.         BtnXOpen.Text = IIf(Comm.IsOpen, "Close", "Open")
119.         BtnXOpen.Enabled = Comm.IsOpen
120.  
121.     End Sub
122.  
123.     '动态的修改获取文本框是否支持自动换行。
124.     Private Sub CheckBoxNewLineGet_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles CheckBoxNewLineGet.CheckedChanged
125.         TxtGet.WordWrap = CheckBoxNewLineGet.Checked
126.     End Sub
127.  
128.     Private Sub BtnXSend_Click(sender As System.Object, e As System.EventArgs) Handles BtnXSend.Click
129.         Dim n As Integer = 0  '定义一个变量,记录发送了几个字节
130.         If checkBoxHexSend.Checked Then   '16进制发送
131.             '我们不管规则了。如果写错了一些,我们允许的,只用正则得到有效的十六进制数  
132.             Dim Mc As MatchCollection = Regex.Matches(TxtSend.Text.Trim, "(?i)[/da-f]{2}")   '"(?i)[/da-f]{2}"
133.             Dim buf As List(Of Byte) = New List(Of Byte)
134.  
135.             '依次添加到列表中  
136.             For Each m As Match In Mc
137.                 '  buf.Add(Byte.Parse(m.Value))
138.                 buf.Add(Byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber))
139.             Next
140.  
141.             '转换列表为数组后发送 
142.             Comm.Write(buf.ToArray, 0, buf.Count)
143.             n = buf.Count
144.         Else                             'ascii编码直接发送
145.             '包含换行符
146.             If checkBoxNewlineSend.Checked Then
147.                 Comm.WriteLine(TxtSend.Text)
148.                 n = TxtSend.Text.Length + 2
149.             Else
150.                 Comm.Write(TxtSend.Text)
151.                 n = TxtSend.Text.Length
152.             End If
153.         End If
154.  
155.         SendCount += n    '累加发送字节数
156.         labelSendCount.Text = "Send:" + SendCount.ToString
157.     End Sub
158.  
159.     Private Sub BtnXReset_Click(sender As System.Object, e As System.EventArgs) Handles BtnXReset.Click
160.  
161.         '复位接受和发送的字节数计数器并更新界面。
162.         SendCount = 0
163.         ReceiveCount = 0
164.         labelGetCount.Text = "Get:0"
165.         labelSendCount.Text = "Send:0"
166.         Builder.Clear()
167.  
168.     End Sub
169.  
170.     Private Sub BtxClear_Click(sender As System.Object, e As System.EventArgs) Handles BtxClear.Click
171.         TxtGet.Text = ""
172.         Builder.Clear()
173.     End Sub
174. End Class


参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值