c#串口通信(四)--串口数据丢失或分段原因及串口事件的说明

订阅收费文章或资源:公众号“毛线杂货铺”,淘bao店铺ID:122344852,可搜索商铺“幸福的孩子yyx”或复制以下内容:
59《ZuboWnWzq1R《 https://m.tb.cn/h.5D3Od4wRAQzgQpH MF6563 我分享给你了一个超赞的内容,快来看看吧
或:
请添加图片描述

最近在软件调试中,发现数据一长就经常丢失数据,所以耐下心了解了一些原理,用较为简单的理解方式记录下来。
题外话
一般来说,半双工通信需要添加一个超时时间,当超过这个时间后,就判定接收失败了,之前的缓存数据也要清空。
个人选择定时器的方式,至于如何计算超时,公式如下:
数据所需时常=总数据长度10/波特率。
对于我的数据,最长为1237字节,波特率选择9600,则需要耗时1237
10/9600=1.28854…,基本为1.3秒,所以我设置了串口的超时时间为3秒。发送后如果3秒没接收到数据,就算超时,直接发下一条指令。

串口数据丢失:

数据丢失中间部分数据或者尾部数据。
问题原因:

未使用好串口的丢弃缓存函数

serialPort?.DiscardInBuffer();//丢弃接收缓冲区数据

个人习惯在下面的代码后面添加丢弃缓存函数,导致数据丢失

 byte[] buffer = new byte[serialPort.BytesToRead];
 serialPort.Read(buffer, 0, buffer.Length);

原因是我读取serialPort.BytesToRead长度时,用buffer取缓存的时候,长度已经增加了,所以我丢弃缓存会将还没获取的缓存一并清除。
这里大家用read()方法的时候,其实读出来的数据在缓存中已经被清除了,不需要处理。

串口数据一包分很多次触发串口事件

为了串口一次得到完整包,一般我们在进入串口事件后会选择延时(根据完整包所需时长),再从缓存中获取数据。
但是一旦数据包字节很长的时候,这样的方式就不是很好,因为延时造成界面卡或者漏包,就选择将延时去掉。
使用9600的波特率接大于32字节的数据时,如果在串口事件中不延时,会发现每次触发触发事件可以接收到32个字节,所以需要拼接字节,得到最后的完整包。
个人代码如下:

 private void DataReceived(object sender, SerialDataReceivedEventArgs e)
 {
     try
     {
         if (!serialPort.IsOpen)//串口在关闭时不接收数据 为了防止关闭串口时卡死的问题
         {
             serialPort?.DiscardInBuffer();//丢弃接收缓冲区数据
             return;
         }
         if (serialPort.BytesToRead < 4 && LineBuffer == null)
         {
             return;
         }
         byte[] buffer = new byte[serialPort.BytesToRead];
         serialPort.Read(buffer, 0, buffer.Length);
         InquireOutTimeCount = 0;
         if (buffer == null || buffer.Length <= 0)
             return;
         Show(buffer, "串口接收");
         if (buffer[0] == CommunicationHelper.CmdBagHead1 && buffer[1] == CommunicationHelper.CmdBagHead2)//判断是否是包头
         {
             LineBuffer = buffer;
         }
         else if (LineBuffer != null)//拼接
         {
             LineBuffer = CommunicationHelper.AddBytes(LineBuffer, buffer);
         }
         //之后去判断包是否完整,完整解析后清空自己的缓存
         .........
}

有关串口事件说明

串口内部有一个缓存,串口数据都会保留在这里,可使用read()去读取。
经过调试,发现串口事件应该是一个时间触发的机制,例如9600的波特率每次触发串口事件最多能传递32个字节。
串口内部的缓存是类似队列的先进先出,进入串口事件后,读到的缓存长度serialPort.BytesToRead只是读的时候缓存的长度,可能你下一行代码去取缓存的时候,缓存就增加了,你只能取到之前的缓存数量,若没有选择清空缓存,完成本次串口事件后,剩余的缓存会再次触发串口事件让你继续读取缓存。

  • 21
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yyuanyuxin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值