qt之接收数据处理方式(补全断包数据)

一、前言

为什么写这个博客呢,因为我发现在qt中不论用到什么通信方式,最后处理数据的方法都是一样的,蓝牙数据接收,串口数据接收,网口数据接收,can数据接收,wifi通信(即网口)数据接收,基本都是一个套路完成的接口函数,然后去处理数据,这次写个模板出来不用每次都去查找以前的程序了,也怪费劲的。

二、环境

qt5.7 mingw windows8

三、正文

各种模板如下,如后期有新型,也会更新出来

第一步 都是通过各种接口函数,把识别到的一包或者连续几包接收打包起来,到一个QByteArray中去,然后在开启一个函数,

void MainWindow::comBatAnalyze(QByteArray &allData)

去传递这个QByteArray(单次接收全部数据)

不带CRC16 MODBUS校验方式:

1.将全部数据转换为16进制字节类型:

优点:数据内容清晰明确,类似于stm32接收数据处理判断。

缺点:数据定长、也可以自行处理申请动态数组,事先判断数据长度

方法:

void MainWindow::comBatAnalyze(QByteArray &allData)
{
    unsigned char rxdata[100];
    int len;
    bool ok;
    memset(rxdata,0,100);//清空数组
    QByteArray dataTemp=allData;
    len=dataTemp.count();
    for(int i=0;i

2.直接判断字符串形式:

优点:数据长度飘忽不定时,没有稳定数据格式,可采用此方式让数据一直累加判断

缺点:写起来麻烦一些,只能判断固定长度数据(因通讯原因而断开的)

方法:

void MainWindow::comBatAnalyze(QByteArray &allData)
{
    QByteArray dataTemp;
    int len;
    int start;
    int move;
    bool ok;
    dataTemp=allData;
    while((len=dataTemp.count())>=37*2)
    {
      QCoreApplication::processEvents(QEventLoop::AllEvents, 200);
      move=2;
      start=dataTemp.indexOf("42",0);//搜索42字符,返回搜索到的起始位置
      if(start>=0)
      {
         len=len-start;//将42做为开头,长度随之变化
         dataTemp=dataTemp.right(len);//从右侧裁剪len长度数据保存
         if(len>=37*2)
         {          
         if(dataTemp.mid(0,2)=="42"&&dataTemp.mid(10,2)=="43"&&dataTemp.mid(22,2))//判断开头是否为effeef
           {
               if(dataTemp.mid(36,2)=="58"&&dataTemp.mid(46,2)=="2e"&&dataTemp.mid(52,2)=="5a"&&dataTemp.mid(60,2)=="2e"&&dataTemp.mid(72,2)=="25")//dian
               {
                    //...
                    move=37*2;
                    dataTemp=dataTemp.right(len-move);
                    if((len-move)>37*2){
                        dataTemp.clear();
                        allData.clear();
                    }
               }
               else{
                    dataTemp.clear();
                    break;
               }
             }
             else{
                 dataTemp.clear();
                 break;
             }
         }
         else{
            break;
         }
      }
      else{
         dataTemp.clear();
         break;
      }
    }
    allData=dataTemp;
}

带CRC校验方式:

带crc校验就不能用以上的方式了,因为需要数据的每个字节去分析,方式如下:

void MainWindow::comBatAnalyze(QByteArray &allData)
{
    QByteArray dataTemp;
    bool ok;
    int len;
    int start;
    dataTemp=allData;
    while((len=dataTemp.count())>=25*2)
    {
      QCoreApplication::processEvents(QEventLoop::AllEvents);
      start=dataTemp.indexOf("fe0414",0);//返回该字节数组中字节数组fe第一次出现的索引位置,然后从索引位置向前搜索。
      if(start>=0){
         len=len-start;
         dataTemp=dataTemp.right(len);
         if(len>=25*2){
           if(dataTemp.mid(0,6)=="fe0414"){
               dataTemp=dataTemp.left(50);//只处理一组即可,取前25字节
               QCoreApplication::processEvents(QEventLoop::AllEvents);
               QByteArray ccc;//crc用
               quint16 ddd;//crc用
               for(int i=0;i<25;i++){
                   ccc[i]=dataTemp.mid(i*2,2).toInt(&ok,16);
                   if(i==22)ddd=crc16ForModbus(ccc);//获取到前23位crc校验码
               }
               if((ccc[23]==ddd)&&(ccc[24]==(ddd>>8))){//校验crc
                    //...校验通过,处理数据
               }
           }
           dataTemp.clear();
         }
         else{
            break;
         }
      }
      else{
         dataTemp.clear();
         break;
      }
    }
    allData=dataTemp;
}

CRC方式参考我这个帖子中的代码。


20221128增加串口接收数据断包补全

优点:可以补全因通讯原因造成的数据断包

缺点:大量数据时无法使用此方法

原理:在通讯接口接收中断有数据时,建立的定时器开启10ms中断,这时候10ms串口过来的数据会在全局QByteArray数组中补全,10ms之后将数组传入到处理函数中,基本就是全的了,如果不全就适当调增延时时间,大量数据时可能不适用,未测试大数据

方法:

头文件:

    QSerialPort *serial1;//串口句柄
    QByteArray allData1;
    QTimer *timeserial1;

函数文件:

  //初始化部分
  timeserial1=new QTimer(this);
    connect(timeserial1,&QTimer::timeout,[=](){
        timeserial1->stop();
        comBatAnalyze1(allData1);//处理串口得到的数据
    });

//串口中断槽函数
void menu::serialRead1()
{
//    static QByteArray allData;
    timeserial1->start(10);//设置判断10ms内接收完毕数据,在处理
    while (!serial1->atEnd()){
        allData1 += serial1->readAll().toHex();
    }
}
//串口处理函数
void menu::comBatAnalyze1(QByteArray &allData)
{
    QByteArray dataTemp;
    bool ok;
    int len=0;
    int start;
    int move;
    dataTemp=allData.toUpper();
    len=dataTemp.size()/2;
    qDebug()<

可以发现,接收全了,只要不是发送特别快连包,就能单次处理,如果连包,可以按照上面第二种方式将数据组合判断帧头处理

//后续更新会继续更新本篇博客

四、结语

记录,分享,查询,让我们成为 搬运工而不只是获取者。

你可能感兴趣的:(#,qt数据处理/算法类,qt,crc,qt数据处理,qt接收数据)