在使用Qt自带的串口QtSerialPort时。其发送过来的数据需要进行接收,则需要连接一个相应的槽函数:
connect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));// 有数据就直接接收显示
其中只要是串口中有数据,便会执行slots_serialRxCallback()槽函数,并不是说一帧数据发送完了,才执行一次slots_serialRxCallback()函数。而是接收一部分数据进入一次回调处理函数。
很显然,无法形成一个完整的数据帧就无法进行数据处理。
通过测试单片机利用串口发送数据,一次能够接收33个字节,要上报的数据是48个字节,因此接收数据就会先接收33个字节,再接收15个字节。这就导致了一个问题,两次接收的数据被后续的数据处理函数认为是两个字符串,无法进行通信协议判断。
因此如何将这两次接收的数据拼接为一个完整的数据帧是解决这个问题的要点,另外说明一下,虚拟串口调试,48个字节QT是可以一次性接收的,但是单片机发出来的就不行。有知道其中原因的大佬可以评论留言。
如何拼接呢?经过实验测试,我找到了一个比较简单的方法,不用什么定时器延时接收。
第一步:接收数据触发数据处理槽函数slots_serialRxCallback()
第二步:在触发后断开槽函数数据接收,同时延时5毫秒。
disconnect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback())); while (currentPort->waitForReadyRead(5) == true);
上面这两步是必须的,如果不断开接收槽函数,就会一直进入接收数据处理,造成程序异常,引起死机。延时五毫秒之后。
第三步:在触发接收后,调用一次waitForReadyRead,等待5ms。再重新进入数据接收,将后半串数据进行接收。
connect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));
我们在头文件中定义
QByteArray myData2; QByteArray rxbuf;
rxbuf = myData2.append(currentPort -> readAll());
rxbuf是拼接成的完整数据帧,myData2是用来存放第一次接收的数据,再readAll。
第四步:将第一次的缓存数据清空用于接收第二次数据,如果不清空这个数组,那么再下一次接收的数据到来时就会进行累加。会随着接收数据量的增加越加越长。
myData2.clear();
经过上述处理就能得到一个完整的数据帧了。
如果不能理解,我为大家列出其流程图,让你直观感受这么处理的妙处。
回调函数如下:
- /**
- * @brief PLCTempControl::slots_serialRxCallback 接收并先更新温度
- * 接收数据格式位34 D0 88 FF FF 3C 01 79 3C 01 7C 3C 01 77 3C 01 71 3C 01 C8 3C 01 A1 3C 01 A9 3C 01 82 3C 01 82 3C 01 70 3C 01 76 3C 01 71 3C 01 6B 01 00 05 5E
- */
- void PLCTempControl::slots_serialRxCallback()
- {
- disconnect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));// 有数据就直接接收显示
- while (currentPort->waitForReadyRead(5) == true);
- connect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));// 有数据就直接接收显示
- rxbuf = myData2.append(currentPort -> readAll());//读串口缓区QByteArray数据 关键是append
- myData2.clear();
- if (!rxbuf.isEmpty())
- {
- qDebug()<<"接收处理函数";
- qDebug()<<rxbuf.toHex(' ');
- }
- if(this->isDataEffective(rxbuf))//判断校验码是否正确,是位真,不是为假。
- {
- switch( (quint8)rxbuf.at(2) )
- {
- case 0x88:
- quint8 tmp1 = rxbuf.at(6); //tmp1高8位
- quint8 tmp2 = rxbuf.at(7); //tmp2低8位
- qint16 y1 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(9); //tmp1低8位
- tmp2 = rxbuf.at(10); //tmp2高8位
- qint16 y2 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(12); //tmp1低8位
- tmp2 = rxbuf.at(13); //tmp2高8位
- qint16 y3 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(15); //tmp1低8位
- tmp2 = rxbuf.at(16); //tmp2高8位
- qint16 y4 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(18); //tmp1低8位
- tmp2 = rxbuf.at(19); //tmp2高8位
- qint16 y5 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(21); //tmp1低8位
- tmp2 = rxbuf.at(22); //tmp2高8位
- qint16 y6 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(24); //tmp1低8位
- tmp2 = rxbuf.at(25); //tmp2高8位
- qint16 y7 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(27); //tmp1低8位
- tmp2 = rxbuf.at(28); //tmp2高8位
- qint16 y8 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(30); //tmp1低8位
- tmp2 = rxbuf.at(31); //tmp2高8位
- qint16 y9 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(33); //tmp1低8位
- tmp2 = rxbuf.at(34); //tmp2高8位
- qint16 y10 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(36); //tmp1低8位
- tmp2 = rxbuf.at(37); //tmp2高8位
- qint16 y11 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(39); //tmp1低8位
- tmp2 = rxbuf.at(40); //tmp2高8位
- qint16 y12 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(42); //tmp1低8位
- tmp2 = rxbuf.at(43); //tmp2高8位
- qint16 y13 = (qint16)((tmp1<<8)|(tmp2<<0));
- tmp1 = rxbuf.at(45); //tmp1低8位
- tmp2 = rxbuf.at(46); //tmp2高8位
- qint16 y14 = (qint16)((tmp1<<8)|(tmp2<<0));
- this -> tempDisplay(y1, y2, y3, y4, y5, y6, y7,
- y8, y9, y10, y11, y12, y13, y14);//温度显示函数
- break;
- }
- }
- }
- /**
- * @brief PLCTempControl::isDataEffective 检查校验码,验证数据是否有效
- * @param rxbuf
- * @return
- */
- bool PLCTempControl::isDataEffective(QByteArray &rxbuf)
- {
- QByteArray rxbuffer;
- rxbuffer.resize(48);//申明一个数组存储接收数据
- rxbuf.resize(48);
- static quint8 count = 0;
- static quint8 state = 0;
- static quint8 checksum = 0;
- for(int8_t i = 0;i < 48; i++)
- {
- quint8 res = rxbuf.at(i);
- res = res;
- switch(state)
- {
- case 0:
- if(res == 0x44){
- count = 0;
- rxbuffer[count] = res;
- count++;
- state = 1;
- qDebug()<<"首位校验";
- }else{
- count = 0;
- state = 0;
- }
- break;
- case 1:
- if(res ==0xD0){
- rxbuffer[count] = res;
- count++;
- state = 2;
- qDebug()<<"D0位校验";
- }else{
- count = 0;
- state = 0;
- }
- break;
- case 2:
- rxbuffer[count] = res;
- count++;
- if(count>=47)state = 3;
- break;
- case 3:
- rxbuffer[count] = res;
- checksum = 0;
- for(quint8 i = 0;i < count; i++)
- {
- checksum+=rxbuffer.at(i);
- }
- if(res == checksum)
- {
- return true;
- qDebug()<<"校验和成功";
- }
- state=0;
- count=0;
- break;
- default:break;
- }
- }
- return false;
- }
利用QLabl控件,将文字改为图片,要注意载入图片的大小,不然显示不全。
联系客服