C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空

在C#中使用串口接收数据时发现,在完整的接收完一次数据后,还会再次进入串口接收事件。

在网上搜索资料发现其他开发者也有遇到该问题:

[1]  c#串口事件接受一次数据莫名其妙会触发两次   原文链接:https://www.52pojie.cn/thread-1009851-1-1.html

[2]Serial Port object's DataReceived Event firing twice   原文链接:https://stackoverflow.com/questions/30296199/serial-port-objects-datareceived-event-firing-twice

其中[2]提到:串口接收事件触发2次是正常的,第1次是有数据接收,第2次收到的是EOF标志,直接忽略掉第2次就好了。

在串口接收事件开头加入该部分判断后如下:

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    //接收到EOF则直接退出
    if (e.EventType == System.IO.Ports.SerialData.Eof)
    {
        return;    
    }
    
    ...
}
在串口接收事件的if语句处设置断点进行调试,第一次进入时:e.EventType 为System.IO.Ports.SerialData.Chars,串口缓冲区有3个字节需读取。

第2次进入时:e.EventType 仍为System.IO.Ports.SerialData.Chars,串口缓冲区有0个字节需读取。

通过程序调试可知:程序第2次进入串口接收事件并不是因为接收到EOF标志即System.IO.Ports.SerialData.Eof,而是接收到System.IO.Ports.SerialData.Chars,但接收到的字节长度为0。

因此,通过加入if (e.EventType == System.IO.Ports.SerialData.Eof) return;的方式并不可行。既然可以保证在第1次进串口接收事件就将数据接收完毕,且第2次进入串口接收事件的数据长度为0。则可通过判断接收字节长度为0就直接退出的方式忽略掉第2次进入的串口接收事件。

添加判断后的代码如下所示:经验证该方法可行,可以忽略掉第2次进入串口接收事件。具体导致进入第2次串口接收事件的原因还不明确,需继续探究!

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    //if (e.EventType == System.IO.Ports.SerialData.Eof)
    //添加此判断在接收完一帧数据后,第2次意外进入时会直接退出
    if (serialPort1.BytesToRead == 0)
    {
        return;    //串口数据长度为0则直接退出
    }
 
    //串口接收并不是接收的每个字节都会进入该事件,因此需在该事件中接收完数据
    Int32 readByteNum = 0;
 
    /* 等待数据接收完成,即3mS内串口接收到的数据长度不再变化则认为数据已经接收完成 */
    do
    {
        readByteNum = serialPort1.BytesToRead;
        System.Threading.Thread.Sleep(10);
    } while (readByteNum < serialPort1.BytesToRead && serialPort1.BytesToRead < 4096);
 
 
    serialPort1.Read(usartRecvBuffer, 0, readByteNum);  //将串口缓冲区的数据保存至接收缓冲区
    serialPort1.DiscardInBuffer();                      //清空串口缓冲区的内容
    
    //显示串口接收到的数据
    string str = string.Empty;
    for (int i = 0; i < readByteNum; i++)
    {
        str += (usartRecvBuffer[i].ToString("X02") + ' ');
    }
#if USE_DELEGATE
    this.UpdataControl(tboxRecv, str);
#else
    tboxRecv.Text = str;
#endif
}
微软官方对 SerialPort.DataReceived 事件 的使用说明:

 原文链接:https://docs.microsoft.com/zh-cn/dotnet/api/system.io.ports.serialport.datareceived?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0
————————————————
版权声明:本文为CSDN博主「weixin_43885532」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43885532/article/details/112311511

你可能感兴趣的:(单片机学习,c#,开发语言)