Recently, serial communication programming is involved in the project. When teammates are doing this module, they encounter a problem that many people may encounter, that is, accepting data conflicts or loss. It took nearly two hours for my teammates to solve the problem when I asked him to debug it. Now I think it is necessary to summarize the problem to give my friends who have encountered similar problems a thought ~
The problem is that a 15-byte data is sent every two seconds from the corresponding hardware device, storing hexadecimal data, each data entry starts with 7E and ends with 7E. Example: 7E 09 01 1A... 7E. However, the PC end encountered a problem when accepting the display. For example, if the first five data items were accepted normally, the next step would be to fill them with 00, the remaining 10 data items are displayed in the next data display position. As shown below:
7E 09 01 1A 5C 00 00 00 00 00 00 00 00 00 00 // 03 06 1A 2C 3D 09 6C 32 12 7E 00 00 00 00 00 00 00 // /////........
In short, it feels wrong. Right, first put the PC endCodePaste it:
Public Partial Class Form1: Form
{
/// <Summary>
/// Serial Port for receiving data
/// </Summary>
SerialPort spreceive;
Delegate Void Using data ( Byte [] Bytes );
Public Form1 ()
{
Form1.checkforillegalcrossthreadcils = False ;
Initializecomponent ();
Spreceive = New SerialPort ( " Com5 " , 57600 , Parity. None, 8 , Stopbits. One );
Spreceive. open ();
// Set the threshold value for triggering the datareceived event. During debugging, this does not work ~
Spreceive. receivedbytesthreshold = 15 ;
Spreceive. datareceived + = New System. Io. Ports. serialdatareceivedeventhandler (spreceive_datareceived );
}
/// <Summary>
/// Update received data to the UI display
/// </Summary>
/// <Param name = "bytes"> </param>
Public Void Updatereceivetoui ( Byte [] Bytes)
{
If (Txtreceive. invokerequired)
{
Receivdata DL = New Upload data (updatereceivetoui );
Object ARG = Bytes;
Txtreceive. Invoke (DL, ARG );
}
Else
Txtreceive. Text + = " ///////// " + Bitconverter. tostring (bytes );
}
/// <Summary>
/// Events triggered by received serial data
/// </Summary>
/// <Param name = "sender"> </param>
/// <Param name = "E"> </param>
Public Void Spreceive_datareceived ( Object Sender, system. Io. Ports. serialdatareceivedeventargs E)
{
Byte [] Recevied = New Byte [ 15 ];
Int Size = Spreceive. Read (recevied, 0 , Recevied. Length );
If(Size>0)
Updatereceivetoui (recevied );
}
}
during debugging, When I spreceive_datareceived byte [] recevied = New byte [ 15 ]; An Initialization is added, as shown below:
For (INT I = 0; I <Recevied. lengthl; I ++)
Recevied [I] = 11;
At this time, all the places displayed at 00 are replaced by 11. This makes sure that these 00 values are transmitted because the 15 byte arrays are not fully filled into our defined byte arrays, that is, read (byte [] bytes, int offset, int size) the function does not fill in the byte array at a time, but divides it twice. However, in this process, I use the SerialPort class datareceived event, that is, it will be triggered without receiving a piece of data, and the phenomenon here seems to be that the event has been triggered multiple times. Later, I found it in the SerialPort class attributes and suddenly found a receivedbytesthreshold attribute. From this attribute, we can see how many bytes can be controlled to trigger a datareceived event. So I set the threshold value to 15 bytes, and thought the problem was solved, but the result was ~
Sorry, but this property also gave us some tips and found the crux of the problem. That is, the threshold value triggered by the datarecevied event, that is, the number of bytes allowed to be triggered is too small. As a result, a data of 15 bytes triggers two datareceived events. To solve this problem, we can follow this idea, that is, to delay the trigger of the datarecevied event until one piece of data is accepted.
ThereforeSpreceive_datareceivedIn the event function, we make the following changes:
Byte [] receivebuffer = new byte [15];
Public void spreceive_datareceived (Object sender, system. Io. Ports. serialdatareceivedeventargs E)
{
Int bytesread = 0;
Spreceive. receivedbytesthreshold = 100000; // trigger a delayed datarecevied event again
While (true)
{
If (bytesread> = 15) // here 15 is the size of a piece of data.
{
Byte [] bytes = new byte [bytesread];
Array. Copy (receivebuffer, 0, bytes, 0, bytesread );
Array. Clear (receivebuffer, 0, bytesread );
Updatereceivetoui (bytes );
Bytesread = 0;
Break;
}
Try
{
Receivebuffer [bytesread] = (byte) spreceive. readbyte ();
++ Bytesread;
}
Catch (exception ex1)
{
MessageBox. Show (ex1.message );
Break;
}
Bytesread = 0;
Spreceive. receivedbytesthreshold = 1; // change the delay back to normal
}
}
After the above changes, we can solve the problem of data conflicts and loss in reading the serial port ~ We hope you can make an axe when it is not week-long ~