0

我被迫在 Qt 中编写一些代码,让传感器与现有的 Qt 代码集成。否则,我已经使用 pyserial 库用非常简单的 Python 代码测试了读取的传感器数据,它就像一个魅力。不幸的是,我不由自主地陷入了Qt框架这个复杂的泥潭。

硬件:传感器通过 USB 转串口适配器插入 Raspberry Pi 4 上的 USB 端口。

传感器配置为每 1 秒输出一行 RS-232 数据,作为以“\r”(CR,ASCII 13)而不是“\n”(LF,ASCII 10)结尾的 ASCII 字符。

这是我的代码:

#include <QCoreApplication>
#include <QThread>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/qserialportinfo.h>
#include <QList>
#include <QString>
#include <stdio.h>
#include <iostream>
#include <QtCore/QDataStream>

static QString sensor = "";
static QList<QSerialPortInfo> portList;
static QSerialPortInfo sensorport;
static QSerialPort s_sensor;

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);
    
    portList = QSerialPortInfo::availablePorts();

    int size = portList.size();
    const auto portnames = portList[1];

    std::cout << "Number of ports: " << size << "\n";
    for(int i=0;i<size;i++)
    {
        std::cout << portList[i].portName().toStdString() << " " << portList[i].description().toStdString() << "\n";
        if(portList[i].portName().toStdString()=="ttyUSB0"&&portList[i].description().toStdString()=="USB-Serial Controller D")
        {
            sensor.append(portList[i].portName());
            sensorport = portList[i];

        }

    }
    std::cout << sensor.toStdString() << "\n";
    std::cout << sensorport.manufacturer().toStdString() << "\n";
    s_sensor.setPort(sensorport);
    std::cout << s_sensor.open(QIODevice::ReadOnly) << "\n";
    std::cout << s_sensor.portName().toStdString() << "\n";
    std::cout << s_sensor.parity() << "\n";
    std::cout << s_sensor.baudRate() << "\n";
    std::cout << s_sensor.dataBits() << "\n";
    std::cout << s_sensor.stopBits() << "\n";
    std::cout << s_sensor.isOpen() << "\n";
    //std::cout << s_sensor.canReadLine() << "\n";

    //char buf[1024];
    //QString buff;
    static QByteArray byteArray;

    while(s_sensor.isOpen())
        {
            //QByteArray byteArray;
            if(s_sensor.waitForReadyRead())
            {
                byteArray += s_sensor.readAll();
            }

            if(QString(byteArray).contains('\r'))
            {
                QString data = QString(byteArray);//.remove("*");
                byteArray.clear();
                std::cout << "End of line\n";
                std::cout << data.toStdString() << "\n";
            }
            else
            {
                //std::cout << "None\n";
            }

//            if(s_sensor.waitForReadyRead() && s_sensor.bytesAvailable()>=18)
//            {
//                //std::string ll = s_sensor.readAll().toStdString();
//                //std::cout << ll << "\n";
//                qint64 len = s_sensor.readLine(buf,1024);
//                //QString bb = s_sensor.readAll();
//                std::cout << "Num of bytes: " << len << "\n";
//                //std::cout << "Num of bytes: " << sizeof(bb) << "\n";
//                std::cout << buf << "\n";
//                //std::cout << bb.toStdString() << "\n";
//                std::cout << "inner Yes" << "\n";
//                //break;
//            }
            //buff = buf;
            //std::cout << buff.toStdString() << "\n";
            //std::cout << "outer Yes" << "\n";
            //qint64 windline = s_sensor.readLine(buf, sizeof(buf));

        }

    //std::cout << buff.toStdString() << "\n";

    return app.exec();
}

该代码显示了许多连续试验的层,如许多不同的注释代码行所示。

当前的代码不会运行。项目构建完成后,Application Output 窗口将永远显示“Starting (...) ...”。这是添加这些的结果:

int main(int argc, char** argv)
{
     QCoreApplication app(argc, argv)

     return app.exec();
}

添加这些行是为了消除一个奇怪的警告“QSocketNotifier:只能用于以 QThread 开头的线程”。在网上广泛搜索后,我在 SO 上找到了一个答案,说包括 QCoreApplication 来创建事件循环。好吧,添加这些行当然消除了奇怪的警告,但现在我的程序甚至没有启动。

在上述步骤之前,我只有以下内容:

int main()
{
     //QCoreApplication app(argc, argv)

     //return app.exec();
}

我一直收到奇怪的警告,但我一直忽略它。但另一方面,我的程序运行成功。

但是,在我得到任何输出之前仍然有很长的延迟。构建后的典型等待时间约为 2-3 分钟!

而使用 pyserial 的简单 Python 代码,我在编译后立即得到输出,并且每一行输出都与传感器的 1 秒输出间隔完美同步。这是理想的工作方式。

readLine()我尝试了和的所有组合readAll()。没有指定行尾字符的选项。默认值为“\n”。我终于找到了两种读取每一行数据的替代方法。您可以看到上述两种方式的代码。第一种方法是我不断添加新的传入字符byteArray并检查 '\r' 字符。第二种方法是我指定一行数据的字节大小并读取它。

我不知道我是否在这里做一些根本错误的事情,导致执行延迟很长。在最初的 3 分钟延迟之后,一大堆数据被吐出,然后它继续吐出数据,但没有以任何方式与 1 秒的间隔同步。

4

1 回答 1

0

我认为您可能遇到的问题是事件循环没有运行。您可以尝试查看阻塞从机或从机的串行端口示例以获得一些灵感。

另一种方法是尝试将信号连接到串行端口的就绪读取并使用它来处理响应。

因此,不要使用 while 循环,而是使用如下内容:

    if (!s_sensor.open(QIODevice::ReadWrite)) {
        std::cout << s_sensor.portName().toStdString() << s_sensor.error();
    } else {
        std::cout << "port is open";
    }

    QObject::connect(&s_sensor, &QSerialPort::readyRead, [] () {
        std::cout << "ready read";

        static QByteArray byteArray;
        byteArray += s_sensor.readAll();

        if(QString(byteArray).contains('\r'))
        {
            QString data = QString(byteArray);//.remove("*");
            byteArray.clear();
            std::cout << "End of line\n";
            std::cout << data.toStdString() << "\n";
        }
        else
        {
            std::cout << "None\n";
        }
    });

并确保以下行也被启用:

     QCoreApplication app(argc, argv)

     return app.exec();
于 2021-09-02T10:21:41.423 回答