【问题标题】:QSerialPort::readLine doesn't work as expected on MS WindowsQSerialPort::readLine 在 MS Windows 上无法按预期工作
【发布时间】:2013-12-15 07:50:14
【问题描述】:

我正在尝试通过 USB 串行电缆将微控制器与我的台式电脑连接。 我台式电脑的操作系统是 Windows 8.1,USB 串口线是 TTL-232R-3V3。 (FTDI) (Qt 版本:5.2.0 beta1,QtCreator 版本:3.0,编译器:MSVC2012)

现在我正在尝试读/写环回测试,这就是 USB 串行电缆的 RX/TX 引脚相互连接的原因。

这是我的代码。

#include <QtCore/QCoreApplication>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QtCore/QDebug>

#define PORT_NAME "COM3"
#define BAUDRATE 19600
#define TIMEOUT_MS 1000

QT_USE_NAMESPACE
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QSerialPort pSerial(PORT_NAME);
    const char strMsg[] = "#1:Send data line \n #2:Send data line\n #3:Send data line end\n";
    char strBuf[256];
    qint64 nByte;


    if(pSerial.open(QIODevice::ReadWrite)){
        pSerial.setBaudRate(BAUDRATE);
        qDebug() << "OPEN PASS";

        pSerial.write(strMsg);
        pSerial.flush();
        if(pSerial.waitForBytesWritten(TIMEOUT_MS)){
            qDebug() << "WRITE PASS";
        }


        pSerial.waitForReadyRead(TIMEOUT_MS);
        while(true){
            if( pSerial.canReadLine()){
                qDebug() << "CAN READ LINE";
                nByte = pSerial.readLine(strBuf,sizeof(strBuf));
                qDebug() << "Length: " << nByte;
                qDebug() << "Read data: " << strBuf;

            }
        }
        pSerial.close();
    } else {
        qDebug() << "OPEN FAIL\n";
    }
    return a.exec();
}

当程序开始运行时,结果与我预期的不同。 只能接收发送数据的第一行。因此,打印“读取数据:#1 发送数据行” 在控制台上。但是将永远不会收到其余发送的数据。有谁知道为什么?

任何帮助将不胜感激。 提前致谢。

编辑:我根据 Papp 的评论修改了我的代码。然后它按我的预期工作。 已收到所有发送的消息。

这是否意味着我误解了 readLine() 或 canReadLine() 的用法?

//        while(true){
//            if( pSerial.canReadLine()){
//                qDebug() << "CAN READ LINE";
//                nByte = pSerial.readLine(strBuf,sizeof(strBuf));
//                qDebug() << "Length: " << nByte;
//                qDebug() << "Read data: " << strBuf;
//            }
//        }

        pSerial.waitForReadyRead(TIMEOUT_MS);
        QByteArray readData = pSerial.readAll();
        while (pSerial.waitForReadyRead(TIMEOUT_MS)) {
            readData.append(pSerial.readAll());
        }
        qDebug() << "Read data: " << readData;

第二次编辑:以下代码也适用于我。

while(true){
    if( pSerial.waitForReadyRead(TIMEOUT_MS) && pSerial.canReadLine()){ // I revised this line
        qDebug() << "CAN READ LINE";
        nByte = pSerial.readLine(strBuf,sizeof(strBuf));
        qDebug() << "Length: " << nByte;
        qDebug() << "Read data: " << strBuf;
        qDebug() << "Error Message: " << pSerial.errorString();

    }
}

【问题讨论】:

  • 流量控制?你禁用了吗?
  • @JoeZ 感谢您的评论。起初,我没有分配任何关于流控制的标志。然后我添加了以下代码。但它对我不起作用。 pSerial.setFlowControl(QSerialPort::SoftwareControl);或 pSerial.setFlowControl(QSerialPort::NoFlowControl);
  • @yufit_in_Japan:我给了+1,但是您是否尝试过循环读取,例如:QByteArray readData = serialPort.readAll(); while (serialPort.waitForReadyRead(5000)) readData.append(serialPort.readAll());这样的事情是否有效,即我们可以确保它真的是一个 readLine 问题吗?另外,它适用于 Unix 吗?第二次nByte的值是多少?您是否检查了 errorString 以防万一它不成功,或者它以零字符成功?顺便说一句,您的代码中的错误管理相当草率。
  • @LaszloPapp :非常感谢。根据您的评论,我修改了源代码。虽然我不明白为什么会出现问题,但我可以取得进展。
  • @LaszloPapp :当我在 Ubuntu 13.10 上尝试相同的代码(readline() 版本)时,它可以正常工作。这个结果与 MS Windows 的结果不同。(我后来修改了这个评论,因为它被证明是一个错误。)

