【Qt开发】串口通信收不到QSerialPort::readyRead信号的问题

Qt的QSerialPort模块,提供了通过串口与硬件通信的功能。Qt程序利用QSerialPort,通过串口与硬件通信的步骤一般是:

  1. 通过QSerialPortInfo::availablePorts()接口列举所有可用串口
  2. 选择硬件对应的串口
  3. 创建QSerialPort的实例:QSerialPort port = new QSerialPort(portName)
  4. 配置串口,比如波特率之类的:port->setBaudRate(QSerialPort::Baud19200);
  5. 打开串口:port->open(QIODevice::ReadWrite),根据open的返回结果,判断串口是否打开成功
  6. 利用SIGNALreadyRead()判断硬件是否发送了数据
  7. 收到signal后,利用port->readAll()读取缓存中的所有数据
  8. 对数据完成解析,然后使用数据

代码如下

QList<QSerialPortInfo> ports = QSerialPortInfo:::availablePorts();
// 假设ports不为空
QString targetPortName = ports.first().portName();

QSerialPort *port = new QSerialPort(targetPortName);
port->setBaudRate(QSerialPort::Baud19200);
if(!port->open(QIODevice::ReadWrite)) {
    // open serial port failed
}

connect(port, &QSerialPort::readyRead, this, [=](){
    QByteArray data = port->readAll();
    decode(data); // 自定义解码数据
});

我在项目中使用上述代码一直没有问题,都能正常读取并解析数据,直到一次硬件更新,忽然无法从硬件获取数据了

通过排查发现,readyRead Signal不再被触发了,改成以轮询的方式读取后果然还是能够读到数据,并正确解析的。轮询方式如下:

while(true) {
    QByteArray data = port->readAll();
    decode(data);
}

这种方式虽然可以读取到数据,但即便使用多线程,对系统资源的占用也明显太高了,没有从根本上解决问题。

那么造成无法从硬件获取数据的根本原因是什么呢? 为什么之前work的代码,硬件更新后就无法正常工作了?难道是硬件的锅?

通过跟硬件团队沟通,发现原因在于打开串口时,串口的缓存已经满了,导致硬件不能再写入输入,也就不会触发readReadySignal了,这个问题其他人也有提到过,比如这个

那为了解决这个问题,有两种解决方案:

  1. 判断buffer是否已经满了,如果满了就读取数据
  2. 每次开始读取之前,先清空buffer

前者可以利用winbase.h中的EV_RX80FULL。Qt虽然可以使用winbase.h中的接口,但毕竟不太方便,而且可能需要重构原来使用QSerialPort模块的代码。

因此最后采用方案2,QSerialPort模块提供了接口clear(),作用是:

Discards all characters from the output or input buffer, depending on given directions directions. This includes clearing the internal class buffers and the UART (driver) buffers.

在开始读取数据之前,利用该接口清空buffer数据,硬件就可以继续写数据,并触发readReadySignal。

代码如下

QList<QSerialPortInfo> ports = QSerialPortInfo:::availablePorts();
// 假设ports不为空
QString targetPortName = ports.first().portName();

QSerialPort *port = new QSerialPort(targetPortName);
port->setBaudRate(QSerialPort::Baud19200);
if(!port->open(QIODevice::ReadWrite)) {
    // open serial port failed
}

port->clear(QSerialPort::AllDirections);

connect(port, &QSerialPort::readyRead, this, [=](){
    QByteArray data = port->readAll();
    decode(data); // 自定义解码数据
});

至此,问题解决。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值