Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QtSerialPort problems with the continuous reading of data from the serial port



  • Hi, I'm reading data from serial port with QT, in mainwindow I've write this code:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include<QTextStream>
    #include<QSerialPort>
    #include<QSerialPortInfo>
    #include<QtDebug>
    #include<QThread>
    QSerialPort *serial;
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent),
         ui(new Ui::MainWindow),
          m_standardOutput(stdout)
    {
         ui->setupUi(this);
        serial= new QSerialPort(this);
        serial->setPortName("COM3");
        serial->setBaudRate(QSerialPort::Baud115200);
        serial->setDataBits(QSerialPort::Data8);
        serial->setParity(QSerialPort::NoParity);
        serial->setStopBits(QSerialPort::OneStop);
        serial->setFlowControl(QSerialPort::NoFlowControl);
        serial->open(QIODevice::ReadOnly);
    
    
    
        connect(serial, &QSerialPort::readyRead, this, &MainWindow::ReaderH);
    
        float HUM;
         HUM=H;
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::ReaderH()
    {
    
            quint64 X=20;
        serial->waitForReadyRead();
        m_readData=serial->QSerialPort::read(X);
        //if (!m_timer.isActive())
          //     m_timer.start(5000);
         inter2=QString(m_readData);
        QStringList firstlist2= inter2.split(";");
        m_readData3=firstlist2.takeFirst();
        H=m_readData3.toFloat();
         qDebug() <<"Data:"<<m_readData<< " \r\n";
        //QThread::sleep(11);
    
    
    }
    

    the program reads the data correctly for a few seconds, after a while the reading starts to be out of phase, like this:

    Data: "60.904655;25.779804$"

    Data: "60.970406;25.816269$"

    Data: "60.988335;25.798037$"

    Data: "60."

    Data: "883736;25.7"

    Data: "61570$"

    Data: "60."

    Data: "91063"

    Data: "7;25.779804$"

    Data: "60."

    Data: "934544;25."

    Data: "798037$"

    Data: "60"

    Data: ".871784;25.798037$"

    I can't understand how to solve the problem. Thank you for your time.


  • Moderators

    @MatteoB
    you have to accumulate your data, THERE IS NO GUARANTEE that all data is in the serial port buffer, when ready read is emitted.

    also, do not call waitForReady read, inside the slot, that is connected to the signal, bad things may happen

    mockup code:

    #include <QCoreApplication>
    
    #include <QSerialPort>
    #include <QDebug>
    
    QSerialPort serial;
    int sendIndex(-1);
    
    static const QVector<QByteArray> toSend{
        {"Command1"},
        {"Command2"},
        {"Command3"},
    };
    
    void writeNextCommand(){
        sendIndex++;
        if(sendIndex < toSend.size()){
            serial.write(toSend.at(sendIndex));
        } else {
            qDebug() << "All Send";
        }
    }
    
    QByteArray receivedData;
    void onReadyRead(){
        receivedData += serial.readAll();
    
        //Your own logic, that ba is complete and correct
    
        //--
        qDebug() << "onReadyRead: new bytes:" << receivedData.toHex(' ');
    
        //if(dataOK(receivedData))
        writeNextCommand();
    }
    
    qint64 bytesWrittenSoFar(0);
    void onBytesWritten(qint64 bytesWritten){
        bytesWrittenSoFar += bytesWritten;
        if( bytesWrittenSoFar == toSend.at(sendIndex).size()){
            qDebug() << QString("All bytes (%1) of the command send, expecting now answer").arg(bytesWrittenSoFar);
            bytesWrittenSoFar = 0;
        }else
            qDebug() << bytesWrittenSoFar << " of" << toSend.at(sendIndex).size();
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        //Setup Port
    
        QObject::connect(&serial, &QSerialPort::bytesWritten,&onBytesWritten);
        QObject::connect(&serial, &QSerialPort::readyRead, &onReadyRead);
    
        serial.setPortName("PortX");
       /*
        serial.setParity();
        serial.setBaudRate();
        serial.setDataBits();
        serial.setStopBits();
        serial.setFlowControl();
        */
        if(serial.open(QIODevice::ReadWrite)){
            writeNextCommand();
        } else {
            qDebug() << "Could not open Serialport";
        }
    
        return a.exec();
    }
    
    


  • @MatteoB
    Similarities to the discussion currently on-going in https://forum.qt.io/topic/117717/qserialport-waitforreadyread-exits-with-timeou

    connect(serial, &QSerialPort::readyRead, this, &MainWindow::ReaderH);
    ...
    void MainWindow::ReaderH()
    {
        serial->waitForReadyRead();
    ...
    

    Absolutely not! Do not make the blocking waitForReadyRead(); inside the non-blocking QSerialPort::readyRead slot! Do not make any blocking calls if you are using the asynchronous signals/slots, or vice versa.

    I do not know whether this is the cause of your behaviour or not, but start by picking one or the other (preferably the async non-block signals), and stick to them alone :)

    EDIT Post crossed with that from @J-Hilk . Use his code approach.



  • @MatteoB in addition to all the previous suggestions, you may want to try/study the serial port examples, in particular the Terminal one.



  • @MatteoB said in QtSerialPort problems with the continuous reading of data from the serial port:

    void MainWindow::ReaderH()
    {
    quint64 X=20;
    serial->waitForReadyRead();
    m_readData=serial->QSerialPort::read(X);
    //if (!m_timer.isActive())
    // m_timer.start(5000);
    inter2=QString(m_readData);
    QStringList firstlist2= inter2.split(";");
    m_readData3=firstlist2.takeFirst();
    H=m_readData3.toFloat();
    qDebug() <<"Data:"<<m_readData<< " \r\n";
    //QThread::sleep(11);
    }

    I think you have 2 problems with your implementation:

    • first: mixing pooling mode functions (waitForReadyRead() / waitForBytesWritten()) and asynchronous functions (readyRead() / bytesWritten()) is not recommended
    • second: a serial port link is a stream interface and not a packet interface. So you have to know how to detect message begin and end from this stream. When you read data, you may read the full message or just a part of it!

    So you code cannot work properly!
    I support your messages ends with $, so you could do something like this:

    void MainWindow::ReaderH()
    {
        // I support m_readData is a QByteArray
        while(serial->bytesAvailable())
        {
            m_readData.append(serial->readall());
        }
        int idx=0;
        while( (idx=m_readData.indexOf('$')) >= 0 )
        {
            if(idx > 0)
            {
               auto message = QString(m_readData.left(idx));
               qDebug() << "Message:"<< message << " \r\n";
            }
            m_readData.remove(0, idx+1);
        }
    }
    

Log in to reply