本书第10章开始是比较综合的模块
控件布局和逻辑控制方面在之前的布局实验上进行了一些拓展实现了串口设置,打开体温测量模式界面等相关的功能。
主要的代码和逻辑集中在对“人体参数检测系统”发来的数据包做处理的功能上。
介于本章是处理体温监测数据,我们先来认识一下体温相关的PCT协议
可以看到PCT协议下的数据包长度应该为10,每一位是一个0x00-0x7F之间的16进制数据。具体体温的数据是如何打包并且发送的,详细代码在前面的第6章中,这里简单介绍一下:实验硬件设备即人体参数检测系统有TEMP1和TEMP2两个通道,每个通道占用两个字节数据一共16位。有效范围为0~500,再除以10就是以摄氏度为单位的体温。(图片中也有解释↑↑↑)
接下来主要讲如何处理串口通信过来的内容。串口通信在第7章已经接触过一个比较类似的实验,但是在这里结合了实际解码数据包的内容。先来简单复习一下串口通信相关的内容。
串口通信的基本流程如图所示:
首先我们需要在.pro文件中导入用来通信的QSerialPort类
然后我们在mainwindow.h中先定义好一些相关的成员变量和成员函数,内容比较多我们后面在mainwindow.cpp中逐一讲解。
到这里可能有点迷糊了,为什么追上就表示超出2000的缓冲了?原因是在mainwindow.cpp中define了一个PACK_QUEUE_CNT参数用于参与包缓冲数量的计算,mPackHead参与在前面接受的包,mPackTail参与后面处理的包,unpackRcvData()负责在前面接受,dealRcvPackData()负责在后面处理。具体函数内部是怎么运行的,我们下面介绍。
我们直接快进到readSerial()函数的定义,readSerial()函数在前面initSerial()的时候已经被连接到readReady信号,比较好理解。readSerial()本身长这样:
首先读到串口一次发来的所有数据,然后返回一个QByteArray,存到mRxData中。只要mRxData中有东西,就进行解包和分类保存。
接下来看看proUARTData()里面是怎么运行的
proUARTData()取到每一个包的首地址,然后交给解包函数unpackRcvData()去处理,最后清空这一轮获取到的mRxData。解包函数内部结构如下:
首先调用了之前导入的packUnpack模块中的unpackData()函数进行解包,解包完成之后会返回true,解包失败后会返回false,mPackAfterUnpackArr可以缓存2000个数据包,每解包成功一个数据包,就将头指针向前以一位把这个数据包存进去,接下来尾指针可以获取已经缓存的数据包并且进行分类保存。
这里添加一个线程锁,确保mPackhead和mPackTail在改变的时候不会被其他部分访问到,从而发生混乱。(可以加入注释掉的两行代码看看是否和上面描述的结果相符。)
到这里接受数据包解包,并且把他缓存起来的工作已经做完了,接下来要做的就是看看他到底发过来了什么数据,我们要把他拿出来用,所以接着要完成的就是deakRcvPackData()函数:
和之前一样,设置函数自己的headIndex和tailIndex索引,值等于当前的串口进入数据的序号和待处理的数据的序号。由于head可能已经走完一轮到下一轮了,为了保证head始终在tail前面,这里要判断一下他俩的先后,如果head在后则:headIndex+PACK_QUEUE_CNT。
cnt是还没解析的数据包个数,在for循环中判断,如果数据包的模块ID是体温数据包的ID,调用analyzeTempData()解析这些数据包,解析完之后将mPackTail往前推cnt个单位。之前在刚接触PCT通讯协议的时候,也许还不太理解模块ID,二级ID有什么用,从这里开始就能体会到作用了。
analyzeTempData()的主要作用是判断TEMP1和TEMP2的导联状态以及获取实时体温数据,并且控制相关的控件展示这些数据:
红框中的代码是分析数据的关键,使用本教材的许多人可能比较少接触到按位运算,但是其实没有很复杂。数据包的第三个字节的最低位存放着TEMP1的导联状态,倒数第二位存放着TEMP2的导联状态。data & 0x01
表示将数据与0x01进行按位与操作。按位与操作的结果是,如果数据最低位为1,则结果为1;如果数据最低位为0,则结果为0。如果最低位为“1”,比较后返回false,反之返回true。也就是说0表示导联,1表示脱落。TEMP2同理,向右移动一位之后取出其导联状态。
这一部分将第4字节和第5字节数据拼在一起,获得一个16位的数据,这就是我们上面提到的以摄氏度为单位的体温的10倍,再除以10转换之后得到想要的数据。
到此为止,基本的获取数据,解包和解析分类存储的功能就实现了,是对前面每一个单元的独立小实验做了一个很好的串联和实战运用,并且理解这一章节的实验内容之后,也会给后面几章打下比较扎实的基础。涉及Qt的内容并不算是很多,主要还是一些逻辑处理可能比较不好理解,包括包的缓存,还有数据的解析。在不太清楚的时候,可以采用qDebug()来看看到底存了一些什么东西,也可以查看Qt官方文档,看看成员函数返回值和内部结构方便加深理解。