问题描述
我正在使用以下代码通过串行端口接收十六进制数据,似乎其中一些传输是同一传输的一部分时被分成 2 行.如何确保正确接收每个传输?
I'm using the following code to receive hex data over the serial port, it seems that some of these transmissions are broken up into 2 lines when they are parts of the same transmission. How do I make sure that each transmission is received properly?
public void Receiver(object sender, SerialDataReceivedEventArgs e)
{
string data;
do
{
data = COMPort.ReadExisting();
} while (COMPort.BytesToRead != 0);
RxARR = data.ToCharArray().ToList();
Dispatcher.Invoke(new MethodInvoker(Display)); // Start "Display" on the UI thread
}
推荐答案
你永远不应该假设串行端口的数据是一次性提供给你的(顺便说一下,网络通信也是如此).您需要确保您的代码仅在您收到所有信息后才接受消息.
You should never assume that data from a serial port is provided to you in one go (the same is true for network communication by the way). You need to make sure that your code accepts a message only if you have received everything.
一切都很难定义.这可以是所有字符,直到定义的终止序列(例如 \r\n
或 EOL
字节)或直到读取固定数量的字节.一般可以说,由于每条消息都可能被分割,如果没有定义的消息结束信号,可靠的通信是不可能的.
Everything is hard to define. This can either be all characters until a defined termination sequence (for example \r\n
or EOL
byte) or until a fixed number of bytes is read. Generally one can say, as every message can be fragmented, reliable communcation is not possible without a defined end of message signal.
我们所做的是:
- 创建一个
StringBuilder
- 将所有内容读入
StringBuilder
- 搜索终止序列
- 删除从
StringBuilder
到并包括终止序列的所有内容 - 处理那块数据
- 从 3 开始重复直到找不到终止序列
- 保留
StringBuilder
中剩余的字符,因为这是新消息的开始
- Create a
StringBuilder
- Read everything into that
StringBuilder
- Search for termination sequence
- Remove everything from the
StringBuilder
up to and including the termination sequence - Process that chunk of data
- Repeat from 3 until termination sequence is not found
- Keep the remaining characters in
StringBuilder
, as this is the start of a new message
伪代码:
private StringBuilder serialBuffer = new StringBuilder();
private string terminationSequence = "\r\n"; // Anything that can't be part of a message
public void Receiver(object sender, SerialDataReceivedEventArgs e)
{
string data = COMPort.ReadExisting();
serialBuffer.Append(data);
string bufferString = serialBuffer.ToString();
int index = -1;
do
{
index = bufferString.IndexOf(terminationSequence);
if (index > -1)
{
string message = bufferString.Substring(0, index);
bufferString = bufferString.Remove(0, index + terminationSequence.Length);
HandleMessage(message);
}
}
while (index > -1)
serialBuffer = new StringBuilder(bufferString);
}
顺便说一下:不需要在 DataReceived
事件中循环,因为每当有新的东西准备好读取时,SerialPort
就会调用这个事件.默认情况下,循环读取可能会干扰 SerialPort
正在执行的操作.所以:不要在该事件中循环阅读!循环"是由 SerialPort
依次触发的事件.
By the way: Looping within your DataReceived
event is not desired, as this event is called by the SerialPort
whenever something new is ready to be read. Reading in a loop may interfere with what SerialPort
is doing by default. So: Don't read in a loop within that event! The "loop" is the event being fired in sequence by SerialPort
.
这篇关于C# Serialport 没有在单次传输中接收所有字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!