Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
串口数据丢失-C#_C#_Serial Port - Fatal编程技术网

串口数据丢失-C#

串口数据丢失-C#,c#,serial-port,C#,Serial Port,我正在开发一个SerialPort应用程序,其中一个非常简单的部分就是给我带来问题。我只想从端口读取一个恒定的数据流,并在它进入时将其写入一个二进制文件。问题似乎在于速度:我的代码在9600波特的测试设备上运行良好,但在115200bps的实时设备上运行时,我似乎正在丢失数据。发生的事情是在一段可变的时间之后,我丢失了1个字节,这会丢弃其余的数据。我试过几件事: private void serialPort1_DataReceived(object sender, SerialDataRece

我正在开发一个SerialPort应用程序,其中一个非常简单的部分就是给我带来问题。我只想从端口读取一个恒定的数据流,并在它进入时将其写入一个二进制文件。问题似乎在于速度:我的代码在9600波特的测试设备上运行良好,但在115200bps的实时设备上运行时,我似乎正在丢失数据。发生的事情是在一段可变的时间之后,我丢失了1个字节,这会丢弃其余的数据。我试过几件事:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    bwLogger.Write((byte)serialPort1.ReadByte());
}

还有一些变化。我不能使用ReadLine(),因为我正在处理一个恒定的数据流(对吗?)。我尝试过调整缓冲区大小(serialPort1.ReadBufferSize和硬件FIFO缓冲区)。理想情况下,出于可用性的目的,我会在软件方面处理这个问题,而不是让用户必须更改Windows驱动程序设置


有什么想法吗?

我最近使用的机器都会发送一个停止码(在我的例子中是ASCII码3或4)。如果您还具有此功能,则可以从SerialPort对象中使用
ReadTo(string)

我会尝试以下方法:

  • 将缓冲区大小设置为至少230K字节
  • 将传入阈值设置为16K、32K或65K
  • 将此固定数据块写入文件
我不确定这是否有帮助,但它至少应该承受框架的压力,经常触发事件

  • 我将检查read(Byte>[],Int32,Int32)方法返回的读取字节数,并确保它与您期望的匹配

  • 确保正在侦听端口对象上的SerialErrorReceiveDevenHandler ErrorReceived事件。RXOver错误将表明缓冲区已满

  • 检查输出缓冲区上的线程安全性。如果对输出缓冲区的写入不是线程安全的,则第二次写入可能会损坏第一次写入


  • 您可以尝试使用SerialPort对象的Handshake属性启用握手


    您必须在发送方或接收方上设置它。但是:如果您溢出了接收器的UART缓冲区(非常小,16字节IIRC),那么可能没有其他方法。如果无法在发送方上启用握手,则可能必须保持在9600或以下。

    您的bwLogger是BinaryWriter类吗?您可以尝试将其与一起使用,以使磁盘I/O无阻塞


    另外,如果您的数据包有一个已知的结束字符,您可以设置该属性,使您能够使用ReadLine/WriteLine,尽管我认为这不会对性能造成太大的影响。

    如果问题似乎是您处理数据的速度不够快,您可以尝试将数据加倍缓冲

    1) 允许一个线程将串行端口读入一个缓冲区。这可能涉及将数据从端口复制到缓冲区(我对.NET不是很熟悉)

    2) 当您准备好处理传入的数据时,(在不同的线程上),使您的程序读入第二个缓冲区,当这发生时,您应该将第一个缓冲区写入磁盘


    3) 当第一个缓冲区写入磁盘时,将其交换回串行端口缓冲区,然后将第二个缓冲区写入磁盘。重复这个过程,不断交换缓冲区。

    这就是为什么通信协议有规则和校验和。您应该根据协议进行编码,该协议使您能够灵活地检测此类事件并从中恢复。您可以使用超时清除缓冲区,并根据需要重新发送。您将不时丢失数据。时期故事结束了。您需要让每个终端设备优雅地从这种情况中恢复(即不“丢弃”其余数据)。这是一个很好的建议。由于我的特定设备的独特功能,我能够线性插值数据,以填充任何丢失或其他“坏”数据包。在大多数通信情况下,正如您所提到的,通过针对适当的协议开发,这种类型事件的处理肯定会更加健壮。对任何从事任何沟通工作的人都有很好的建议。我很抱歉。在重读之后,我了解到您指的是硬实时需求,缺少一个意味着缺少一块永远不会回来的数据。请参阅我即将给出的关于线程的答案。即使你已经接受了一个答案,它也可能值得研究。它似乎对这个问题没有帮助,尽管从逻辑上说我认为它会。无论如何,这是一个很好的建议,它似乎必须减少我的内存使用,因为引发的事件较少。谢谢。不幸的是,我没有那个奢侈的东西:\只有恒定的二进制数据流。ReadTo方法肯定适用于实用程序中的其他地方。谢谢你的提醒,这似乎是个好主意。我搞乱了握手设置,但总是让软件控制它。将驱动程序设置更改为硬件流控制似乎已经解决了这个问题,至少在短期测试中是这样。我必须运行12个多小时的测试,看看它是否有效,在这种情况下,我会让你知道,并给你其中一个复选标记。这是一个很好的电话,也是我应该调查的事情。在解决了一些从未真正解决过我的问题的问题后,我发现我需要实现一个双缓冲区。我很高兴我再次提出了这个问题,甚至更多,所以你花时间提出了另一个很好的建议。谢谢谢天谢地,.NET通过简单地将一个BufferedStream包装在一个标准的FileStream(它有自己的内部缓冲区)周围来处理一切。我想在我完全确认这一点之前,我还有一些测试,但是这个缓冲逻辑似乎已经消除了一些小问题。
    private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] inc = new byte[serialPort1.BytesToRead];
        serialPort1.Read(inc, 0, inc.Length);
    
        bwLogger.Write(inc);
    }