标签: c++ qt serial-port qtserialport


【解决方案1】:

那是因为你需要像这样循环读取:

QByteArray readData = serialPort.readAll();
while (serialPort.waitForReadyRead(5000))
    readData.append(serialPort.readAll());

请参阅creadersync 示例了解我添加到 5.2 的详细信息。您还可以查看creaderasync 示例以了解非阻塞操作。

公平地说,我们还没有对 readLine 进行太多测试,但它在 Unix 上对我有用,在 Windows 上也适用于其他人。

【讨论】:

  • 这对阅读线有什么帮助??这个答案完全没有抓住重点。
  • 好斗而无知的库巴又回来了。 :( 我真的看不出什么“完全没有抓住重点”。事实上,OP 有两种不同的解决方案应该在这个回复中起作用,他甚至对此感到高兴。请在这个网站上保持建设性。
  • OP 在读行代码时遇到了问题。您的回答根本没有解决这个问题,您提供了一个忽略行阅读方面的不同解决方案。当然,这是有效的代码,但与行阅读无关。在我的书中,这没有抓住重点。我不知道如何指出明显且明显可见的事实被认为具有侵略性或无知。
  • @KubaOber:您的回答没有建设性,并且您错误地指出了一些“明显”的内容。此外,答案明确写道它应该与 readLine() 以及测试的不同操作系统一起使用,但由于它不适用于 OP,因此答案提供了一个可行的解决方案肯定,以便 OP 可以在最坏的情况下进行。有了你的回答,他就会一直卡住。下次请不要把“明显”点错。
【解决方案2】:

您所犯的错误是期望在waitForReadyRead 返回时收到所有发送的数据。当waitForReadyRead 完成时,您可以保证一些数据 可供读取。可能只有一个字符,不一定是整行。

您上次修改的循环是几乎正确的方法。您应该在单独的循环中嵌套读取行。下面的代码是应该怎么做的,符合QIODevice的语义:

while (pSerial.waitForReadyRead(TIMEOUT_MS)) {
  while (pSerial.canReadLine()) {
    qDebug() << "NEW LINE";
    QByteArray line = pSerial.readLine();
    qDebug() << "Length: " << line.size();
    qDebug() << "Read data: " << line;
    qDebug() << "Error Message: " << pSerial.errorString();
  }
}
qDebug << "TIMED OUT";

请注意,这些代码甚至都不应该在 GUI 线程中运行。理想情况下,您应该将其移至 QObject,使用QIODevice(以及QSerialPort)发出的信号,然后将该对象移至单独的线程。

GUI 线程有时会长时间阻塞,通常不希望它干扰设备通信的及时性。同样,您不希望设备超时阻塞 GUI 线程。两者都同样糟糕,并且是糟糕的用户体验的常见来源。 Qt 使多线程变得非常容易 - 为了您的用户而利用它,并正确地使用它。

【讨论】:

  • 您真的阅读过 OP 写的内容吗?您的假设没有任何意义,因为写入发生在同步操作中,而且:OP 只得到一行。我不明白这个答案的重点。更不用说,ui 线程与非 ui 线程在这里是一个红鲱鱼。这与 canReadLine 和 readLine 没有任何关系,因为它应该在这两种情况下都有效。
  • @LaszloPapp:问题是关于阅读线的,您的答案中没有提到阅读线。写入是同步的这一事实并不意味着什么。仅仅因为同步写入已“返回”并不意味着字节实际上已在环回场景中移动到接收缓冲区。哎呀,这甚至不意味着他们已经离开了 USB 主机。 UI 线程的提及是相关的——我指出不应该将阻塞代码放在那里。它可能适用也可能不适用,我只是以防万一。
  • 您真的不听,无论是 OP 还是我:正如所写,OP 收到了一行(并且随机地,因为您的回答错误地假设)。最终,您的代码甚至更糟:它不会等待输入超过某个超时,这不是 OP 想要的。此外,提及所有与手头实际问题无关的想象和理论案例是多余的。
  • s/随机/非随机/
猜你喜欢
  • 2017-05-15
  • 1970-01-01
  • 2019-01-15
  • 2014-10-20
  • 2021-08-13
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多