C#串口通讯接收结束位检验

Herry_zzz 2020-01-12 02:03:15
C#串口通讯,接收数据,不确定长度,第一位是0x7e,倒数第三位是0x0d。请问大家,怎么检验才不会丢失数据呢?
...全文
774 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
Herry_zzz 2020-01-16
  • 打赏
  • 举报
回复
引用 7 楼 冰风漫天 的回复:
while (receivedDatas.Count>=3 && receivedDatas[receivedDatas.Count-3]==0x0d) 这样呢
7楼说的这个有用,没有在报错了。9楼写的有点复杂,看不懂~!
雪狼孤竹 2020-01-15
  • 打赏
  • 举报
回复
串口通讯,具体看协议,一条数据被确认为有效数据,一般都会有相应的校验。在收全数据后,对收到的数据做相应的校验,相等表明该数据是有效数据,然后根据具体的协议说明来解析数据。
你说出的条件,不太好确认一条有效数据,因为在传输的数据中,是否就有你要作为标识的“7E”和“0D”?
个人认为,你应该先把协议看明白,然后再来问问题!
github_36000833 2020-01-14
  • 打赏
  • 举报
回复
class 测试
{
    static void Main(string[] args)
    {
        var 分割器 = new 数据帧分割器();
        分割器.数据帧收悉事件 += (s, e) =>
        {

            // 这里可以自行添加校验代码 ThrowOnCorruptedData(e.数据帧);
            // ...
            Console.WriteLine(BitConverter.ToString(e.数据帧)); 
            Console.WriteLine(Encoding.UTF8.GetString(e.数据帧, 1, e.数据帧.Length - 3));
            Console.WriteLine();
        };

        分割器.添加数据(Encoding.ASCII.GetBytes("~first frame\r")); // 假设收到这些数据
        分割器.添加数据(new byte[] { 8, 8 }); // 假设校验码是0x08, 0x08

        分割器.添加数据(Encoding.ASCII.GetBytes("~second fram"));
        分割器.添加数据(new byte[] { (byte)'e', (byte)'\r', 0x78, 0x9a }); // 假设校验码是0x78, 0x8a

        Console.ReadLine();
    }
}
github_36000833 2020-01-14
  • 打赏
  • 举报
回复
引用 4 楼 Herry_zzz 的回复:
... 开头是7e ,中间是ASCII码的数字,比如 7e 30 31 32..............39 0d ab cd 0d后面两位是对0d前面所有字符的一个校验。
最好把数据帧分割独立出来,放到一个类似FrameDelimiter的类下。这样做代码比较清晰,也容易测试。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class 数据帧分割器
{
    const byte 起始标志 = 0x7E;
    const byte 结束标志 = 0x0D;
    const int 校验码长 = 2;
    List<byte> _待处理数据 = new List<byte>();

    public void 添加数据(byte[] data)
    {
        添加数据(data, 0, data.Length);
    }
    public void 添加数据(byte[] data, int offset, int count)
    {
        _待处理数据.AddRange(new ArraySegment<byte>(data, offset, count));

        var 起始位置 = _待处理数据.IndexOf(起始标志);
        if (起始位置 < 0) return; // 尚未收到起始标志

        var 结束位置 = _待处理数据.IndexOf(结束标志, index: 起始位置);
        if (结束位置 < 0 || _待处理数据.Count < 结束位置 + 校验码长) return; // 尚未收到结束标志 + 校验码

        var frame = new byte[结束位置 + 校验码长 + 1 - 起始位置];
        _待处理数据.CopyTo(起始位置, frame, 0, frame.Length); // 把数据帧割出
        _待处理数据 = new List<byte>(_待处理数据.Skip(结束位置 + 校验码长 + 1)); // 把剩余数据留下

        数据帧收悉事件?.Invoke(this, new DataFrameEventArgs() { 数据帧 = frame }); // 激发数据帧收悉事件
    }

    public event EventHandler<DataFrameEventArgs> 数据帧收悉事件;
    public class DataFrameEventArgs : EventArgs
    {
        public byte[] 数据帧 { get; set; }
    }
}
冰风漫天 2020-01-14
  • 打赏
  • 举报
回复
while (receivedDatas.Count>=3 && receivedDatas[receivedDatas.Count-3]==0x0d) 这样呢
Herry_zzz 2020-01-14
  • 打赏
  • 举报
回复
引用 5 楼 冰风漫天 的回复:
那你现在的操作是,在0x7e后面找到0x0d,然后把这两个字节之间的字节流,再用0x0d后面的两位去校验?是有碰到什么问题了吗?
具体代码应该怎么实现呢??我网上看的代码,改了一下,但是有个问题是,while的位置,有时候会报错, byte[] ReceivedData = new byte[sp.BytesToRead];//创建接收字节数组 sp.Read(ReceivedData, 0, ReceivedData.Length);//读取所接收到的数据 receivedDatas.AddRange(ReceivedData); while (receivedDatas[receivedDatas.count]-3==0x0d)//如果接收数据中有0x0d { if (receivedDatas[0] != 0x7e) { //若针头针尾没有达到协议标准则移除BufferList第一位,继续下一轮判断 receivedDatas.RemoveAt(0); continue; } tbReceivedCount.Text = (Convert.ToInt32(tbReceivedCount.Text) + ReceivedData.Length).ToString();//接收计数 if (cb16Display.Checked) tbReceivedData.Text = Methods.ByteTo16Str(receivedDatas.ToArray()); else tbReceivedData.Text = Encoding.Default.GetString(receivedDatas.ToArray()); sp.DiscardInBuffer();//丢弃接收缓冲区数据 receivedDatas.Clear(); }
冰风漫天 2020-01-14
  • 打赏
  • 举报
回复
那你现在的操作是,在0x7e后面找到0x0d,然后把这两个字节之间的字节流,再用0x0d后面的两位去校验?是有碰到什么问题了吗?
Herry_zzz 2020-01-14
  • 打赏
  • 举报
回复
开头是7e ,中间是ASCII码的数字,比如 7e 30 31 32..............39 0d ab cd 0d后面两位是对0d前面所有字符的一个校验。
引用 1 楼 冰风漫天 的回复:
问题提的还不够具体 什么情况下会丢失数据? 数据流中还有其他字节存在0x7e、0x0d的值是吗? 多个数据流是会合在一起过来的是吧?字节流间会不会混杂其他类型的数据?
//// //// 开头是7e ,中间是ASCII码的数字,比如 7e 30 31 32..............39 0d ab cd 0d后面两位是对0d前面所有字符的一个校验。
「已注销」 2020-01-13
  • 打赏
  • 举报
回复
通常一个串口协议要封装,需要有同步头(也就是第一个字需是固定的值),帧数据长度指示,校验字节,否则就要保证你的前后检查的字节不能被重复。
xiaoid 2020-01-13
  • 打赏
  • 举报
回复
通讯数据不都是有定义的格式吗?怎么定义的,就怎么读取吧。
读取不了, 说明定义的不规范,重新定就是了。
比如你上面的说这样的说法,那就是查找7E , 再找0D, 找到0D后,再加2就是完整的包数据了。
如果一个数据包中有7E, 0D等数据,那你就转义后再发送吧。
冰风漫天 2020-01-12
  • 打赏
  • 举报
回复
问题提的还不够具体 什么情况下会丢失数据? 数据流中还有其他字节存在0x7e、0x0d的值是吗? 多个数据流是会合在一起过来的是吧?字节流间会不会混杂其他类型的数据?

111,094

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