C#解决串口数据丢失问题

您所在的位置:网站首页 串口缓冲区数据读取后就消失 C#解决串口数据丢失问题

C#解决串口数据丢失问题

2024-07-01 05:59| 来源: 网络整理| 查看: 265

C# 解决串口数据丢失问题

C # 串行类( SerialPort )是.NET Framework version 2.0 中一个新增的类,该类将串口操作了封装,从而为串口通信提供了简便方法。

但在实际串口通信的应用中,在串口高波特率大信息量的数据通信时,会出现丢失数据的问题。

通常我们使用SerialPort类接收串口发送过来的数据时,只需要写一个事件函数。

即DataReceived 事件绑定一个处理函数,然后就可以在该函 数中实现对串口数据的读取。 这个函数的内容可以根据我们的需求自行修改。就单纯从接收数据的角度出发, 假设该函数内容如下:

//串口接收事件 private void SerialPort_Rec(object sender, SerialDataReceivedEventArgs e) { //Thread.Sleep(50); string recString = string.Empty; while (this.SerialPort.BytesToRead > 0) { recString += this.SerialPort.ReadExisting(); //数据读取,直到读完缓冲区数据 } DealString(recString); //处理接收到的字符串,由自己写 }

大多串口程序都会采用这种思路来实现串口通信。即先接收数据,然后处理数据,并在完成数据处理后,再次等待接收新数据。但这种实现方法在串口高速率大信息量通信时,会出现丢失数据的情况。

这里根据我自己的情况举一个例子:

我从下位机每次发送一帧数据给串口,我希望这一帧数据如下:

应答:$STA,A,27.0,1234,210914080000,X A为仪器ID,27.0为温度,1234为功耗1234mW,RTC时间,X为校验

但实际接收过程中往往只收到一半数据$STA,A,27.0,1234就直接执行了数据处理函数。

解决方法

采样多线程的方法来解决这个问题。

在主线程中专门接收数据,增加一个线程来处理数据。

最好不要选用像数组这样数据结构。因为此类数据结构在多线程中操作时必须频繁地“加锁”和“解锁”,在一定程度上会降低程序的性能。所以我们选用队列 Queen 作为数据池的数据结构。

image-20210919184929014

使用列队的好处在这里充分体现了,数据先入先出,先收到的数据进行处理后就可以直接释放掉这部分内存,使得程序的运行效率大幅增加。

同时在结束处理的的时候,要对队列的长度进行判断,只有把整个队列处理结束才可以结束线程。

同时该方法也存很明显在劣势,如下:

当数据流入队的速度大于出列队(即接收数据的速度大于处理数据),举个简单例子,就相当于我们手上有一万块钱,每天要花20,每天只能赚10块钱,短时间内我们的钱是够用的,但时间一长,资源就会枯竭。

以上情况下,且需要长时间运行时,堆内存就有可能溢出。

这里贴出我的代码:

//串口接收事件 private void SerialPort_Rec(object sender, SerialDataReceivedEventArgs e) { while (this.SerialPort.BytesToRead > 0) { data_Queue.Enqueue((byte)SerialPort.ReadByte()); //数据入队 } }

数据处理线程:

//数据处理线程 public void DealDataThread() { List databytes = new List(); //byte[] databytes = new byte[20]; //C#,java的数组的数据只能分配在堆区,没有办法 while (!canStop) //循环检测列队 { /*中间这部分是我个人的数据处理代码,用户可以根据自己需求自己改变*/ if(data_Queue.Count>=24) //当接收到的数据长度足够时开始处理 { //System.Diagnostics.Debug.WriteLine(data_Queue.Peek()); if (data_Queue.Dequeue()== 36) //36就是字符'$',即对应帧头 { if(data_Queue.Dequeue() == 36) //双$$指令 { for(int i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3