Qt串口通信中如何实现十六进制帧数据的读写?
Qt串口十六进制读写问题分析与修正方案
我来帮你一步步梳理代码里的问题,然后教你怎么正确实现Qt串口的十六进制读写~
先说说你代码里的几个明显问题
- 重复打开串口:在读取数据的分支里,你居然又调用了
serial->open(QIODevice::ReadWrite)——这时候串口已经处于打开状态,重复调用open不仅会失败,还会打乱串口的正常状态,完全没必要。 - 同步读取不可靠:你用
if (serial->bytesAvailable())同步判断有没有数据,这根本不靠谱,串口数据是异步传输的,发送完数据后,设备的返回不会立刻到达,你的代码大概率会跳过读取逻辑,啥也读不到。 - 十六进制显示不直观:你直接输出
QByteArray,qDebug会把可打印字符显示成普通字符,不可打印的显示成转义符,没法直观看到十六进制格式的数据。
修正后的完整实现方案
1. 先配置好串口并连接信号槽
Qt串口的正确姿势是用信号槽监听readyRead()信号,一旦有数据到达就自动触发读取操作,这是异步IO的标准做法。
假设你的类里有一个QSerialPort *serial成员,在类的构造函数里做这些初始化:
// 初始化串口(这里假设你已经配置好波特率、数据位等参数) serial = new QSerialPort(this); // 连接readyRead信号到自定义的读取槽函数 connect(serial, &QSerialPort::readyRead, this, &YourClassName::onSerialReadyRead);
2. 正确的十六进制发送逻辑
发送十六进制字节的思路是对的,但要注意十进制和十六进制的区别,还要加错误判断:
if (serial->isOpen()) { qDebug() << "开始发送数据"; // 注意:这里的0xA1、0xFF是十六进制,如果你想发送十六进制的0x97,要写成0x97,而不是十进制的97(97对应0x61,是ASCII的'a') static const char sendBuff[] = {0xA1, 0xFF, 0xFF, 0x00, 0x61}; qint64 writtenBytes = serial->write(sendBuff, sizeof(sendBuff)); if (writtenBytes == -1) { qDebug() << "发送失败:" << serial->errorString(); } else { qDebug() << "成功发送" << writtenBytes << "字节"; serial->flush(); // 强制把数据写入串口,避免缓存 } } else { qDebug() << "串口未连接:" << serial->errorString(); }
3. 异步读取并转换成十六进制显示
实现刚才连接的槽函数,读取数据后转换成十六进制字符串输出,方便查看:
void YourClassName::onSerialReadyRead() { if (!serial->isOpen()) { qDebug() << "错误:串口未打开"; return; } QByteArray receivedData = serial->readAll(); // 把原始字节转换成带空格分隔的大写十六进制字符串,直观显示 qDebug() << "收到的十六进制数据:" << receivedData.toHex(' ').toUpper(); // 如果需要处理固定长度的数据包,可以在这里缓存数据,比如: // static QByteArray cache; // cache.append(receivedData); // if (cache.size() >= 你需要的长度) { // // 处理完整数据包 // cache = cache.mid(你需要的长度); // 移除已处理的数据 // } }
几个关键注意事项
- 串口参数必须匹配:波特率、数据位、停止位、奇偶校验这些参数,必须和你连接的设备完全一致,否则会出现乱码或者根本读不到数据。
- 区分十进制和十六进制:写字节的时候,
97是十进制,对应十六进制0x61;如果要发送十六进制的0x97,一定要写成0x97,别搞混了。 - 避免同步阻塞:不要用循环等待
bytesAvailable()的方式读取数据,Qt的异步信号槽机制才是最可靠的。
内容的提问来源于stack exchange,提问作者meth
相关产品推荐
相关产品推荐

