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

Serial terminal disconnecting unexpectedly



  • Hi,

    In my qt application I wanted to read data from a serial device every 3 seconds.
    Around 10 minutes the application is communicating with the device without any problem. But after some time there is no communication. If I am disconnecting and reconnecting the serial port then it will work. Why like this it is happening.
    Given below is my code

    void MainWindow::on_actionConnect_triggered()
    {
        if(openserialFlag)                                         //connect to the serial terminal when this flag set
        {
            serial = new QSerialPort(this);
    
            OldComport = m_settingsDialog->settings().comport;
            COMport =OldComport;
            slaveID = m_settingsDialog->settings().SlaveID;
            serial->setPortName(COMport);  /*comport to modbus*/
            serial->setBaudRate(QSerialPort::Baud9600);                  //baud rate
            serial->setDataBits(QSerialPort::Data8);                     //Data bit
            serial->setParity(QSerialPort::NoParity);                    //no parity
            serial->setStopBits(QSerialPort::OneStop);                   //one stop bit
            serial->setFlowControl(QSerialPort::NoFlowControl);
            if (serial->open(QIODevice::ReadWrite)) {                    //open the serial port in read write mode
                openserialFlag=0;
                serialopenflag=1;
                statusBar()->showMessage("Connected");
                ui->actionConnect->setEnabled(false);     //disable the connect button
                ui->actionDisconnect->setEnabled(true);   //enable the disconnect button
                QDateTime now = QDateTime::currentDateTime();
                QString timestamp = now.toString(("yyyyMMdd"));
                QString filename = QString::fromLatin1("C:/Users/alphy/Google Drive/PROJECTS-Alphy/QT-Projects/HITECH/160520_GUISmartModule/SmartModuleGUI/Log Data/%1.txt").arg(timestamp);
                logFile.setFileName(filename);
                if (logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
                {
                    fileWrtOpenFlag =1;
                }
                else
                {
                    statusBar()->showMessage("File open error");
                }
                connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));   //make the signal connecting to readdata slot
                connect(timer, SIGNAL(timeout()), this, SLOT(ReadRequest()));   //connect the timeout signal to readrequest slot
                timer->start(3000);                                             //start the timer timeout for every 2seconds
    
            } else {
                openserialFlag =1;
                QMessageBox::information(this,"Message","Device not connected");
            }
        }
    }
    void MainWindow::readData()
    {
        //    timer->stop();
        //    readflag =1;
        QTextStream streamIn(&logFile), streamOut(&logFile);
    
        bool  ampMinFlag=0, amphrHlag=0, datareceivedFlag =0;
        float fmyvolage =0, fmycurrent =0,fmyAmpMin =0,fmyAmphr =0,fmyAmptotalizer =0;
        uint32_t u32myvolage =0,u32mycurrent =0,u32myAmpMin =0, u32myAmphr =0,u32myAmptotalizer =0;
        char *ProfName;
        uint8_t ProftimeHr =0, ProftimeMin =0, ProfElpsHr =0, ProfElpsMin =0;
        uint8_t glob_index =0,noOfReg =0, u8Index =0;
        statusBar()->clearMessage();             //clear the status bar
    
        memset(serialBuffer,0,sizeof (serialBuffer));
        //    //    delay(2500);
        //    serial->waitForReadyRead(50);
        //    //    qint64 ulLength= serial->bytesAvailable();
        //    Readdata = serial->readAll();
        QByteArray Readdata; //= data.toLocal8Bit();
        //    QByteArray responseData;
        //while (serial->waitForReadyRead(30))
        serial->waitForReadyRead(20);
        Readdata = serial->readAll();
        //    QByteArray Readdata;
        //        Readdata.append(data);
        for (int i=0;i<Readdata.length();i++)
        {
            serialBuffer[glob_index++]=static_cast<unsigned char>(Readdata[i]);         //store the data read to an array
            noOfReg = serialBuffer[2];
            noOfReg =noOfReg+ 4;
            //        if(!writeFlag)                               //if write flag is not set then take the data length as 9byte
            //        {
            if(glob_index>noOfReg)
            {
                glob_index=0;
                datareceivedFlag  =1;
                break;
            }
            //        }
        }
        if(datareceivedFlag){
            datareceivedFlag=0;
            crccalculated = crc16ForModbus(serialBuffer,(noOfReg -1 ));    //calculate the crc
            crcrecieved = static_cast<quint16>(serialBuffer[noOfReg-1] << 8) | serialBuffer[noOfReg];
            if(crcrecieved==crccalculated)                  //check the crc received and crc calculated are equal
            {
                if(serialBuffer[u8Index++]==slaveID && serialBuffer[u8Index++]==3)
                {
                    u8Index++;
                    u32myvolage = static_cast<uint32_t>(serialBuffer[u8Index++]<<24);
                    u32myvolage |= static_cast<uint32_t>(serialBuffer[u8Index++]<<16);
                    u32myvolage |= static_cast<uint32_t>(serialBuffer[u8Index++]<<8);
                    u32myvolage |=static_cast<uint32_t>(serialBuffer[u8Index++]);
                    fmyvolage = IEEE_HexToFloatPt(u32myvolage);
                    ui->lineEdit_voltage->setText(QString::number(fmyvolage));
                    //                ui->lineEdit_voltage->setText(QString::number(fmyvolage));
    
                    u32mycurrent = static_cast<uint32_t>(serialBuffer[u8Index++])<<24;
                    u32mycurrent |= static_cast<uint32_t>(serialBuffer[u8Index++])<<16;
                    u32mycurrent |= static_cast<uint32_t>(serialBuffer[u8Index++]<<8);
                    u32mycurrent |=static_cast<uint32_t>(serialBuffer[u8Index++]);
                    fmycurrent = IEEE_HexToFloatPt(u32mycurrent);
                    ui->lineEdit_Current->setText(QString::number(fmycurrent));
    
                    if(serialBuffer[11]==0&&serialBuffer[12] ==0 && serialBuffer[13]==0 && serialBuffer[14] ==0)
                    {
                        ampMinFlag=0;
                        amphrHlag=1;
                    }
                    else if(serialBuffer[15]==0&&serialBuffer[16] ==0 && serialBuffer[17]==0 && serialBuffer[18] ==0){
                        ampMinFlag=1;
                        amphrHlag=0;
                    }
                    if(ampMinFlag)
                    {
                        u32myAmpMin = static_cast<uint32_t>(serialBuffer[u8Index++]<<24);
                        u32myAmpMin |= static_cast<uint32_t>(serialBuffer[u8Index++]<<16);
                        u32myAmpMin |= static_cast<uint32_t>(serialBuffer[u8Index++]<<8);
                        u32myAmpMin |=static_cast<uint32_t>(serialBuffer[u8Index++]);
                        fmyAmpMin = IEEE_HexToFloatPt(u32myAmpMin);
                        //                    fmyAmpMin =fmyAmpMin*1000;
                        ui->groupBox_AmpMINHR->setTitle("Current Ampere Minute");
                        ui->label_CrntAmpMinHr_unit->setText("Am");
                        ui->lineEdit_CrntAmp_MinHr->setText(QString::number(fmyAmpMin));
                        u8Index =19;
                    }
                    else if(amphrHlag){
                        u8Index =15;
                        u32myAmphr = static_cast<uint32_t>(serialBuffer[u8Index++]<<24);
                        u32myAmphr |= static_cast<uint32_t>(serialBuffer[u8Index++]<<16);
                        u32myAmphr |= static_cast<uint32_t>(serialBuffer[u8Index++]<<8);
                        u32myAmphr |=static_cast<uint32_t>(serialBuffer[u8Index++]);
                        fmyAmphr = IEEE_HexToFloatPt(u32myAmphr);
                        //                    fmyAmphr = fmyAmphr*60000;
                        ui->groupBox_AmpMINHR->setTitle("Current Ampere Hour");
                        ui->label_CrntAmpMinHr_unit->setText("Ah");
                        ui->lineEdit_CrntAmp_MinHr->setText(QString::number(fmyAmphr));
                        u8Index =19;
                    }
                    u32myAmptotalizer = static_cast<uint32_t>(serialBuffer[u8Index++]<<24);
                    u32myAmptotalizer |= static_cast<uint32_t>(serialBuffer[u8Index++]<<16);
                    u32myAmptotalizer |= static_cast<uint32_t>(serialBuffer[u8Index++]<<8);
                    u32myAmptotalizer |=static_cast<uint32_t>(serialBuffer[u8Index++]);
                    fmyAmptotalizer = IEEE_HexToFloatPt(u32myAmptotalizer);
                    ui->lineEdit_Totalizer->setText(QString::number(fmyAmptotalizer));
    
                    if(serialBuffer[23] ==0 && serialBuffer[24] ==0 && serialBuffer[25] ==0 && serialBuffer[26] ==0 && serialBuffer[27] ==0)
                    {
    
                        if(noOfEntryJobnotSlct==0)
                        {
                            QSize availableSize = qApp->desktop()->availableGeometry().size();
                            int width = availableSize.width();
                            int height = availableSize.height();
                            width *= 0.6; // 90% of the screen size
                            height *= 0.6; // 90% of the screen size
                            QSize newSize( width, height );
    
                            setGeometry(
                                        QStyle::alignedRect(
                                            Qt::LeftToRight,
                                            Qt::AlignCenter,
                                            newSize,
                                            qApp->desktop()->availableGeometry()
                                            )
                                        );
                            ui->groupBox_JobProf->show();
                            noOfEntryJobnotSlct++;
                            No_ofEntry =0;
                        }
                        ui->groupBox_JobProf->hide();
                    }
                    else {
                        if(No_ofEntry==0)
                        {
                            noOfEntryJobnotSlct =0;
                            QSize availableSize = qApp->desktop()->availableGeometry().size();
                            int width = availableSize.width();
                            int height = availableSize.height();
                            width *= 0.6; // 90% of the screen size
                            height *= 0.9; // 90% of the screen size
                            QSize newSize( width, height );
    
                            setGeometry(
                                        QStyle::alignedRect(
                                            Qt::LeftToRight,
                                            Qt::AlignCenter,
                                            newSize,
                                            qApp->desktop()->availableGeometry()
                                            )
                                        );
                            ui->groupBox_JobProf->show();
                            No_ofEntry++;
                        }
                        //                    ProfName[0]= serialBuffer[u8Index++];
                        //                    ProfName[1]= serialBuffer[u8Index++];
                        //                    ProfName[2]= serialBuffer[u8Index++];
                        //                    ProfName[3]= serialBuffer[u8Index++];
                        //                    ProfName[4]= serialBuffer[u8Index++];
                        QString ProfileName;             //QString::fromUtf8(ProfName);
                        ProfileName.append(serialBuffer[u8Index++]);
                        ProfileName.append(serialBuffer[u8Index++]);
                        ProfileName.append(serialBuffer[u8Index++]);
                        ProfileName.append(serialBuffer[u8Index++]);
                        ProfileName.append(serialBuffer[u8Index++]);
                        u8Index++;
                        ProftimeHr = serialBuffer[u8Index++]<<8;
                        ProftimeHr |= serialBuffer[u8Index++];
                        ProftimeMin = serialBuffer[u8Index++]<<8;
                        ProftimeMin |= serialBuffer[u8Index++];
                        ProfElpsHr = serialBuffer[u8Index++]<<8;
                        ProfElpsHr |= serialBuffer[u8Index++];
                        ProfElpsMin = serialBuffer[u8Index++]<<8;
                        ProfElpsMin |= serialBuffer[u8Index++];
    
                        ui->groupBox_JobProf->setTitle(ProfileName);
                        QString ProfTime = QString::number(ProftimeHr);
                        QString ProfTimeMin = QString::number(ProftimeMin);
                        ProfTime.append(":");
                        ProfTime.append(ProfTimeMin);
                        ui->lineEdit_JobTime->setText(ProfTime);
                        QString ElapsTime = QString::number(ProfElpsHr);
                        QString ProfElpsedMin = QString::number(ProfElpsMin);
                        ElapsTime.append(":");
                        ElapsTime.append(ProfElpsedMin);
                        ui->lineEdit_ElpsTime->setText(ElapsTime);
                    }
                    if(fileWrtOpenFlag)
                    {
                        streamOut<< "Voltage:  " << fmyvolage <<"\t" << "Current:  " << fmycurrent<<"\r\n";
                        logFile.flush();
                    }
    
                    //                logFile.close();
                    //                                 }
                    readflag =0;
                }
            }
        }
    //    serial->flush();
        serial->clear(QSerialPort::Directions(1|2));
        Readdata.clear();
        memset(serialBuffer,0,sizeof (serialBuffer));
        //    timer->start(3000);
    }
    void MainWindow::ReadRequest()
    {
        //    timer->stop();
        unsigned char data[10];
        data[0]= slaveID;
        data[1]=3;     //Function code
        data[2]=0;     //MSB start register
        data[3]=0;     //LSB start register
        data[4]=0;     //MSB no.of register
        data[5]=17;    //LSB no.of register (no.of reister to read 30)
        //calculate crc
        crccalculated = crc16ForModbus(data,6);   //calculate the CRC of thw data to send
        data[6]=static_cast<unsigned char>(crccalculated>>8);
        data[7]=static_cast<unsigned char>(crccalculated);
        QByteArray datatowrite = QByteArray(reinterpret_cast<char*>(data), sizeof (data)); //convert cahr to bytearray
        //    QByteArray inttobyte;// = QByteArray::number(crccalculated,16);
        //     inttobyte.setNum(crccalculated);
        //        QDataStream out(&datatowrite, QIODevice::WriteOnly | QIODevice::Append);            //append the CRC calculated to the data to write
        //        out.setByteOrder(QDataStream::BigEndian);                                          //set the byte order in bigendian
        //        out << crccalculated;                                                             //append the crc calculated to the data
        //        out>>datatosend;                                                                 //data from the out to qbytearray
        //    datatowrite.append(inttobyte);
    
        serial->write(datatowrite);
        serial->flush();
        datatowrite.clear();
        memset(data,0,sizeof (data));
    
    }
    
    

    Thank you,
    Alphy


  • Moderators

    @Alphy
    a few things to keep in mind

    • do not mix waitForX and signal & slots. Stick with one, with SIGNAL and SLOTS
    • do not write in the slot connected to the ready read signal, IIRC there were some problems with that
    • What os and what Qt version are you using?


  • @J-Hilk said in Serial terminal disconnecting unexpectedly:

    do not mix waitForX and signal & slots. Stick with one, with SIGNAL and SLOTS

    If I am not giving serial->waitForReadyRead(20); command then the application won't get the entire data the device send.

    do not write in the slot connected to the ready read signal, IIRC there were some problems with that
    is that means to call a new method from the readData Slot.
    What os and what Qt version are you using?
    OS:Windows10
    Qt:Qt Creator 4.9.2

    Thank you,
    Alphy


  • Moderators

    @Alphy said in Serial terminal disconnecting unexpectedly:

    If I am not giving serial->waitForReadyRead(20); command then the application won't get the entire data the device send.

    of course not, and there is no guarantee that 20ms will be enough each and every time!

    If new data arrives readyread will signal again. Your job as a programmer is to store the data, identify if all is arrived, and only then do your processing.

    If you call waitForReady read, inside the slot the signal will not be reemitted.

    and since you also send a new datagram from the slot, I'm pretty sure it breaks here.

    Qt:Qt Creator 4.9.2

    Qt version(the one from your kit) not QtCreator QSerialPort has gone through major revisions lately and perhaps you're on an old/faulty one.



  • @J-Hilk said in Serial terminal disconnecting unexpectedly:

    of course not, and there is no guarantee that 20ms will be enough each and every time!
    If new data arrives readyread will signal again. Your job as a programmer is to store the data, identify if all is arrived, and only then do your processing.

    Thank you so much for your quick reply. I store the data in an array and wait for the entire data to come. Now there is no problem with serial communication.


Log in to reply