介绍

绑定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语言写,简单的协议还好,复杂的协议简直要命(请用高级语言)!


© 2025 hywing 使用 Stellar 创建
总访问 113701 次 | 本页访问 326