当前位置:   article > 正文

Qt 和 MCU 的串口通讯(完整帧)_qt串口帧类型

qt串口帧类型

前言:

        最近一段时间在做有关串口通讯的Qt项目,其中与MCU STM32那部分的通讯比较令人头疼,因为MCU处理的是HEX16进制数,而Qt应用更多的倾向于对字符串的处理,经过这段时间的痛苦而又煎熬的摸索,也算是有所新的认识。在这中秋佳节即将来临之际,也得空写点关于这方面的心得,算是一个记录笔记吧。

介绍:

项目情况

MCU STM32控制端:

几个控制按键挂在MCU上,随着按键的动作相应地发出指定数据帧,通过串口RX/TX传给ARM板端,Qt应用作出相应动作。

ARM Qt显示应用端:

需要Qt的应用能够接受到MCU 发出的数据帧,并且解析出有用的数据,进行相应动作。

MCU那边的串口通讯我就不说了,应该比较常见。我着重讲一下Qt这边怎么处理一个完整的数据帧。

相关知识点

一个完整的数据帧,包括帧头、标识符、数据长度、数据块、校验和帧尾等,比如:

帧头各种标识...数据长度数据块校验帧尾
FFEE...12数据长度个字节**AA

串口通讯中,以商议好的数据帧形式发送和接受数据,能够有效的避免数据接受不完整,接受错误。使用指定形式的数据帧是一种有效、准确的通讯方式。

校验

数据在传输过程中,可能会存在数据出错的情况。为了保证数据传输的正确性,因此会采取一些方法来判断数据是否正确,或者在数据出错的时候及时发现进行改正。常用的几种数据校验方式有奇偶校验、CRC校验、LRC校验、格雷码校验、和校验、异或校验等。

一般串口通讯中常用到的校验有CRC32、CRC16、和校验或是异或校验等。如果大家有兴趣可以多找一找这方面的资料看看,我在这里就不多做赘述。讲的比较详细:

https://blog.csdn.net/zhengqijun_/article/details/53150749

划重点————————————————————————————————————————————————————

Qt 解析完整数据帧

MCU发出的是16进制数据帧,Qt善于处理QString的字符串。

我先说一下Qt 解析部分大概思路:1. 串口读取为二进制字节组---QByteArray;2. 将QByteArray 写入数据流QDataStream,而后从中按一个一个字节读取出,直到结束;3. 按数据帧协议处理一个字节一个字节,环环相扣,引入状态机机制,解析完整帧。

直接上代码。Talk is cheap, show me the code.

头文件声明:

  1. QString buffer;//串口接受数据缓冲区
  2. QString bufferdatalen;//数据长度两字节字符串缓存
  3. QString frameData;//
  4. uint8_t checkSum, SendBuf[200];//校验异或和
  5. ushort TxNum;
  6. int num;
  7. int state_machine;//协议解析状态机
  8. int lencnt, datalen;
  9. bool stopped;
  10. bool ok;

 

