C # solve the problem of serial port data loss
C # serial class (SerialPort) is a new class in. NET Framework version 2.0. This class encapsulates the serial port operation, thus providing a simple method for serial port communication.
However, in the actual application of serial communication, the problem of data loss will occur in the data communication with high baud rate and large amount of information.
Usually, when we use the SerialPort class to receive the data sent from the serial port, we only need to write an event function.
That is, the DataReceived event is bound to a processing function, and then the function can be
Number to read the serial port data. The content of this function can be modified according to our needs. From the perspective of receiving data, it is assumed that the function is as follows:
//Serial port receiving event private void SerialPort_Rec(object sender, SerialDataReceivedEventArgs e) { //Thread.Sleep(50); string recString = string.Empty; while (this.SerialPort.BytesToRead > 0) { recString += this.SerialPort.ReadExisting(); //The data is read until the buffer data is read } DealString(recString); //Process the received string and write it yourself }
Most serial programs will use this idea to realize serial communication. That is, first receive the data, then process the data, and wait for receiving new data again after completing the data processing. However, this implementation method will lose data when the serial port communicates with high speed and large amount of information.
Here is an example based on my own situation:
I send one frame of data from the lower computer to the serial port every time. I hope this frame of data is as follows:
Response: $STA, a, 27.0123421091408000, X
A is the instrument ID, 27.0 is the temperature, 1234 is the power consumption, 1234mW, RTC time, and X is the calibration
However, in the actual receiving process, only half of the data is received, and $STA, a, 27.01234 directly executes the data processing function.
resolvent
Sampling multithreading method to solve this problem.
Receive data in the main thread, and add a thread to process data.
It's best not to use data structures like arrays. Because such data structures must be frequently "locked" and "unlocked" when operating in multithreading, which will reduce the performance of the program to a certain extent. Therefore, we choose queue Queen as the data structure of the data pool.
The advantages of using queue are fully reflected here. The data is first in first out. After processing the first received data, this part of memory can be directly released, which greatly increases the operation efficiency of the program.
At the same time, at the end of processing, the length of the queue should be judged. The thread can be ended only after the whole queue is processed.
At the same time, this method also has obvious disadvantages, as follows:
When the speed of data flowing into the queue is faster than out of the queue (that is, the speed of receiving data is faster than processing data), for a simple example, it is equivalent to that we have 10000 yuan in our hands, spend 20 yuan a day, and earn only 10 yuan a day. Our money is enough in a short time, but as time goes on, our resources will be exhausted.
Under the above circumstances, and when it needs to run for a long time, the heap memory may overflow.
My code is posted here:
//Serial port receiving event private void SerialPort_Rec(object sender, SerialDataReceivedEventArgs e) { while (this.SerialPort.BytesToRead > 0) { data_Queue.Enqueue((byte)SerialPort.ReadByte()); //Data queue } }
Data processing thread:
//Data processing thread public void DealDataThread() { List<byte> databytes = new List<byte>(); //byte[] databytes = new byte[20]; //C #, the data of java array can only be allocated in the heap area, there is no way while (!canStop) //Loop detection queue { /*The middle part is my personal data processing code, which users can change according to their own needs*/ if(data_Queue.Count>=24) //Processing starts when the received data length is sufficient { //System.Diagnostics.Debug.WriteLine(data_Queue.Peek()); if (data_Queue.Dequeue()== 36) //36 is the character '$', that is, the corresponding frame header { if(data_Queue.Dequeue() == 36) //Dual $$instruction { for(int i = 0; i < 20; i++) { databytes.Add(data_Queue.Dequeue()); //databytes.(i, data_Queue.Dequeue().to,1); } fileWriter.WriteLine(System.Text.Encoding.Default.GetString(databytes.ToArray())); databytes.Clear(); } } } } }