在SerialPort vb.net中读取字节值26

时间:2016-04-05 10:28:26

标签: vb.net

我有一个vb.net winforms应用程序,可以读取/写入连接到USB-RS485设备的多个设备的串行数据。该应用程序是用Visual Basic .NET 2008编写的,尽管我也尝试过.NET 2015。

几乎一切都运行良好,除非其中一个设备发送一个字节值为26的消息。然后我不确定究竟发生了什么但是在字节值26之后,读数似乎停止了。之后的所有数据都会在下一个DataReceived事件中读取。

我做了一个简短的程序来测试serialport。它显示完全相同。此外,我只有一个设备连接测试。 设备发送的数据由10个字节组成。值为251,20,(6个数据字节),校验和,校验和。

前两个和后两个字节永远不会达到26的值,它只是可以做到的数据字节。

进口:

Imports System.IO.Ports
Imports System.Text

变量:

Dim WithEvents SP_TestCom As SerialPort
Public DataArray() As Byte

潜艇:

Public Sub OpenCom()
    If SP_TestCom.IsOpen Then
        Exit Sub
    End If
    SP_TestCom.Open()
End Sub

Public Sub CloseCom()
    If Not SP_TestCom.IsOpen Then
        Exit Sub
    End If
    SP_TestCom.Close()
End Sub

Public Sub SendData(ByVal Data() As Byte)
    Try
        If SP_TestCom.IsOpen Then
            SP_TestCom.Write(Data, 0, Data.Length)
        End If
    Catch ex As Exception

    End Try
End Sub


Private Sub SP_TestCom_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SP_TestCom.DataReceived
    Try
        If SP_TestCom.BytesToRead > 0 Then
            Dim DataArray_Temp(SP_TestCom.BytesToRead + 1) As Byte
            SP_TestCom.Read(DataArray_Temp, 0, SP_TestCom.BytesToRead)

            Array.Copy(DataArray_Temp, DataArray, DataArray_Temp.Length)
        End If
    Catch ex As Exception

    End Try
End Sub

我有一个带有两个按钮和一个计时器的主表单。按钮用于打开和关闭端口。计时器读取数据表

我尝试了几种阅读方法。

  • 直接读入数组
  • 单独阅读每个字节
  • 读入字符串然后将其转换为字节数组

我也尝试了不同的编码。虽然我不确定它是否会产生任何影响。

  • ASCII
  • UNICODE
  • UTF

All给出了同样的错误。

我可以通过忽略包含字节值26的任何消息来绕过错误。这至少不会在我的应用程序的其余部分给出奇怪的结果,但它不是完美的解决方案。

有没有人知道问题可能是什么?

编辑:

Public Sub InitSerial()
    SP_TestCom = New SerialPort
    SP_TestCom.PortName = "COM26"
    SP_TestCom.ReadTimeout = 20
    SP_TestCom.BaudRate = 19200
    SP_TestCom.DataBits = 8
    SP_TestCom.StopBits = StopBits.One
    SP_TestCom.Parity = Parity.None
    SP_TestCom.ReceivedBytesThreshold = 10
End Sub

1 个答案:

答案 0 :(得分:4)

   SP_TestCom.ReceivedBytesThreshold = 10

这是一个相当麻烦的财产。是的,26是一个神奇的数字。它是Ctrl + Z,默认的文件结束字符。日期回到石器时代,不幸的是它无法改变。

对于您的DataReceived事件处理程序而言,它会激发一个额外的时间来告诉您有关Eof的信息。这搞砸了你的逻辑,BytesToRead的价值是不可预测的。你必须快速离开,像这样:

Private Sub SP_TestCom_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SP_TestCom.DataReceived
    If e.EventType <> SerialData.Chars Then Return
    '' etc...
End Sub

不是该属性的唯一问题。您现在可以保证ReceivedBytes 至少 10.确保您实际将10传递给Read()方法。但是你不知道你会得到哪10个。例如,它可以是前一个数据包的4个字节和下一个数据包的6个字节。除非你非常小心地控制启动顺序,否则这样做不会很好。在程序启动后,必须打开设备,这样您才能确保收到的第一个字节是数据包的第一个字节。如果必须向设备发送显式命令以开始发送,则可以正常工作。

或者您可能需要通过特殊字节值检测数据包的开头,例如251。然后通过读取单个字节进行同步,将其丢弃,直到获得251.您不能使用ReceivedBytesThreshold&gt;来执行此操作。 1。

使用ErrorReceived事件也非常非常重要。发生溢出错误,尤其是在没有握手时,必须在发生错误时重新进行同步。

您还需要注意处理数据包的方式。如果你不能在DataReceived事件处理程序中这样做,那么你需要一个线程安全的队列来确保没有数据丢失。