如何将串口通信读入缓冲区并解析出完整的消息 [英] How to read serial port communication into buffer and parse out complete messages
问题描述
我正在使用以下代码从 com 端口读取值:
I am using the following code to read values from a com port:
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
这工作得很好,但它时不时地获取所有数据,并且返回结果是两个字符串而不是一个.
This works just fine, but every now and then it doesnt get all the data and in return results in two strings instead of just one.
一个例子是,如果 com 端口通过HELLO2YOU"这个词发送,它看起来像:
An example would be if the com port was sending over the word "HELLO2YOU" it was look like:
HEL
LO2YOU
或
HELLO2
YOU
如何在其中放置缓冲区以确保在显示之前读取了所有数据?
How can i place a buffer in there so that it makes sure it has all the data read before displaying it?
谢谢!
推荐答案
您必须将串行端口通信视为流数据.任何时候您接收数据时,您都必须预料到它可能是一条完整的消息、只是部分消息或多条消息.这完全取决于数据传入的速度以及您的应用程序能够从队列中读取的速度.因此,您认为需要缓冲区是正确的.但是,您可能还没有意识到,严格通过串行端口,无法知道每条消息的开始和结束位置.这必须通过发送方和接收方之间商定的协议来处理.例如,许多人使用标准的文本开始 (STX) 和文本结束 (ETX) 字符来表示每条消息发送的开始和结束.这样,当您收到数据时,您就可以知道何时收到了完整的消息.
You have to think of Serial Port communications as streaming data. Any time you receive data, you have to expect that it may be a complete message, only a partial message, or multiple messages. It all depends how fast the data is coming in and how fast you application is able to read from the queue. Therefore, you are right in thinking you need a buffer. However, what you may not be realizing yet, is that there is no way to know, strictly via, the Serial Port, where each message begins and ends. That has to be handled via some agreed upon protocol between the sender and the receiver. For instance, many people use the standard start-of-text (STX) and end-of-text (ETX) characters to indicate the beginning and ending of each message send. That way, when you receive the data, you can tell when you have received a complete message.
例如,如果您使用 STX 和 ETX 字符,您可以创建这样的类:
For instance, if you used STX and ETX characters, you could make a class like this:
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
我还应该提到,在通信协议中,通常有一个校验和字节,您可以通过它来确定消息在发送方和接收方之间的传输过程中是否被破坏.
I should also mention that, in communication protocols, it is typical to have a checksum byte by which you can determine if the message got corrupted during its transmission between the sender and the receiver.
这篇关于如何将串口通信读入缓冲区并解析出完整的消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!