vb.net - 如何将串口通信读入缓冲区并解析出完整的消息

标签 vb.net serial-port

我正在使用以下代码从 com 端口读取值:

Private port As New SerialPort("COM13", 9600, Parity.None, 8, StopBits.One)

Private Sub port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
    Debug.Print(port.ReadExisting())
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    AddHandler port.DataReceived, New SerialDataReceivedEventHandler(AddressOf port_DataReceived)
    port.Open()
End Sub

这工作得很好,但时不时地它不会获取所有数据,并且返回结果是两个字符串而不是一个。

一个例子是,如果 com 端口通过单词“HELLO2YOU”发送它看起来像:
HEL
LO2YOU

或者
HELLO2
YOU

我如何在其中放置一个缓冲区,以确保在显示之前读取所有数据?

谢谢!

最佳答案

您必须将串行端口通信视为流数据。每当您收到数据时,您都必须期望它可能是完整的消息、仅是部分消息或多条消息。这完全取决于数据进入的速度以及应用程序能够从队列中读取的速度。因此,您认为需要缓冲区是正确的。但是,您可能还没有意识到,严格来说,无法通过串行端口知道每条消息的开始和结束位置。这必须通过发送方和接收方之间商定的协议(protocol)来处理。例如,许多人使用标准的文本开始 (STX) 和文本结束 (ETX) 字符来指示每条消息发送的开始和结束。这样,当您收到数据时,您就可以知道您何时收到了完整的消息。

例如,如果你使用 STX 和 ETX 字符,你可以创建一个这样的类:

Public Class DataBuffer
    Private ReadOnly _startOfText As String = ASCII.GetChars(New Byte() {2})
    Private ReadOnly _endOfText As String = ASCII.GetChars(New Byte() {4})

    Public Event MessageReceived(ByVal message As String)
    Public Event DataIgnored(ByVal text As String)

    Private _buffer As StringBuilder = New StringBuilder

    Public Sub AppendText(ByVal text As String)
        _buffer.Append(text)
        While processBuffer(_buffer)
        End While
    End Sub

    Private Function processBuffer(ByVal buffer As StringBuilder) As Boolean
        Dim foundSomethingToProcess As Boolean = False
        Dim current As String = buffer.ToString()
        Dim stxPosition As Integer = current.IndexOf(_startOfText)
        Dim etxPosition As Integer = current.IndexOf(_endOfText)
        If (stxPosition >= 0) And (etxPosition >= 0) And (etxPosition > stxPosition) Then
            Dim messageText As String = current.Substring(0, etxPosition + 1)
            buffer.Remove(0, messageText.Length)
            If stxPosition > 0 Then
                RaiseEvent DataIgnored(messageText.Substring(0, stxPosition))
                messageText = messageText.Substring(stxPosition)
            End If
            RaiseEvent MessageReceived(messageText)
            foundSomethingToProcess = True
        ElseIf (stxPosition = -1) And (current.Length <> 0) Then
            buffer.Remove(0, current.Length)
            RaiseEvent DataIgnored(current)
            foundSomethingToProcess = True
        End If
        Return foundSomethingToProcess
    End Function


    Public Sub Flush()
        If _buffer.Length <> 0 Then
            RaiseEvent DataIgnored(_buffer.ToString())
        End If
    End Sub
End Class

我还应该提到,在通信协议(protocol)中,通常有一个校验和字节,您可以通过该字节确定消息在发送方和接收方之间的传输过程中是否损坏。

关于vb.net - 如何将串口通信读入缓冲区并解析出完整的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11458850/

相关文章:

asp.net - 在javascript中获取列表框的选定项目

javascript - latlng函数参数

Python + Arduino 与 Mac OS X

java - 从 Java 中的 COM 端口读取,错误 0x5 位于 ..\rxtx\src\termios.c(892)

c# - 如何在 c sharp 中的单个 com 端口同时接收多个任务

.net - 如何将 Queue(Of String) 作为字符串连接?

mysql - VB NET - 查询 Mysql - 在哪里\

c# - 调整图像大小以适合打印页面的问题

c# - C#中的串口通信参数不正确

c++ - 使用QSerialPort将带有引号的内容写入串行设备