Error while writing and reading (SerialPort)
-
Hello There!
I´m new in Qt and doing Serial Communication. I need to make the connection between a GPS receiver and my PC, the connection is correct, and the reading is ok as well... but there is a problem, when a try to write and send commands to the GPS always got something wrong...
When I was able to send the information correctly, something strange happends. If a configure the GPS outside QT (RealTerm), and reconfigure with my code, the response that supose to give me just 2 short messages in the command window, get stuck with the same message and sends me infinite number of themif there is no previous configuration, the program doesn't send anything, at least that seems to be.
This is my code
#include "myserial.h" #include <QtSerialPort/QSerialPort> #include <QObject> #include <QtWidgets> #include <QFile> #include <QTextStream> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); //MySerialPort(); MySerialPort iSerialPort; iSerialPort.openSerialPort(); return a.exec(); } MySerialPort::MySerialPort() { serial = new QSerialPort(this); connect(serial, SIGNAL(readyRead()), this, SLOT(readData())); //openSerialPort(); } void MySerialPort::openSerialPort() { QString nombre; const auto infos = QSerialPortInfo::availablePorts(); for (const QSerialPortInfo &info : infos) { QString puerto = info.portName(); if ( info.manufacturer() == "Prolific" ) { nombre = puerto; qDebug().noquote() << "El GPS se encuentra conectado en el puerto:" << nombre; } } serial->setPortName(nombre); serial->setBaudRate(QSerialPort::Baud9600); serial->setDataBits(QSerialPort::Data8); serial->setParity(QSerialPort::NoParity); serial->setStopBits(QSerialPort::OneStop); serial->setFlowControl(QSerialPort::NoFlowControl); if (serial->open(QIODevice::ReadWrite)) { showStatusMessage("Contectado a GPS"); } else { showStatusMessage(tr("Open error")); } } void MySerialPort::closeSerialPort() { if (serial->isOpen()) serial->close(); showStatusMessage(tr("Disconnected")); } void MySerialPort::sendData() { static char Cf[]={0x40, 0x40, 0x43, 0x66, 0x25, 0x0D, 0x0A}; for (int i=0; i < 7; i++) { serial->putChar(Cf[i]); }/* static char Gd[]={0x40, 0x40, 0x47, 0x64, 0x03, 0x20, 0x0D, 0x0A}; for (int i=0; i < 8; i++) { serial->putChar(Gd[i]); } static char Ge[]={0x40, 0x40, 0x47, 0x65, 0x01, 0x23, 0x0D, 0x0A}; for (int i=0; i < 8; i++) { serial->putChar(Ge[i]); }*/ static char Hn[]={0x40, 0x40, 0x48, 0x6e, 0x02, 0x24, 0x0D, 0x0A}; for (int i=0; i < 8; i++) { serial->putChar(Hn[i]); } } void MySerialPort::readData() { sendData(); QByteArray data = serial->readAll(); // qDebug() << data; QByteArray received = data.toHex(); qDebug()<<"testing :"<<received; } void MySerialPort::handleError(QSerialPort::SerialPortError error) { if (error == QSerialPort::ResourceError) { closeSerialPort(); } } void MySerialPort::showStatusMessage(const QString &message) { qDebug() << message; }
Any help would be nice, thank you
-
Its works now!!
I better call both functions in order to execute one at time, used the readyRead signal
... MySerialPort::MySerialPort() { serial = new QSerialPort(this); connect(serial, SIGNAL(readyRead()), this, SLOT(readData())); ... serial->setPortName(nombre); serial->setBaudRate(QSerialPort::Baud9600); serial->setDataBits(QSerialPort::Data8); serial->setParity(QSerialPort::NoParity); serial->setStopBits(QSerialPort::OneStop); serial->setFlowControl(QSerialPort::NoFlowControl); if (serial->open(QIODevice::ReadWrite)) { showStatusMessage("Contectado a GPS"); } else { showStatusMessage(tr("Open error")); } sendData(); readData(); } ... ...
Used "waitForBytesWritten()" at the end of writing, and "QIODevice::readyRead();" before start reading, so there is no failure now. Thanks everybody!
-
Hi, the connection to the GPS is 9600 baud, which means about 1000 characters per second, but in void MySerialPort::readData():
void MySerialPort::readData() { // you're transmitting 15 characters, which takes about 15 milliseconds sendData(); // but you're immediately trying to get an answer from the GPS QByteArray data = serial->readAll();
try waiting 15 milliseconds for the 15 characters to be transmitted and then wait at least 15 milliseconds more the characters to arrive, before doing serial->readAll()
Note: there are lots of helper functions for this in the QSerialPort class, for example you can use waitForBytesWritten() to make sure all of 15 characters have been transmitted before you're expecting an answer.
-
While I fully agree to the first part of your answer, I object to the second one.
try waiting 15 milliseconds for the 15 characters to be transmitted and then wait at least 15 milliseconds more the characters to arrive, before doing serial->readAll()
No, that is wrong.
The correct way is to use a slot connected to
readyRead()
and read the incoming data there. Once the device answers, you will get the data there.Everything else, including
waitForBytesWritten()
is contra-productive (except if running in a separate thread).Regards
-
By the way, can't you use the Qt positioning module?
-
@aha_1980 said in Error while writing and reading (SerialPort):
try waiting 15 milliseconds for the 15 characters to be transmitted and then wait at least 15 milliseconds more the characters to arrive, before doing serial->readAll()
No, that is wrong.
Yes, agreed it's a dumb way. (Also waitForBytesWritten() has a history of being unreliable, at least on Windows.)
Problem was:
readyRead()
signal is connected ok, but transmitting the 15 characters inside thereadyRead()
signal handler and expecting an immediate answer will fail, so I tried to explain that serial communication is a sloooow business. -
@hskoglund said in Error while writing and reading (SerialPort):
Problem was: readyRead() signal is connected ok, but transmitting the 15 characters inside the readyRead() signal handler and expecting an immediate answer will fail, so I tried to explain that serial communication is a sloooow business.
That is fully correct. But sending the characters out will lead to another answer, i.e. another
readyRead()
signal and there the answer can be handled.Regards
-
This post is deleted!
-
H
Now I get that, will use "readyRead()" and won´t ask for inmmediate answer haha thanks!
-
Its works now!!
I better call both functions in order to execute one at time, used the readyRead signal
... MySerialPort::MySerialPort() { serial = new QSerialPort(this); connect(serial, SIGNAL(readyRead()), this, SLOT(readData())); ... serial->setPortName(nombre); serial->setBaudRate(QSerialPort::Baud9600); serial->setDataBits(QSerialPort::Data8); serial->setParity(QSerialPort::NoParity); serial->setStopBits(QSerialPort::OneStop); serial->setFlowControl(QSerialPort::NoFlowControl); if (serial->open(QIODevice::ReadWrite)) { showStatusMessage("Contectado a GPS"); } else { showStatusMessage(tr("Open error")); } sendData(); readData(); } ... ...
Used "waitForBytesWritten()" at the end of writing, and "QIODevice::readyRead();" before start reading, so there is no failure now. Thanks everybody!