2

我正在开发一个从 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

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...
}
4

3 回答 3

0

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

“当数据在打开时到达设备时,QSP 可能会忽略所有读取事件。在这种情况下,即使重新打开设备也无济于事。原因是 QWinOverlappedIoNotifier 在调用 startAsyncCommunication() 之后启用,这可能, 导致忽略所有 EV_RXCHAR 事件。解决方法是在调用任何 I/O 操作之前启用通知程序。” - Denis Shienkov,QSerialPort 维护者

于 2018-04-09T14:12:09.937 回答
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,则函数不会超时。

于 2018-03-20T07:25:17.607 回答
0

卡在 IOCTL_SERIAL_WAIT_ON_MASK

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

于 2018-03-21T10:36:17.600 回答