CPP文件解析函数一览:

  1. //读取串口数据帧并处理
  2. void SerialPortA::readMyComA(QByteArray temp)
  3. {
  4. QDataStream out(&temp, QIODevice::ReadWrite);
  5. // qDebug()<<"MyComA temp hex"<<temp.toHex();
  6. while (!out.atEnd()) {
  7. qint8 outChar = 0;
  8. out>>outChar;
  9. QString byte = QString("%1").arg(outChar&0xFF, 2, 16, QLatin1Char('0'));
  10. // qDebug()<<"byte"<<byte;
  11. byte = byte.toUpper();
  12. if(state_machine == 0)//协议解析状态机
  13. {
  14. if(byte == INC1)//起始符1
  15. state_machine = 1;
  16. else
  17. state_machine = 0;//状态机复位
  18. }
  19. else if(state_machine == 1)
  20. {
  21. if(byte == INC2)//起始符2
  22. state_machine = 2;
  23. else
  24. state_machine = 0;//状态机复位
  25. }
  26. else if(state_machine == 2)
  27. {
  28. if(byte == INC3)//起始符3
  29. state_machine = 3;
  30. else
  31. state_machine = 0;//状态机复位
  32. }
  33. else if(state_machine == 3)
  34. {
  35. if(byte == FRAMESTAR)//帧头
  36. state_machine = 4;//
  37. else
  38. state_machine = 0;
  39. }
  40. else if(state_machine == 4)
  41. {
  42. if(byte == FRAMETYPE)//帧类型
  43. {
  44. state_machine = 5;
  45. buffer = byte;
  46. }
  47. else
  48. state_machine = 0;
  49. }
  50. /×××××××××中间的部分按照各自的协议数据帧进行处理×××××××××××××/
  51. else if(state_machine == 12)//第一字节数据长度
  52. {
  53. buffer += byte;
  54. bufferdatalen = byte;
  55. state_machine = 13;
  56. }
  57. else if(state_machine == 13)//第二字节数据长度
  58. {
  59. buffer += byte;
  60. bufferdatalen += byte;
  61. lencnt = 0;//接收数据计数器
  62. datalen = bufferdatalen.toInt(&ok, 16);//接收数据长度
  63. // qDebug()<<"datalen is :"<<datalen<<"bufferdatalen"<<bufferdatalen;
  64. state_machine = 14;
  65. }
  66. else if((state_machine == 14) || (state_machine == 15))//接收一定长度的数据块
  67. {
  68. frameData += byte;//数据保存
  69. buffer += byte;
  70. if(lencnt == (datalen-1))
  71. state_machine = 16;
  72. else
  73. {
  74. state_machine = 15;
  75. ++lencnt;
  76. }
  77. }
  78. else if(state_machine == 16)//进行校验
  79. {
  80. TxNum = 0;
  81. if(buffer.isEmpty()) return;
  82. // buffer += "AA";//加上帧尾
  83. // qDebug()<<"用于计算校验位的字符串: "<<buffer;
  84. QByteArray temp;
  85. temp = QByteArray::fromHex(buffer.toLatin1().data());//获取buffer数据为字符串,需要转换成16进制
  86. QDataStream out(&temp, QIODevice::ReadWrite);//将字节组读入
  87. while(!out.atEnd())
  88. {
  89. qint8 outchar = 0;
  90. out >> outchar;//每字节填充一次,直到结束
  91. SendBuf[TxNum] = (uint8_t)(outchar & 0xff);
  92. TxNum++;
  93. }
  94. checkSum = (uint8_t)(myAlgorithm->Sum_Calculate(SendBuf, TxNum));//求帧头以外所有数据的校验和
  95. QString strSum = QString("%1").arg(checkSum&0xFF, 2, 16, QLatin1Char('0'));
  96. strSum = strSum.toUpper();
  97. byte = byte.toUpper();
  98. // qDebug()<<"Check SUM is :"<<strSum<<"Byte is:"<<byte;
  99. if(byte == strSum)//判断校验XOR是否相等
  100. {
  101. state_machine = 17;
  102. // qDebug()<<"!!!!!!!!!!!!!!!!!!!!!!!";
  103. sendOneFrame(CORRECT_RESPONSE);//校验无异常
  104. }
  105. else
  106. {
  107. state_machine = 0;
  108. sendOneFrame(ERROR_RESPONSE);//校验异常
  109. }
  110. }
  111. else if(state_machine == 17)
  112. {
  113. // qDebug()<<"*************"<<byte;
  114. if((byte == "AA") || (byte == "aa")) //判断是否接收到帧尾结束符
  115. {
  116. // qDebug()<<"frame data :"<<frameData<<"buffer"<<buffer;
  117. // qDebug()<<"MyComA Receive Frame End AA!!!";
  118. /****************数据块8字节分析*********************/
  119. byte8Analysis(frameData);
  120. /*****************数据块8字节分析********************/
  121. }
  122. frameData = "";
  123. buffer = "";
  124. state_machine = 0;//状态机复位
  125. }
  126. }
  127. }

校验计算函数

  1. uint8_t Algorithm::Sum_Calculate(uint8_t *puchMsg, uint16_t usDataLen)
  2. {
  3. uint8_t CRCValue=0;
  4. uint16_t i=0;
  5. for ( i=0; i<usDataLen; i++ )
  6. {
  7. CRCValue = puchMsg[i] ^ CRCValue;//进行异或校验取值
  8. }
  9. return CRCValue;
  10. }

解析部分,按照自身协商的数据帧,实际情况进行处理分析。大概的思路已经给出。

在此,也感特别谢@yuxiangs的转发博客给予的思路:

https://blog.csdn.net/yilongdashi/article/details/80449315#comments

 

以上仅是个人对qt中串口使用的大概了解,各位有补充的欢迎留言指导及斧正,谢谢大家,预祝大家中秋佳节快乐。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/510609
推荐阅读
相关标签
  

闽ICP备14008679号