QT串口读取

4

我正在尝试通过USB读取设备插头发送的数据。

首先,我通过以下命令读取数据:

  • sudo stty -F /dev/ttyUSB0 1200 sane parenb evenp cs7 -crtscts
  • cat /dev/ttyUSB0

数据的格式如下:

TGPHI_s -0,24 =

MESURES2 BT 4 SUP36 A

PTCOUR2 HPH /

现在我想通过一个Qt5.3程序读取数据

QSerialPort serial;
serial.setPortName("ttyUSB0");
if(!serial.setBaudRate(QSerialPort::Baud1200 , QSerialPort::Input))
    qDebug() << serial.errorString();
if(!serial.setDataBits(QSerialPort::Data7))
    qDebug() << serial.errorString();
if(!serial.setParity(QSerialPort::EvenParity))
    qDebug() << serial.errorString();
if(!serial.setFlowControl(QSerialPort::HardwareControl))
    qDebug() << serial.errorString();
if(!serial.setStopBits(QSerialPort::OneStop))
    qDebug() << serial.errorString();
if(!serial.open(QIODevice::ReadOnly))
    qDebug() << serial.errorString();
qDebug() << serial.bytesAvailable();
while(true)
{
    if (serial.isOpen()) {
        qDebug() << "Serial port is open...";
        QByteArray datas = serial.readAll();
        if (datas.size() == 0) {
            qDebug() << "Arrived data: 0";
        } else {
            for (int i = 0; i < datas.size(); i++){
                if (datas.at(i)) {
                    qDebug() << datas[i];
                }
            }
        }

    } else {
        qDebug() << "OPEN ERROR: " << serial.errorString();
    }
}
return 0;

答案是 ->
"/dev/ttyUSB0"
0
Serial port is open...
Arrived data: 0
Serial port is open...
Arrived data: 0

所以我的程序没有捕获到任何数据......

  • 我在QSerialPort的设置中错过了什么吗?
  • 如果没有,为什么没有通过qDebug()显示数据?

编辑

感谢Mike,我终于可以读取这个USB设备!!!以下是我的最终代码:

    QSerialPort serial;
serial.setPortName("ttyUSB0");
if(!serial.setBaudRate(QSerialPort::Baud1200))
    qDebug() << serial.errorString();
if(!serial.setDataBits(QSerialPort::Data7))
    qDebug() << serial.errorString();
if(!serial.setParity(QSerialPort::EvenParity))
    qDebug() << serial.errorString();
if(!serial.setFlowControl(QSerialPort::HardwareControl))
    qDebug() << serial.errorString();
if(!serial.setStopBits(QSerialPort::OneStop))
    qDebug() << serial.errorString();
if(!serial.open(QIODevice::ReadOnly))
    qDebug() << serial.errorString();
QObject::connect(&serial, &QSerialPort::readyRead, [&]
{
    //this is called when readyRead() is emitted
    //qDebug() << "New data available: " << serial.bytesAvailable();
    qDebug() << "New data available: " << serial.bytesAvailable();
    QByteArray datas = serial.readAll();
    qDebug() << datas;
});
QObject::connect(&serial,
                     static_cast<void(QSerialPort::*)(QSerialPort::SerialPortError)>
                     (&QSerialPort::error),
                     [&](QSerialPort::SerialPortError error)
{
    //this is called when a serial communication error occurs
    qDebug() << "An error occured: " << error;
    return qApp->quit();
});


if(!serial.open(QIODevice::ReadOnly))
    qDebug() << serial.errorString();
return qApp->exec();
1个回答

9

Qt 中的大多数 IO 函数都是异步的。这意味着 readAll() 不会等待数据到达。相反,它返回当前可用的数据(可以从设备读取而无需等待的数据)。目前,您只是在一个无限循环中调用 readAll(这使线程在此循环中花费所有时间,无法接收可能已到达的新数据...)

只有在知道有新数据到达时才需要调用 readAll。这可以通过两种方式实现:

非阻塞异步方式:

