I'm developing software for logging data from RS232. There is a lot of data received each millisecond. Received data is stored in datagridview, you can see on attached picture.
For filling data I use dataGridView1.InvokeRequired from serialPort1_DataReceived event.
It works fine when there is just a few data on RS232. But when it receives many packets from RS232 GUI is working slow. There is no reaction for buttons pressing, and application consumes CPU. Once I disconnect RS232 physically there is no new data, buttons pressing response immediately.
My second approach was using dataGridView1.Rows.Add directly from serialPort1_DataReceived event. In this case it works fast, buttons are responsible. But dataGridView1 doesn't refresh, and some times flicker. I'm already using double buffering for it.
So my questions are:
How to speed up using InvokeRequired?
How to refresh dataGridView1 after filling dataGridView1.Rows.Add from serialPort1_DataReceived?
enter image description here
Related
I developed a Windows Form application, using C#, that receives data through the serial port sent by a microcontroller. I'm receiving the data using the serialPort_DataReceived event in which I use ReadLine() to read the serial port. Then I use the Invoke method to call a function that will print the received string into a textBox. The problem is that the app can't keep up with the rate at which it receives the strings, for example, the string that I send from the microcontroller has the time at which it was sent and even though it has already passed 2 or 3 seconds the app is still printing the strings that were sent at the 0.2 second. And when I send a string to the microcontroller to stop sending data, the app onlys stops ptinting the data after a while, this is, it keeps printing the values stored in the receiving buffer.
I believe that is happens given the large amount of data that the app receives and the rate (I'm using a baud rate of 115200), one string for every millisecond. This is, I think that the app is always being interrupted by the DataReceived event and it doesn't has time to print the data and starts falling behind.
One way I though of overcome this problem was with multi-threading but I can't figure it out how. I already tried a few examples using the BackgroundWorker but I didn't manage to make it work at all. I'm still a noob in terms of programming Windows Form apps and even C#.
Can anyone confirm the cause of the problem? And how do I make a thread to print the received data?
You can utilize SerialPort.ReceivedBytesThreshold property and SerialPort.ReadExisting() method (or a StringBuilder instance) to update UI with a batch of strings at once rather than a single string.
For more information check:
Serial port DataReceived firing too much discussions on StackOverflow
Top 5 SerialPort Tips article by Kim Hamilton
Serial Port ReadLine vs ReadExisting or how to read the data from serial port properly discussion on StackOverflow
Quickest way to Update Multiline Textbox with Large Amount of Text discussion on StackOverflow
I'm new to C# and WinForms, and i'm developing an application, which would allow me to read data from serial port and display it on some display tool (listview,...).
Now, i got serial communication and other functionalities working, but i'm having a problem with displaying the data. I need to be able to display incoming data really fast (every 1ms). To display data (for now), i'm using dataGridView, but the problem is that dataGridView is not fast enough.
So my question is: Is there some way to display data that fast? I know the human eye can't really see data in this interval, but still... It would be prefered to display data in dataGridView-like display, since it's really easy to organize data.
Best regards,
Nejc
You are not going to succeed displaying data every 1 ms. What you should do is buffer the incoming data on one thread, then every N incoming data, call on a method to display the data (i.e. you will be adding N rows at a time). Note you will need to use Invoke() as you will be calling on the GUI from a different thread (the thread that receives the data, not the thread that created the GUI).
I am trying to draw graphics on a form application based on data from an externally connected USB device to my PC. my goal is to continuously uploading the data from USB device and updating the graphics like every 20ms.
First, I made the below two codes and put them in button_click function. Each time the button is clicked, they work fine.
uploadData(); // this uploads 2KB data from USB device connected to my PC
drawGraphics(); // this draws graphics on a picture box
So as next step, I put them in while infinite loop like below. But drawing does not work while data uploading from the USB device keeps running. I was probing the USB device hardware and I confirmed it keeps sending new data to my PC.
while(true)
{
uploadData();
drawGraphics();
}
I put Thread.Sleep() between the above codes and put various delay values to see if the problem is solved, but no success.
Interesting thing is that each time when I move mouse's cursor over the form, the drawing starts a bit but stops at early point.
This could be related to very simple mistake. I am kind of new to Visual C# so just hit this wall and not able to overcome it.
Usually the way to handle an occasional-update requirement in a GUI app is to use a timer. The timer runs on a background thread and notifies the main thread occasionally that a "tick" has occurred. This way, other operations like processing mouse and keyboard input, drawing to the screen, etc. can continue. I'm not entirely sure why your solution isn't working, but I'm 99% sure you can fix it by replacing the while loop with a System.Windows.Forms.Timer that ticks on the desired interval.
So, I recommend: adding a Windows Forms Timer to your form via the Visual Studio designer, setting its Interval property to the desired number of milliseconds, registering an event handler for the timer tick, moving the uploadData() call to that event handler, and moving the content of the drawGraphics() method to the PictureBox's Paint event.
Instead of having an infinite loop, create a timer control. Set the Interval to 20 (thats 20 ms). In the OnTick create an Method that:
1) Send the Enabled property of your timer to 'False'
2) Calls your upLoadData and drawGraphics methods
3) Sets the Enabled property of your timer to 'True'
This way you won't simultaneously try to access the data on the USB more than once at a time if for some reason the 1st occurence takes a little longer than expected.
It's a simple, bare-bones C# app (as far as the Form Controls are concerned). The DataGridView is bound to manually-populated DataTable (including column headers). There's a menu item that begins the event-driven data acquisition process. As the data is added to the DataTable, the Console shows each row. One row has been added with dummy data, to verify DataTable data formats (this row will eventually be removed).
When the app is launched, and the data acquisition started, the DataView does not show any changes, only the dummy row is shown. The Console output tells me that the data is being process, and shows no errors, including overzealously trapped error messages.
Form.Refresh, DataGridView.Refresh, and DataGridView.RefreshEdit have been attempted, but appear to have no effect.
However... When the app is minimized and restored, data changes appear, and updates are shown as they are added; in other words, it "behaves". Once minimized and restored, it continues to operate as expected, for as long as the app runs.
Any ideas, short of minimizing and restoring the app on the first activation?
I'm brand new to StackOverflow, just noticed the "Answer Your Question" button at the bottom. See my previous comment for details.
In a nutshell, the DataGridView refreshes (properly) when running in the same thread as the invoking object. If you're getting an error about thread access violations, then read above.
I am writing an application that will display serial/USB data at a rate of up to 250kb/sec. I am using the .net SerialPort class and reacting to the DataReceived event. For early implementations of this software, I simply stored the incoming data in a WinForms RichTextBox. This solution works fine until there are 50k - 100k lines in the control, at which point the application bogs down. Since then, I've tried accomplishing my goals with WPF and found the same problem. I tried, at one point, to keep only the currently visible text in the textbox, and store the rest in a large List<string> but this solution required a huge number of workarounds and, in the end, was abandoned - I'd rather not reinvent the wheel.
Now I come to you for a thread of hope - I am willing to try anything! Should I use a custom control (both pay and free controls are welcome)? SQLite? Virtualization as described above? Should I try polling the SerialPort instead of reacting to events?
Use a thread to read the data and write it directly to a file. Have your app refresh the last x number of lines from the file every so often. Maybe even have the refresh based off of a notification from the reader thread?
By using multiple threads you'll keep the UI responsive and by writing straight to a file you'll ensure you've collected all of the data. Also, it will allow you to pause the display long enough to actually copy/paste the data you want while continuing to capture data.
Possibly you could implement your own type of file reader that would allow the user to "scroll" through the file by only loading the parts you can actually display on screen at one time.
If the data is largely line oriented (ReadLine) then put it in a ListBox. It is the fastest control for putting lots of text onscreen.
But you will find that all UI controls are geared toward human interaction, not to the speed of a Port. Best thing to do would be to rethink your design. What is that data for anyway?