代码之家  ›  专栏  ›  技术社区  ›  samtal

串行数据流:如何确保完成

  •  0
  • samtal  · 技术社区  · 10 年前

    我有一个设备,可以通过USB到COM端口以不同的速度和长度向我的程序发送串行数据。

    在数据中有一个数千字节的块,以特殊的不同代码开始和结束(“FDDD”表示开始,“FEEE”表示结束)。 由于流的长度,有时并非所有数据都在一段中接收。 在解析消息之前,建议将所有字节合并为一条消息的方法是什么? (我注意了缓冲区的大小,但无法控制串行线的质量,也无法使用USB的硬件控制)

    谢谢

    2 回复  |  直到 10 年前
        1
  •  0
  •   DrV    10 年前

    实现这一点的一种可能方式是按照以下几点进行:

    # variables
    #   buffer: byte buffer
    #   buffer_length: maximum number of bytes in the buffer
    #   new_char: char last read from the UART
    #   prev_char: second last char read from the UART
    #   n: index to the buffer
    
    new_char := 0
    loop forever:
        prev_char := new_char
        new_char := receive_from_uart()
    
        # start marker
        if prev_char = 0xfd and new_char = 0xdd
            # set the index to the beginning of the buffer
            n := 0
        # end marker
        else if prev_char = 0xfe and new_char = 0xee
            # the frame is ready, do whatever you need to do with a complete message
            # the length of the payload is n-1 bytes
            handle_complete_message(buffer, n-1)
        # otherwise
        else
           if n < buffer_length - 1
               n := n + 1
               buffer[n] := new_char
    

    一些提示/评论:

    • 您不一定需要单独的开始标记和结束标记(您可以同时使用这两个标记)
    • 如果您希望有两个字节标记,那么使用相同的第一个字节标记会更容易
    • 您需要确保数据流中没有出现标记组合
    • 如果您使用转义码来避免有效载荷中的标记,则可以在同一代码中处理它们
    • 参见HDLC异步帧(简单编码,简单解码,注意转义)
    • handle_complete_message 通常复制 buffer 或交换另一个缓冲区,而不是 缓冲器 如果赶时间
    • 如果数据帧没有完整性检查,则应检查有效负载长度是否等于 buffer_length -1,因为这样可能会溢出
        2
  •  0
  •   samtal    10 年前

    经过几次测试,我对自己的问题(针对c#)提出了以下简单的解决方案。 图中显示了一个最小的简化解决方案。可以添加长度检查等。 “Start”和“End”是任意长度的字符串标记。

        public void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    
        SerialPort port = (SerialPort)sender;
    
        inData = port.ReadExisting();
        {
        if (inData.Contains("start"))
               {
              //Loop to collect all message parts   
              while (!inData.Contains("end"))
                 inData += port.ReadExisting();  
              //Complete by adding the last data chunk
               inData += port.ReadExisting();
               }                    
              //Use your collected message  
              diaplaydata(inData);
    
    推荐文章