.NET框架下 SerialPort.Read()分包原因分析及解决办法。

串口接收,一般我们都是开启新的线程,用新线程来处理接收数据的事务,以下代码是容易产生分包的代码:(示例代码为C#)

        void Received_dat()
        {
            
            while (serialPort.IsOpen)
            {
                Thread.Sleep(50);  //延时50毫秒
                try
                {
                    int n = serialPort.BytesToRead;    //    获取串口已缓存到的字节数            
                    byte[] buf = new byte[n];  //定义字节型数组存放串口读取到的数据

                       if (n != 0) //排除没有接收到数据的情况
                       { 
                        serialPort.Read(buf, 0, n); //读串口,把数据存放到字节型数组
                        Application.Current.Dispatcher.Invoke(delegate{
                        TB_AESPassword.Text = UTF8Encoding.UTF8.GetString(buf);}); 更新主线程UI
                       }

                }
                catch (Exception)
                {

                    
                }
            }
        }

分析原因:以上代码放进新线程中运行,会在新线程中无限循环,当串口接收的数据还不完整的时候,比如接收了50字节(共计100字节),这个时循环程序执行到了serialPort.Read(buf, 0, n); 这句,就把前50个字节给读出来了,剩下50字节,自然就会在下一个循环中接收到,这就产生了串口数据分包。 基于以上分析,我们可以利用两次读取BytesToRead属性值来判断接收到的数据是完整的,还是数据正在进行中。。。。。。 第一次读BytesToRead完后,延时一小断时间,然后再读一次,如果数据相等,说明数据已接收完,如果数据不相等,那么说明接收还在进行中,这样就可以避免串口数据分包的情况发生。

实现代码如下:

        void Received_dat()
        {
            
            while (serialPort.IsOpen)
            {
                Thread.Sleep(50);  //延时50毫秒,防止CPU占用过多
                try
                {
                    int n = serialPort.BytesToRead;    // 获取串口已缓存到的字节数 
                    Thred.Sleep(1);   //延时1毫秒 
                    int n1 = serialPort.BytesToRead;   //再次获取串口已缓存到的字节数
                    byte[] buf = new byte[n];  //定义字节型数组存放串口读取到的数据

                    if(n==n1)  //如果第一次和第二次读取的字节数相等,那么认为数据接收完整。
                     {
                       if (n != 0) //排除没有接收到数据的情况
                       { 
                        serialPort.Read(buf, 0, n); //读串口,把数据存放到字节型数组
                        Application.Current.Dispatcher.Invoke(delegate{
                        TB_AESPassword.Text = UTF8Encoding.UTF8.GetString(buf);}); 更新主线程UI
                       }
                     }

                }
                catch (Exception)
                {
                    
                }
            }
        }

经实际调试,以上代码很好的解决了分包问题,达到了预期的效果。

猜你喜欢

转载自blog.csdn.net/dream52/article/details/124396702