QT Serial Port Reading

14,359

Most IO functions in Qt are asynchronous. This means that readAll() does not wait for data to arrive. Instead, it returns currently available data (data that can be read from the device without waiting). Currently, You are just calling readAll in an endless loop (this makes the thread, spend all its time in this loop, unable to receive the new data that may have arrived. . .)

You need to call readAll only when you know that new data has arrived. This can be accomplished in two ways:

  • Non-blocking Asynchronous Way:

    Use the readyRead() signal to get notified when new data is available in the device instead of looping forever. This is how you should do most stuff in Qt, In order to be able to act upon multiple events that may arrive at any time. Your code can be rewritten like this:

    #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,
                         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;
            a.quit();
        });
    
        return a.exec();
        //     ^^^^^^^^
        //very important: starts the Qt main event loop
        //this makes all asynchronous stuff possible
    }
    
  • Blocking Synchronous Way:

    Use waitForReadyRead() to block the thread until new data arrives to the serial port. This makes the calling thread unable to do anything until new data arrives on this serial port. If this thread was a GUI thread, This will make the application unresponsive during that period of time. Use this approach only when you are sure this is what you want. Your code can be rewritten like this:

    #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;
    }
    
Share:
14,359
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    I am trying to read the data sent by a device plug via usb. First i read the data via this command

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

    And the data are like this

    TGPHI_s -0,24 =
    
    MESURES2 BT 4 SUP36 A
    
    PTCOUR2 HPH /
    

    Now i want to read the data via a Qt5.3 program

    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;
    

    and the answer is ->

    "/dev/ttyUSB0"
    0
    Serial port is open...
    Arrived data: 0
    Serial port is open...
    Arrived data: 0
    

    So there is no data catch by my program ... My questions are :

    • Did i miss something in the setting of the QSerialPort ?
    • If no why there is no data display via the qDebug()

    EDIT

    Thanks to mike i can finaly read this usb device !!! here is my final code

        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();