zoukankan      html  css  js  c++  java
  • 串口数据帧同步

    串口数据帧同步

    介绍

    串口是十分常用的一个资源, 每次需要进行处理串口数据, 但是 PC 上的串口存在缓冲区机制, 导致串口跟我们在单片机中的使用方式可能有所不同,
    每次拿到缓冲区数据之后,判断是否满足帧头,进而开始新的一帧数据计数存储, 最终满足一帧数据之后 将数据发送出来.

    原理

    我们使用自定义的存储结果 作为自己的存储结果, 一般来说在项目中使用就是帧数据长度是一致的, 我们的程序也是基于这个原理的

    class SerialData
    {
        public:
        uchar *data_;   ///< 帧数据
        uchar *head_;   ///< 帧头数据
        int dat_len_;   ///< 数据帧长度
    }

    我们需要根据自己的协议初始化数据长度和数据帧头内容 假设我们的数据为 14 个字节 包括 一般使用串口通信的数据都是按照这种格式进行的数据发送,

    [帧头] [长度] [地址] [指令] [数据] [校验]
    00 01 02 03 04 05 06 07 08 09 10 11 12 13
    68 0D 00 84 00 04 09 11 79 45 00 81 13 01

    frame_len = 14;
    data_ = new uchar[frame_len];               ///< 存储数据
    head_ = new uchar[4]{ 0x68,0x0D,0x00,0x84 }; ///< 旧版协议头

    实际上我们确定通信协议之后,PC不存在命令之类的解析的话,可以把前面四个字节处理帧头,
    每次接收到帧头四个字节的时候表示数据已经重新开始了一帧,将收集到的数据存储相应的流程即可,继续处理后续数据

    1. 如果数据正常, 读取到帧头数据之后,假设帧头数据一致, 数据依次往后填充数据,等到数组填满,会再次获取到帧头数据
    2. 根据上一帧的状态码, 确定当前值, 如果满足设定的四个值, 满足帧头数据, 处理后续字节
    3. 将数据与帧头数组依次比较,使用 $flg_status$ 记录上一次匹配的位置, 如果不一致, 置零, 下次重新开始,
    4. 每次判断四个字节一致之后, $flg_status$ 累加到了 4 , 这时候进行 数据校验, 根据结果,将当前数据帧的值 压入队列中,
    5. 以上方法会导致第一帧校验失败,但是后续的帧处理结果可以保证不会出现问题, 相当于将四个字符作为了帧尾处理
        static int data_cnt = 0;
        static int flg_status = 0;  // 0 普通数据,与数据头1 比较, 1 数据头1,2 数据头2, 3 数据头3,
                                    // 每次将缓冲区 数据全部读出来,
                                    // 判断上一帧读取到了什么状态, 数据分为 前4个字节的帧头数据和 后面的数据
                                    // 1.读取到了帧头 // 2. 读取到了一般数据帧
                                    // 每次计数, 读取到帧头的时候, 判断数据是否已经满了, 已经满了进行数据校验, 满足就加入数据
                                    // 数据未满, 则可能数据未满, 
        QByteArray recv = serial_->readAll();   // QSerial  读取的数据类型是 QByteArrray
        int N = recv.size();
        if (recv.isEmpty())
        {
            Sleep(5);   // 休眠5毫秒
            LError("recv data is empty");
            return false;
        }
        // 遍历得到的数据数组
        for (int i = 0; i < N; i++)
        {
            uchar tmp = char2uchar(recv[i]);
    
            // 每次来了数据与上次的置位比较, 如果一致, 比较后一位, 
            //  如果前面4位都一致,表示已经开始了新的一帧, 将数据依次复制
            //    如果数据已经满足帧头, 将之前的数据 校验满足之后加入队列中, 其他线程处理
            if (tmp == m_Frame.head_[flg_status])
            {
                flg_status++;
                if (flg_status == 4)
                {
                    // 由于存在每次存入数据的时候存在上一帧的数据 问题 所以这里校验可能失败
                    m_read_queue_->Push(m_Frame);
                    // 更新前面4个字节的帧头数据
                    for (int i = 0; i < 4; i++)
                        m_Frame.data_[i] = m_Frame.head_[i];
                    // 匹配重新置零, 同时将数据前面数据复制过去
                    flg_status = 0;
                }
            }
            else
            {
                flg_status = 0; // 如果前面的匹配上了, 后面匹配不上, 则重新开始进行匹配
            }
            m_Frame.data_[data_cnt++] = tmp;    // 移动指针, 将数据存储到数组中
            // 超过设定值, 减去一个长度,避免越界  // 与取与操作 % 处理一致 
            // 重新开始的位置 从可以刷新的数据开始
            if (data_cnt == m_Frame.dat_len_)
                data_cnt = 0;
        }

    更多

    这个程序是自己目前在使用的方法,简单有效, 适用于串口通信的数据处理,十分好用, 这个算是项目文档 的一部分,后续可能再拓展, 但是基本框架不变, 测试起来也很好用

    自己测试过程可以使用 VSPD虚拟串口 6.9 汉化版 模拟出来两个相连的串口,初始设置一下就好, 然后使用普通的串口调试软件打开两个串口即可进行通信,十分方便,

    参考链接

  • 相关阅读:
    Android AlertDialog警告对话框实现
    Android状态栏通知Status Bar Notification
    Android spinner控件的实现
    Winform之UI后台线程
    Winform之自定义控件
    WebForm原理,aspx服务器端与客户端源码比较
    IHttpModule之闲扯
    [算法]方正面试题:N×N矩阵螺旋打印输出
    DOTA版设计模式——工厂方法
    Window服务
  • 原文地址:https://www.cnblogs.com/hugochen1024/p/12570783.html
Copyright © 2011-2022 走看看