IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> C#解决串口数据丢失问题 -> 正文阅读

[数据结构与算法]C#解决串口数据丢失问题

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<byte> databytes = new List<byte>();
		//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 < 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()}
				}
			}
		}
	}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-20 16:00:39  更:2021-09-20 16:02:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 8:02:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码