使用 readyRead() 信号来通知您设备上有新数据可用,而不是永远循环。这是您应该在 Qt 中完成大部分工作的方式,以便能够对可能随时到达的多个事件进行操作。您的代码可以重写为:

    #include <QtSerialPort>

    int main(int argc, char* argv[]){
        QCoreApplication a(argc, argv);
        QSerialPort serial;
        serial.setPortName("ttyUSB0");
        if(!serial.setBaudRate(QSerialPort::Baud1200))
            qDebug() << serial.errorString();
        if(!serial.setDataBits(QSerialPort::Data7))
            qDebug() << serial.errorString();
        if(!serial.setParity(QSerialPort::EvenParity))
            qDebug() << serial.errorString();
        if(!serial.setFlowControl(QSerialPort::HardwareControl))
            qDebug() << serial.errorString();
        if(!serial.setStopBits(QSerialPort::OneStop))
            qDebug() << serial.errorString();
        if(!serial.open(QIODevice::ReadOnly))
            qDebug() << serial.errorString();
        QObject::connect(&serial, &QSerialPort::readyRead, [&]
        {
            //this is called when readyRead() is emitted
            qDebug() << "New data available: " << serial.bytesAvailable();
            QByteArray datas = serial.readAll();
            qDebug() << datas;
        });
        QObject::connect(&serial,
                         &QSerialPort::errorOccurred,
                         [&](QSerialPort::SerialPortError error)
        {
            //this is called when a serial communication error occurs
            qDebug() << "An error occured: " << error;
            a.quit();
        });

        return a.exec();
        //     ^^^^^^^^
        //very important: starts the Qt main event loop
        //this makes all asynchronous stuff possible
    }

阻塞同步方式:

使用 waitForReadyRead() 阻塞线程,直到串口接收到新数据。这会使调用线程无法做任何事情,直到该串口接收到新数据。如果该线程是 GUI 线程,则在此期间应用程序将变得无响应。仅在确定需要时才使用此方法。您的代码可以重写为:

    #include <QtSerialPort>

    int main(int argc, char* argv[]){
        QCoreApplication a(argc, argv);
        QSerialPort serial;
        serial.setPortName("ttyUSB0");
        if(!serial.setBaudRate(QSerialPort::Baud1200))
            qDebug() << serial.errorString();
        if(!serial.setDataBits(QSerialPort::Data7))
            qDebug() << serial.errorString();
        if(!serial.setParity(QSerialPort::EvenParity))
            qDebug() << serial.errorString();
        if(!serial.setFlowControl(QSerialPort::HardwareControl))
            qDebug() << serial.errorString();
        if(!serial.setStopBits(QSerialPort::OneStop))
            qDebug() << serial.errorString();
        if(!serial.open(QIODevice::ReadOnly))
            qDebug() << serial.errorString();
        qDebug() << serial.bytesAvailable();
        while(serial.isOpen())
        {
            if(!serial.waitForReadyRead(-1)) //block until new data arrives
                qDebug() << "error: " << serial.errorString();
            else{
                qDebug() << "New data available: " << serial.bytesAvailable();
                QByteArray datas = serial.readAll();
                qDebug() << datas;
            }
        }
        return 0;
    }

感谢您的回复,但问题始终存在,即没有数据显示。我采用了异步方式,唯一得到的是这个:http://pastebin.com/RW7PVNMN在每个“New data available: 1”之间有一个空格。也许这是由于参数(波特率、数据位等)引起的。您认为这是否与stty命令的选项匹配? - tlebreton
@tlebreton,我已经改变了输出方式,这可以更好地表示接收到的数据(从而帮助弄清楚发生了什么)。 我认为参数是相同的。也许尝试使用serial.setStopBits(QSerialPort::TwoStop)而不是一个停止位,因为我不确定sanestty中如何设置它。 - Mike
我发现了我的错误(真是丢人)。在setBaudRate中,我不需要QSerialPort :: Input。有了它,什么也没有显示,没有它,我得到了我想要的一切。感谢你的帮助Mike,我很感激。 - tlebreton
@tlebreton,不客气。但我不明白为什么这会引起问题。据我所知,这意味着波特率设置仅适用于输入数据(即正在读取的数据),这应该是我们的目标,不是吗?无论如何,我已经更新了答案 :) - Mike
@Mike 我在使用异步方式时遇到以下错误:static_cast 从类型 QSerialPort::SerialPortError (QSerialPort ::*)() const 转换到类型 void (QSerialPort::*)(QSerialPort::SerialPortError) 是无效的,你能帮我吗? - ruda
@ruda,你是对的。在Qt6中,信号QAbstractSocket::error已被移除,并被QAbstractSocket::errorOccurred取代。这消除了丑陋的转换需求。请查看我的更新答案... - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接