串口接收数据分包问题处理(QT上位机/单片机等)

2023-11-08

串口数据出现分包如何正确完整接收

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

串口通信在QT上位机以及单片机或者安卓串口等使用情况下,经常容易出现一包数据分成几包的情况下,如何快速将这些分散的数据拼成完整一包相信很多单片机以及串口相关的开发人员都会遇到,可能很多简单的方式都能实现,但是一个有效耐得住考验少丢数据的方法也是很重要的。`

一、设计思路

1.数据的格式是头0XA4 0X4A 尾部是0X3C 0X3C,里面包含数据数据长度和帧校验等相关定义,本文只从头尾如何顺利提取到每一包。
2.思路1是每一次数据到来将数据保存起来,然后识别里面是否有尾部,如果没有,等待下一次,这样数据缓冲会越来越多,索引尾部多少会有点慢.
3.现在改为每来一次数据,识别当前数据是否有尾部,如果有,则认为当前数据是一包,则再将缓冲数据进行头部识别,识别不到头,证明是错误数据,不进行处理。识别成功,则调用相应处理函数。若数据中没有尾部,则将数据放入缓存。若数据最后一位是0X3C,则做好标记,下一包数据来临时优先判断第一个字节是不是0X3C。
若单次接收包含了多包数据也应能处理。

二、代码参考

QT代码参考
代码如下(示例):

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    void setupPlot();
    void setCVMode();
    void setCCMode();
    void initActionsConnections();

private slots:

    void updateView();
    void updateLCDNumber();
    void handleTimeout();

    void showStatusMessage(const QString &message);
    void about();
    void openSerialPort();
    void closeSerialPort();
    void writeData(const QByteArray &data);
    void readData();
    void SerialRecv_solt();
    void process_serial_recv(char *pBuf,int len);
    void ComSend( unsigned char cmd1, int var1);
    int get_tail(unsigned char *pbuf,int len);
    int get_head(unsigned char *pbuf,int len);
    int send_copy_from_read(unsigned char *pbuf,int len);
    int process_pack(unsigned char* pbuf,int len);

    void on_doubleSpinBox_vol_valueChanged(double arg1);
    void on_doubleSpinBox_cur_valueChanged(double arg1);
    void on_radioButton_cv_clicked();
    void on_radioButton_cc_clicked();
    void on_pushButton_verify_clicked();
    void on_verticalSlider_vol_valueChanged(int value);
    void on_verticalSlider_cur_valueChanged(int value);
    void on_actionCtrl_triggered(bool checked);
    void on_actionUpdate_triggered();

private:
    Ui::MainWindow *ui;
    QSerialPort *serial;
    SettingsDialog *settings;
    QVector<double> vol, cur;
    QTimer *m_pTimer;

    unsigned char data_recv[1024];
    int len_pack=0;
    int maybe_tail;//疑似拿到了尾部一个字节
};
int MainWindow::get_tail(unsigned char *pbuf,int len)
{
    int i=0;
    int pos;
    for(i=0;i<len;i++)
    {
        if(pbuf[i]==0xc3)
        {
            if(i==(len-1))
            { 
              return 0;//疑似拿到了尾部一个字节
            }
            else
            {
               if(pbuf[i+1]==0xc3)
               pos=i+2;//第几个字节出现了尾部
               return pos;//完整的拿到了尾部
            }
        }
    }
    return -1;//没有拿到尾部任何信息
}
/**
 * @brief 获取头的位置
 * @param  pbuf              [in/out]
 * @param  len               [in/out]
 * @return int 
 */
int MainWindow::get_head(unsigned char *pbuf,int len)
{
    int i=0;
    for(i=0;i<len;i++)
    {
        if((pbuf[i]==0xA5)&&(i<(len-1)))
        {
          if(pbuf[i+1]==0x5A)
          return i; 
        }
    }
    return -1;//没有头部信息
      
}

int MainWindow:: process_pack(unsigned char* pbuf,int len)
{
    int pos_head=0;
    memcpy(data_recv+len_pack,pbuf,len); 
    len_pack+=len;

   pos_head=get_head(data_recv,len_pack);
   if(pos_head>=0)//找到了头
   {
       send_copy_from_read(data_recv+pos_head,len_pack-pos_head);
       qDebug() << "hello";
   }
   
  //相关标志位清零
   maybe_tail=0;
   len_pack=0;  
}
/*------------------------ slot ----------------------------------------------*/
/**
  ******************************************************************************
  * @brief 串口数据接收处理
  ******************************************************************************
  **/
void  MainWindow::SerialRecv_solt()
{
    QByteArray    data;
    data.resize (serial->bytesAvailable());
    serial->read (data.data(),data.size());
    //int pos_tail=0;
    //int pos_head=0;
    int size_now=0;
    int pos_data=0;
    int data_num=0;
    size_now=data.size();
    if((maybe_tail==1)&&((unsigned char )data.data()[0]==0xc3))//识别到结束位
    {
        process_pack((unsigned char *)data.data(),1);
        //将当前包剩余的数据赋值给下一包 
        if(data.size()>1)
        {
          memcpy(data_recv+len_pack,&data.data()[1],(data.size()-1)); 
          len_pack+=(data.size()-1);
        }     
    }
    else
    {
        maybe_tail=0;        
          //size_now--剩余字节数
           while(size_now>0)
            { 
              pos_data=data.size()-size_now;
              data_num=get_tail((unsigned char *)data.data()+pos_data,size_now);
               if(data_num>0)//识别到结束位
               {
                  process_pack((unsigned char *)data.data()+pos_data,data_num);
                  size_now=data.size()-data_num; 
               }
               else//没有识别到结束位
               {
                   if(data_num==0)
                    maybe_tail=1;
                    if((len_pack+data.size())<1024)//限制缓冲大小为1024个字节
                    {
                        memcpy(data_recv+len_pack,data.data()+pos_data,size_now);
                        len_pack+=size_now;
                    }
                    else
                    {
                        len_pack=0;//从头开始
                    }
                   break;
               }  
            }       
        
    }
}

总结

该代码测试之后可以经过任意几包数据混合,断开发送,使用串口测试过。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

串口接收数据分包问题处理(QT上位机/单片机等) 的相关文章

随机推荐

  • 利用chatgpt实现三分钟快速制作自定义PPT

    目录 利用ChatGPT MindShow三分钟生成PPT 机器人 道合顺 莓用ai 百晓生 aichat 结合提词器以达到更好地提问效果 更好地提问ChatGPT 常用prompt表 小黄同学LL的博客 CSDN博客 举个栗子 利用Cha
  • 现代循环神经网络-门控循环单元(GRU)

    理论 门控隐状态 门控循环单元与普通的循环神经网络之间的关键区别在于 前者支持隐状态的门控 这意味着模型有专门的机制来确定应该何时更新隐状态 以及应该何时重置隐状态 这些机制是可学习的 并且能够解决了上面列出的问题 例如 如果第一个词元非常
  • stream().sorted 排序

    想用stream sorted 做双字段排序 list stream sorted Comparator comparing outObject gt outObject getinnerObject getAttribute revers
  • 责任链模式在项目中的引入使用

    责任链模式是一种设计模式 在责任链模式里 很多对象由每一个对象对其下家的引用而连接起来形成一条链 请求在这个链上传递 直到链上的某一个对象决定处理此请求 发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求 这使得系统可以在不影响客
  • mybatisPlus 枚举类注解 @EnumValue @JsonValue

    1 概要说明 创建枚举类 在需要存储数据库的属性上添加 EnumValue注解 在需要前端展示的属性上添加 JsonValue注解 2 示例实践 public enum SexEnum MAN 1 男 WOMAN 2 女 EnumValue
  • 使用FormData对象

    使用FormData对象 TABLE OF CONTENTS 创建一个FormData对象 使用HTML表单来初始化一个FormData对象 使用FormData对象发送文件 TAGS 文件 利用FormData对象 你可以使用一系列的键值
  • swagger介绍及使用

    文章目录 Swagger 概述 1 maven导入Swagger包 2 配置开启swagger2 3 测试swagger 4 配置swagger信息 5 配置swagger扫描接口 6 swagger分组与接口注释 Swagger 概述 S
  • rockemq创建topic

    sh mqadmin updateTopic n sms pro 007 9876 sms pro 008 9876 c DefaultCluster t smsFrontSmsMq 10 w 4 r 4
  • Java 每日面试题6( BufferReader, 对象序列化)

    BufferReader属于哪种流 主要是用来做什么 里面有哪些方法 BufferReader属于处理流中的缓冲流 可以将读取的内容存在内存里面 比Reader类多了一个readLine 方法 这篇博文提供了BufferReader类的详细
  • 传输层 —— TCP协议

    一 TCP 二 TCP报文段首部格式 1 序号 在一个TCP连接中传送的字节流中的每一个字节都按顺序编号 本字段表示本报文段所发送数据的第一个字节的序号 2 确认号 期望收到对方下一个报文段的第一
  • 【HTML】HTML5给网页音频带来的变化

    HTML HTML5给网页音频带来的变化 引言 内容速递 看了本文您能了解到的知识 音乐播放 相信大家都很熟悉 但是早在之前的音乐播放之前 你的浏览器会问你 是否下载flash插件 然而现在 估计一些年轻的开发者都不用了解flash是啥了
  • Jmeter压测接口全流程详解

    Jmeter压测接口全流程详解 描述 内容包含Jmeter压测软件的安装 环境变量配置 具体实例参数的配置 动态参数构建 元件引入 函数引入 监控插件引入 在京东云上的引用等 第一部分 Jmeter应用下载 一 Jmeter下载 进入官网
  • 一起学nRF51xx 8 -  Time

    前言 Nrf518xx的TIMER有以下几部分组成 nrf51822有三个定时器 time0 1 2 1 计数时钟源 有1M 16M 2种时钟源 2 时钟源分频器 用来设置分频 范围是2的0 9次方 3 定时 计数模式选择 用来配置TIME
  • 百度翻译爬虫-使用execjs库逆向解析百度翻译

    本文目标破解百度翻译接口 抓取翻译结果数据 python3安装execjs方法 pip install pyexecjs 检查页面 使用Chrome浏览器打开百度翻译 观察界面 右键查看源代码 发现密密麻麻全是看不懂JS代码 初步判定为是异
  • CVE-2017-11882漏洞复现

    本文记录一下针对CVE 2017 11882的漏洞复现 0x00 前言 参考backlion师傅的PDF 记录一下这个过程 2017年11月14日 微软发布了11月份的安全补丁更新 其中比较引人关注的莫过于悄然修复了潜伏17年之久的Offi
  • 详解c++---优先级队列和仿函数

    目录标题 什么是仿函数 如何定义一个仿函数 什么是优先级队列 优先级队列的使用 模拟实现priority queue 准备工作 top函数的实现 size函数的实现 empty函数的实现 adjustup函数的实现 push函数的实现 po
  • Opencv图像处理(全)

    文章目录 博主精品专栏导航 备注 以下源码均可运行 不同项目涉及的函数均有详细分析说明 11 图像项目实战 一 银行卡号识别 sort contours resize 二 文档扫描OCR识别 cv2 getPerspectiveTransf
  • IntelliJ IDEA 修改 idea64.exe.vmoptions文件修改错误导致软件打不开

    如果修改了idea64 exe vmoptions文件中的参数 然后导致idea打不开 那么此文一定能帮你解决问题 有的小伙伴出现此类问题之后 可能尝试的重装IntelliJ IDEA的方法 但是重装之后发现还是解决不了问题 还是会弹出如下
  • iOS开发判断版本号不同

    判断是否是第一次启动或者版本号不同时 NSString key CFBundleVersion 上一次打开的版本号 存储在沙盒中的版本号 NSString lastVersion NSUserDefaults standardUserDef
  • 串口接收数据分包问题处理(QT上位机/单片机等)

    串口数据出现分包如何正确完整接收 提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 设计思路 二 代码参考 总结 前言 串口通信在QT上位机以及单片机或者安卓串口等使用情况下 经常容易出现一包数据分成几包