介绍
绑定QSerialPort对象的readyRead信号时,从串口接收缓冲区读取的数据大概率不是一次就能接收完成的,有可能分成n次接收;这是一种什么情况呢,它有可能多次readyRead:1次,2次,3次,4次……这样子!如果不对数据的边界进行有效识别,就很难分别出哪些是我们要的数据

定长协议
比如接收够15个字节才算接收完成,可以用QSerialPort::bytesAvailable这个接口进行组包,理论上给出头部标记就能识别有效的一帧数据:$ 10 0123456789 CS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #define MAX_SIZE 15
QByteArray buffer; int size = 0; auto callback = [&]() { auto &&data = this->readData(); if(data.startsWith("$")) { size = m_serial->bytesAvailable(); buffer.clear(); buffer += data; if(size == MAX_SIZE) { size = 0; emit this->sendOneFrame(buffer); } } else { size += m_serial->bytesAvailable(); buffer += data; if(size == MAX_SIZE) { size = 0; emit this->sendOneFrame(buffer); } } };
connect(m_serial, &QSerialPort::readyRead, this, callback);
|
不定长协议
这个需要识别数据的边界(头部跟尾部)在哪里,比如用$头部,@做尾部,我们把分段的数据依次拼接起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| QByteArray buffer; auto callback = [&]() { qDebug() << m_serial->bytesAvailable(); auto &&data = this->readData(); if(data.startsWith("$")) { buffer.clear(); buffer += data; if(data.endsWith("@")) { emit this->sendOneFrame(buffer); } qDebug() << "1 : " << buffer; } else { if(!data.endsWith("@")) { buffer += data; qDebug() << "2 : " << buffer; } else { buffer += data; qDebug() << "3 : " << buffer; emit this->sendOneFrame(buffer); } } }; connect(m_serial, &QSerialPort::readyRead, this, callback);
|
总结
串口数据解析本质是一个文本处理的过程,如果接收端用C语言写,简单的协议还好,复杂的协议简直要命(请用高级语言)!