关于#c的问题:使用串口收数据,可能因为分包时候对bufstr的操作吗(操作系统-windows)

使用串口收数据,接收端是这样写的,但是会丢帧,可能因为分包时候对bufstr的操作吗,怎么更好的写可以不丢包

                int count = Serial.Port.BytesToRead;
                byte[] buffer = new byte[count];
                Serial.Port.Read(buffer, 0, count);
                bufstr = bufstr + Encoding.ASCII.GetString(buffer);
                Console.WriteLine(bufstr);
                int i = bufstr.IndexOf("\r\n");
                while (i != -1)//粘连分包
                {
                    GetMessage(1, new string(bufstr.Take(i).ToArray()), null);//数据处理及显示
                    bufstr = new string(bufstr.Skip(i + 2).ToArray());
                    i = bufstr.IndexOf("\r\n");
                }

维护一个全局变量list
接收到之后先add进list里,然后判断list里有没有换行符,有就从头到尾的执行,并把处理过的数据remove掉
你目前的代码,必须一次性接收到完整的数据,分两次来的时候会全部丢弃


你的代码中存在粘连分包的问题,这可能是导致丢帧的原因之一。在串口通信中,由于数据的传输速率和处理速度不一致,可能会出现粘连分包的情况,即多个数据包被粘合在一起,导致数据解析错误。因此,你需要在代码中处理这个问题,以避免丢帧。

在你的代码中,你使用了一个字符串变量 bufstr 来存储接收到的数据。每次读取到数据后,你都将其转换为字符串并追加到 bufstr 变量后面。然后,你使用一个循环来查找 bufstr 中的数据包,并调用 GetMessage 方法进行处理。

这里的问题在于,如果接收到的数据包仅包含部分数据,那么你可能会错过这个数据包,从而导致丢帧。比如,如果接收到的数据为 "hello\r\nworld\r\n",那么第一个数据包是 "hello\r\n",第二个数据包是 "world\r\n",但是如果你在读取数据时只读取了 "hello\r\n" 这个数据包的一部分,那么就会导致第二个数据包的解析错误。

因此,你需要修改代码来解决粘连分包的问题。一种常见的解决方法是使用一个缓冲区来存储接收到的数据,并在缓冲区中查找数据包。具体来说,你可以将接收到的数据追加到缓冲区中,然后查找缓冲区中的数据包,直到所有的数据包都被处理完毕。

下面是修改后的代码示例:

reasonml
Copy
byte[] buffer = new byte[Serial.Port.BytesToRead];
Serial.Port.Read(buffer, 0, buffer.Length);
bufferList.AddRange(buffer); // 将接收到的数据追加到缓冲区中

while (true)
{
    int index = bufferList.IndexOf("\r\n"); // 查找缓冲区中的数据包
    if (index == -1) break; // 如果没有找到数据包,跳出循环

    string message = Encoding.ASCII.GetString(bufferList.ToArray(), 0, index);
    bufferList.RemoveRange(0, index + 2); // 从缓冲区中移除已经处理过的数据包

    GetMessage(1, message, null); // 处理数据包
}
在这个代码中,我们使用一个 List<byte> 类型的变量 bufferList 来存储接收到的数据。每次读取到数据后,我们将其追加到 bufferList 变量后面。然后,在一个循环中不断查找 bufferList 中的数据包,并调用 GetMessage 方法进行处理。在查找数据包时,我们使用 IndexOf 方法查找 "\r\n" 字符串,并返回其在缓冲区中的位置。如果找到了数据包,我们就调用 GetString 方法将数据包转换为字符串,并调用 RemoveRange 方法从缓冲区中移除已经处理过的数据包。注意,在调用 GetString 方法时,我们需要指定要转换的字节数和起始位置。

这样,你就可以避免粘连分包的问题,并可以更好地处理串口通信中的数据。

回答整理自chatgpt,如果有帮助麻烦采纳一下,谢谢啦!


private StringBuilder bufstr = new StringBuilder();

private void SerialDataReceivedEventHandler(object sender, SerialDataReceivedEventArgs e)
{
    int count = Serial.Port.BytesToRead;
    byte[] buffer = new byte[count];
    Serial.Port.Read(buffer, 0, count);
    string data = Encoding.ASCII.GetString(buffer);
    
    bufstr.Append(data);
    ProcessReceivedData();
}

private void ProcessReceivedData()
{
    string data = bufstr.ToString();
    int i = data.IndexOf("\r\n");
    while (i != -1)
    {
        string message = data.Substring(0, i);
        GetMessage(1, message, null);
        
        data = data.Substring(i + 2);
        i = data.IndexOf("\r\n");
    }
    
    bufstr.Clear();
    bufstr.Append(data);
}