C# .Net Serial DataReceived Event response too slow for high-rate data
Asked Answered
D

4

7

I have set up a SerialDataReceivedEventHandler, with a forms based program in VS2008 express. My serial port is set up as follows:

115200, 8N1

Dtr and Rts enabled

ReceivedBytesThreshold = 1

I have a device I am interfacing with over a BlueTooth, USB to Serial. Hyper terminal receives the data just fine at any data rate. The data is sent regularly in 22 byte long packets. This device has an adjustable rate at which data is sent. At low data rates, 10-20Hz, the code below works great, no problems. However, when I increase the data rate past 25Hz, there starts to recieve mulitple packets on one call. What I mean by this is that there should be a event trigger for every incoming packet. With higher output rates, I have tested the buffer size (BytesToRead command) immediatly when the event is called and there are multiple packets in the buffer then. I think that the event fires slowly and by the time it reaches the code, more packes have hit the buffer. One test I do is see how many time the event is trigger per second. At 10Hz, I get 10 event triggers, awesome. At 100Hz, I get something like 40 event triggers, not good. My goal for data rate is 100HZ is acceptable, 200Hz preferred, and 300Hz optimum. This should work because even at 300Hz, that is only 52800bps, less than half of the set 115200 baud rate. Anything I am over looking?

    public Form1()
    {
        InitializeComponent();
        serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);            
    }


    private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        this.Invoke(new EventHandler(Display_Results));
    }


    private void Display_Results(object s, EventArgs e)
    {
        serialPort1.Read(IMU, 0, serial_Port1.BytesToRead);
    }
Ducat answered 1/6, 2010 at 6:58 Comment(0)
V
8

Did you try to ajust time latency on the USB serial converter? I had the same problem with a FTDI USB to serial converter. I use an oscilloscope to see my IN and OUT data coming from the device and I could see that the computer was always slow to respond. By default, time latency on the device is set to 16 ms. I changed it to 2 ms and it makes a big difference. Go to your USB Serial Converter in the Device Manager and in the advanced settings, change Latency time to 2 ms. It should works. Try it.

Verbiage answered 27/6, 2011 at 13:36 Comment(1)
Any idea why a "16ms" latency translates into hundreds of milliseconds between bunches of received data?Gastronome
B
3

Why do you Invoke() the call to DisplayResults?

This will push it to the MessageLoop, an unnecessary delay.

It would be better if DataReceived() pushed data onto a (thread-safe) queue for decoupled processing.

I also think you could run into problems with split packages.

Burial answered 1/6, 2010 at 7:20 Comment(1)
I tried removing the Invoke() call and read the data directly in the DataReceived() event with the same results. Sorry to be a little naive, but could you tell me more about how you do the queue and why that works faster. Thanks for the help.Ducat
D
2

You could try setting ReceivedBytesThreshold = 22, which will result in the event being fired when there are at least 22 bytes to read. Note that it will be at least 22. There may be more.

I don't think I would personally do this though, because what happens if your packet size changes in the future, for example to 12 bytes? You would end up with 12 bytes in the buffer but not firing the event at all.

Far better to leave it set to 1, which will fire the event when at least 1 byte is available. Then push all received bytes into a list or a queue as Henk has already posted.

Note that the DataReceivedEvent has no knowledge of what you consider a packet of data to be of course. It just fires when there are bytes available. It is up to the developer to assemble these bytes into a meaningful message or packet.

Demur answered 20/11, 2010 at 11:10 Comment(0)
S
2

The problem lies in the received data handler.

I ran a separate thread with a while(true) loop and serial.ReadLine(), all works perfectly.

using System.Threading;

Thread readThread = new Thread(Read);
readThread.Start();

Hope someone else doesn't need to spend 3 hours fixing this.

Slick answered 20/7, 2017 at 9:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.