简体   繁体   English

C#SerialPort - 混合具有不同波特率的端口的问题

[英]C# SerialPort - Problems mixing ports with different baud rates

I have two devices that I would like to connect over a serial interface, but they have incompatible connections. 我有两个设备,我想通过串行接口连接,但它们有不兼容的连接。 To get around this problem, I connected them both to my PC and I'm working on a C# program that will route traffic on COM port X to COM port Y and vice versa. 为了解决这个问题,我将它们连接到我的PC上,我正在开发一个C#程序,它将把COM端口X上的流量路由到COM端口Y,反之亦然。

The program connects to two COM ports. 该程序连接到两个COM端口。 In the data received event handler, I read in incoming data and write it to the other COM port. 在数据接收事件处理程序中,我读入传入的数据并将其写入另一个COM端口。 To do this, I have the following code: 为此,我有以下代码:

    private void HandleDataReceived(SerialPort inPort, SerialPort outPort)
    {
        byte[] data = new byte[1];

        while (inPort.BytesToRead > 0)
        {
            // Read the data
            data[0] = (byte)inPort.ReadByte();

            // Write the data
            if (outPort.IsOpen)
            {
                outPort.Write(data, 0, 1);
            }
        }
    }

That code worked fine as long as the outgoing COM port operated at a higher baud rate than the incoming COM port. 只要传出的COM端口以高于传入COM端口的波特率运行,该代码就能正常工作。 If the incoming COM port was faster than the outgoing COM port, I started missing data. 如果传入的COM端口比传出的COM端口快,我开始丢失数据。 I had to correct the code like this: 我不得不纠正这样的代码:

    private void HandleDataReceived(SerialPort inPort, SerialPort outPort)
    {
        byte[] data = new byte[1];

        while (inPort.BytesToRead > 0)
        {
            // Read the data
            data[0] = (byte)inPort.ReadByte();

            // Write the data
            if (outPort.IsOpen)
            {
                outPort.Write(data, 0, 1);
                while (outPort.BytesToWrite > 0);  //<-- Change to fix problem
            }
        }
    }

I don't understand why I need that fix. 我不明白为什么我需要修复。 I'm new to C# (this is my first program), so I'm wondering if there is something I am missing. 我是C#的新手(这是我的第一个程序),所以我想知道是否有我遗漏的东西。 The SerialPort defaults to a 2048 byte write buffer and my commands are less than ten bytes. SerialPort默认为2048字节写缓冲区,我的命令少于10个字节。 The write buffer should have the ability to buffer the data until it can be written to a slower COM port. 写缓冲区应该能够缓冲数据,直到它可以写入较慢的COM端口。

In summary, I'm receiving data on COM X and writing the data to COM Y. COM X is connected at a faster baud rate than COM Y. Why doesn't the buffering in the write buffer handle this difference? 总之,我在COM X上接收数据并将数据写入COM Y. COM X以比COM Y更快的波特率连接。为什么写缓冲区中的缓冲不能处理这种差异? Why does it seem that I need to wait for the write buffer to drain to avoid losing data? 为什么我需要等待写缓冲区耗尽以避免数据丢失?

Thanks! 谢谢!

* Update * *更新*

As noted, this code can very easily run into an overflow condition with large and/or fast incoming data transfers. 如上所述,此代码很容易遇到具有大量和/或快速传入数据传输的溢出情况。 I should have written more about my data stream. 我应该写更多关于我的数据流的文章。 I'm expecting < 10 byte commands (with < 10 byte responses) at 10 Hz. 我期待10赫兹的<10字节命令(<10字节响应)。 In addition, I'm seeing failures on the first command. 另外,我看到第一个命令失败了。

So while I know this code does not scale and is less than optimal, I'm wondering why the 2-4K read/write buffers couldn't even handle the first command. 因此,虽然我知道这个代码不能扩展并且不是最佳的,但我想知道为什么2-4K读/写缓冲区甚至无法处理第一个命令。 I'm wondering if there is a bug with writing a single byte of data or something with the event handler that I don't understand. 我想知道是否存在使用我不理解的事件处理程序写入单个数据字节的错误。 Thanks. 谢谢。

* Update * *更新*

Here's an example of the failure: 这是失败的一个例子:

