【问题标题】:C# Serialport not receiving all the bytes in a single transmissionC# Serialport 在一次传输中未接收到所有字节
【发布时间】:2016-04-27 18:10:17
【问题描述】:

我正在使用以下代码通过串行端口接收十六进制数据,当它们是同一传输的一部分时,似乎其中一些传输被分成两行。如何确保正确接收每个传输?

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
} 

【问题讨论】:

    标签: c# serial-port


    【解决方案1】:

    您永远不应该假设串行端口的数据是一次性提供给您的(顺便说一下,网络通信也是如此)。您需要确保您的代码仅在您收到所有内容后才接受消息。

    一切都很难定义。这可以是所有字符,直到定义的终止序列(例如\r\nEOL 字节)或直到读取固定数量的字节。一般来说,可以说,由于每条消息都可能被分割,如果没有定义的消息结束信号,可靠的通信是不可能的。

    我们做的是:

    1. 创建StringBuilder
    2. 将所有内容读入StringBuilder
    3. 搜索终止序列
    4. 删除从 StringBuilder 直到并包括终止序列的所有内容
    5. 处理该数据块
    6. 从 3 开始重复,直到找不到终止序列
    7. 保留StringBuilder 中的剩余字符,因为这是新消息的开始

    伪代码:

    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 依次触发的事件。

    【讨论】:

    • vb.net中的terminationSequence等价物是什么?
    • 终止序列是什么意思?
    • 我的意思是定义的字节序列,它不是任何消息的一部分,因此可以让您确定消息是否完整。当你遇到那个(序列)字节时,消息就结束了。
    • @adib 在上面的代码中,终止序列只是一个字符串。我将更改我的答案以使其更清楚。
    • 如果可能的话,你能回答这个问题吗? stackoverflow.com/questions/36868157/…
    【解决方案2】:

    我也遇到过差不多的情况。

    就像 Thorsten 所说的那样,数据有时不会立即出现。 可能是因为硬件或波特率..

    真正适合我的是:

            var end = '\r';
            int dataLength = _serialPort.BytesToRead;
            byte[] data = new byte[dataLength];
            int nbrDataRead = _serialPort.Read(data, 0, dataLength);
    
            RxString = Encoding.ASCII.GetString(data);
            txtCod.AppendText(RxString);
    
            if (RxString.IndexOf((char)end) > -1)
            {
                this.Invoke(new EventHandler(Final));   
            } 
    

    【讨论】:

    • 在 vb.net 中相当于什么?
    • 尚未测试,但我相信像这样。 Dim [end] = ControlChars.Cr Dim dataLength As Integer = _serialPort.BytesToRead Dim data As Byte() = New Byte(dataLength - 1) {} Dim nbrDataRead As Integer = _serialPort.Read(data, 0, dataLength) RxString = Encoding.ASCII.GetString(data) txtCod.AppendText(RxString) If RxString.IndexOf(CChar([end])) > -1 Then Me.Invoke(New EventHandler(Final)) End If
    • 你能帮我把这部分转换成dotnet吗? if (RxString.IndexOf((char)end) > -1) { this.Invoke(new EventHandler(Final)); }
    • @Adib 类似这样的东西,If RxString.IndexOf(CChar([end])) > -1 Then Me.Invoke(New EventHandler(Final)) End If
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多