SerialPort data loss - C#

2020-07-23 05:49发布

问题:

I'm working on a SerialPort app and one very simple part of it is giving me issues. I simply want to read a constant stream of data from the port and write it out to a binary file as it comes in. The problem seems to be speed: my code has worked fine on my 9600 baud test device, but when carried over to the 115200bps live device, I seem to be losing data. What happens is after a variable period of time, I miss 1 byte which throws off the rest of the data. I've tried a few things:

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

or

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    byte[] inc = new byte[serialPort1.BytesToRead];
    serialPort1.Read(inc, 0, inc.Length);

    bwLogger.Write(inc);
}

and a few variations. I can't use ReadLine() as I am working with a constant stream of data (right?). I've tried fiddling with the buffer size (both serialPort1.ReadBufferSize and the hardware FIFO buffer). Ideally, for usability purposes, I'd handle this on the software side and not make the user have to change Windows driver settings.

Any ideas?

回答1:

You might try enabling handshaking, using the Handshake property of the SerialPort object.

You'll have to set it on both the sender or receiver. however: if you're overflowing the receiver's UART's buffer (very small, 16 bytes IIRC), there's probably no other way. If you can't enable handshaking on the sender, you'll probably have to stay at 9600 or below.



回答2:

If the problem seems to be that you can't process the data fast enough, what you could try would be to double-buffer your data.

1) Allow one thread to read the serial port into one buffer. This may involve copying data off the port into the buffer (i'm not intimately familiar with .NET).

2) When you are ready to handle the incoming data, (on a different thread) make your program read into the 2nd buffer, and while this is happening you should write the first buffer to disk.

3) When the first buffer is written to disk, swap it back to the serial port buffer, and write the 2nd buffer to disk. Repeat process, continually swapping the buffers.



回答3:

I'd try the following:

  • Set the Buffer-Size to at least 230K Bytes
  • Set the Incoming Threshold to 16K, 32K or 65K
  • Write this fixed blocks of data to the file

I'm not sure if this might help, but it should at least take the pressure of the framework to fire the event that often.



回答4:

  1. I would check the number of bytes read which is returned by the Read(Byte>[], Int32, Int32) method and make sure it matches what you expect.

  2. Make sure you are listening for SerialErrorReceivedEventHandler ErrorReceived events on the port object. An RXOver error would indicate your buffer is full.

  3. Check the thread safety on your output buffer. If the write to the output buffer is not thread safe, a second write may corrupt the first write.



回答5:

Is your bwLogger a BinaryWriter class? You might try using it with a BufferedStream to make the disk I/O nonblocking.

Also, if your packets have a known ending character, you can set the SerialPort.NewLine property to enable you to use ReadLine/WriteLine, although I don't think that would make much of a performance difference.



回答6:

The machines I've been working with recently all send a stop code (in my case ASCII code 3 or 4). If you also have this feature, you can make use of ReadTo(string) off your SerialPort object.