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 codevoid 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 -
@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.2Thank you,
Alphy -
@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.