处理高速数据时,避免在QSerialPort上超时

时间:2018-03-19 17:36:02

标签: c++ windows qt serial-port qt5.10

我正在开发一个从600Hz传感器接收数据的Windows应用程序。在五分之二的情况下,我的IO线程成功地从传感器读取4个字节的数据并将其传递给GUI线程。

问题是五次中的三次,QSerialPort有无法解释的超时,其中QSerialPort的waitForReadyRead()返回false而serial.errorString()有超时错误。在这种情况下,它永远不会读取数据。如果我从串行端口读取,尽管超时错误,我将在下一个waitForReadyRead中读取2000+字节的数据,这将以块的形式提供,这会使我的应用程序的实时数据接收方面过时。

我尝试使用串口的readyRead()信号,但它表现出相同的行为,即。如果出现超时错误,则不会触发readyRead()信号。

更新:我能够使用Qt的终端示例([QT_INSTALL_EXAMPLES] / serialport / terminal)重现该问题,该示例使用非阻塞读取。错误的频率相当低,但它仍然存在。

更新:使用串行端口监视器,我可以看到当它卡住时,Qt终端示例卡在IOCTL_SERIAL_WAIT_ON_MASK上,我的示例在IOCT_SERIAL_WAIT_ON_MASK之后卡在IRP_MJ_WRITE DOWN上。这种情况从未发生在其他终端软件上,这让我认为问题肯定与Qt有关。

Pastebin of Serial Port Monitor Output

void IOThread::run(){

QSerialPort serial;
serial.setPortName(portname)
serial.setBaudRage(QSerialPort::Baud115200);
serial.setStopBits(QSerialPort::OneStop)
serial.setParity(QSerialPort::NoParity);
serial.setDataBits(QSerialPort::Data8);
serial.setFlowControl(QSerialPort::NoFlowControl);

if(!serial.open(QIODevice::ReadWrite)
{
    qDebug() << "Error Opening Port";
    return;
}
else
{
    qDebug() << "Error Message: " << serial.errorString() // prints "Unknown Error"
}

while(true)
{
    if(serial.waitForReadyRead(1000))
    {
        qDebug() << "Normal read";
        reception_buffer = serial.readAll();
    }
    else
    {
        qDebug() << "Timeout";
        /* serial.readAll() here will read nothing but force next read to read huge chunk of data */ 
        continue;
    }
}

// Process data...
}

3 个答案:

答案 0 :(得分:0)

如果这有任何不同,请尝试:

while (true) {
    QByteArray reception_buffer;
    if (serial.waitForReadyRead(1000)) {
        reception_buffer = serial.readAll();
        while (serial.waitForReadyRead(10)) {
            reception_buffer += serial.readAll();
        }
        qDebug() << "reception_buffer ready";
    }
    else {
        qDebug() << "Timeout";
    }
}

如果您想阻止来自waitForReadyRead的超时,您可以设置:

if(serial.waitForReadyRead(-1))

bool QSerialPort::waitForReadyRead(int msecs = 30000)将在msecs毫秒后超时;默认超时为30000毫秒。如果msecs为-1,则该函数不会超时。

答案 1 :(得分:0)

  

卡在IOCTL_SERIAL_WAIT_ON_MASK

最可能的问题出在您的硬件或驱动程序中。 QSP使用基于WaitCommEvent的异步通知。如果WaitCommEvent卡住了 - 那么你的设备或驱动程序就会出现问题(最有可能)。

答案 2 :(得分:0)

感谢QSerialPort的工作人员,通过应用此补丁解决了Qt 5.10.1中的这个错误:https://codereview.qt-project.org/#/c/225277/

  

&#34;当数据到达设备时,QSP可能会忽略所有读取事件   开场。在这种情况下,即使重新打开设备也不会   救命。原因是之后启用了QWinOverlappedIoNotifier   比调用的startAsyncCommunication(),可能导致   忽略所有EV_RXCHAR事件。解决方法是启用   通知之前的通知程序,而不是任何称为I / O操作的通知程序。&#34; - Denis Shienkov,QSerialPort Maintainer