Let's say my command is four bytes: 0x01 0x02 0x3 0x4. 假设我的命令是四个字节:0x01 0x02 0x3 0x4。 The Device on COM X sends the command. COM X上的设备发送命令。 I can see the C# program receiving four bytes and sending them on to the device on COM Y. The device on COM Y receives two bytes: 0x01 0x03. 我可以看到C#程序接收四个字节并将它们发送到COM Y上的设备.COM Y上的设备接收两个字节:0x01 0x03。 I know the device on COM Y is reliable, so I'm wondering how the two bytes were dropped. 我知道COM Y上的设备是可靠的,所以我想知道这两个字节是如何被丢弃的。

By the way, can someone let me know if it's better to just reply to answers with comments or if I should keep editing the original question? 顺便说一下,有人可以告诉我,如果只是回复带有评论的答案,或者我是否应该继续编辑原始问题? Which is more helpful? 哪个更有帮助?

What you are trying to do is equivalent to drinking from a fire hose. 你要做的就是用消防水管喝水。 You are relying on the receive buffer to store the water, it isn't going to last long when somebody doesn't turn the tap off. 您依靠接收缓冲区来存储水,当有人不关闭水龙头时,它不会持续很长时间。 With your workaround, you are making sure that the receive buffer will overflow silently, you probably didn't implement the ErrorReceived event. 使用您的解决方法,您确保接收缓冲区将以静默方式溢出,您可能没有实现ErrorReceived事件。

To make this work, you'll have to tell the input device to stop sending when the buffer is full. 要使其工作,您必须告诉输入设备在缓冲区已满时停止发送。 Do that by setting the Handshake property. 通过设置Handshake属性来做到这一点。 Set it to Handshake.RequestToSend first. 首先将它设置为Handshake.RequestToSend。 Use XOnXOff next. 接下来使用XOnXOff。 It depends on the device whether it will use the handshake signals properly. 这取决于设备是否将正确使用握手信号。

Use the Read() method to make this a bit more efficient. 使用Read()方法可以提高效率。


Okay, not fire hose. 好的,不是消防水带。 I can think of only one other possibility. 我只能想到另一种可能性。 A common problem with early UART chip designs, they had a on-chip receive buffer that could store only one byte. 早期UART芯片设计的一个常见问题是,它们具有片上接收缓冲器,只能存储一个字节。 Which required the interrupt service routine to read that byte before the next one arrived. 这要求中断服务程序在下一个字节到达之前读取该字节。 If the ISR isn't quick enough, the chip turns on the SerialError.Overrun state and the byte is irretrievably lost. 如果ISR不够快,芯片将打开SerialError.Overrun状态,并且该字节无法恢复丢失。

A workaround for this issue was to artificially put a delay between each transmitted byte, giving the ISR in the device more time to read the byte. 此问题的解决方法是在每个传输的字节之间人为地设置延迟,从而使设备中的ISR有更多时间来读取字节。 Which is what your workaround code does, as a side-effect. 这是您的解决方法代码所做的,作为副作用。

It is not a great explanation, modern chip designs have a FIFO buffer that's at least 8 bytes deep. 这不是一个很好的解释,现代芯片设计有一个至少8字节深的FIFO缓冲区。 If there is any truth to this at all, you should see the problem disappear when you lower the baudrate. 如果对此有任何道理,那么在降低波特率时应该会看到问题消失。 Also, using Read() instead of ReadByte() should make the problem worse since your Write() call can now transmit more than one byte at a time, eliminating the inter-character delay. 此外,使用Read()而不是ReadByte()会使问题变得更糟,因为您的Write()调用现在可以一次传输多个字节,从而消除了字符间延迟。 To be clear, I'm talking about the output device. 要清楚,我在谈论输出设备。

You should make sure that outPort.WriteBufferSize is bigger than the biggest buffer you expect to send. 您应该确保outPort.WriteBufferSize大于您希望发送的最大缓冲区。 Also, calling ReadByte and WriteByte in a loop is generally going to be slow. 此外,在循环中调用ReadByteWriteByte通常会很慢。 If you change your handler to something like: 如果您将处理程序更改为:

int NumBytes = 20; //or whatever makes sense
byte[] data = new byte[NumBytes];

while (inPort.BytesToRead > 0)
{
    // Read as much data as possible at once
    count = inPort.Read(data, 0, min(NumBytes, inPort.BytesToRead));

    // Write the data
    if (outPort.IsOpen)
    {
        outPort.Write(data, 0, count);
    }
}

this will reduce the overhead, which ought to help. 这将减少开销,这应该有所帮助。 The Write buffer will then (hopefully) handle the timing as you expect. 然后,Write缓冲区将(希望)按预期处理时序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM