Write ASCII Character and read response using serialport
-
wrote on 23 Jul 2020, 07:58 last edited by
Hi. I'm making GUI which displays encoder's position on the QTextBrowser. I communicate with my device through serialport, So I use QSerialport.
The picture I attach is the some parts of the document.class MotorPort : public QSerialPort /// this is my MotorPort class. void MotorPort::openMotorPort(const QString &portName) { setPortName(portName); setBaudRate(defaultBaudRate); setDataBits(defaultDataBits); setStopBits(defaultStopBits); setParity(defaultParity); open(QIODevice::ReadWrite); }
based on this I wrote code like below.
/// In MainWindow.h MotorPort *rls; /// In MainWindow.cpp rls->openMotorPort("COM5"); //I Checked my PC and device are connected! rls->write(//something//); QByteArray data = rls-> readAll(); ui->statusencoder->setText(QString(data)); //statusencoder is QTextBrowser
The problem is I don't know what to put in the rls->write(). I try to make code like this one, but It doesn't work.
char ch1(63); //63 means "?" in ASCII table. rls->write(&ch1);
Can you let me know how to send ASCII character? Also, Is
QByteArray data = rls-> readAll();
enough to read the response?Thank you
-
Hi
You can use
QByteArray buffer = "?";
serial->write(buffer);- rls-> readAll(); enough to read the response?
No, not always. You should read until you see CR ( as shown in your table)
Also you cant just call it. you normally use the signal QSerialPort::readyRead and then call readall()
More than one signal might come.So not sure you are using it correctly.
-
Hi,
In addition to @mrjj, you should always check that the QSerialPort open method returned successfully. You may be using the correct port name but not have access to the device for different reasons.
-
wrote on 25 Jul 2020, 07:50 last edited by H.dragon
Sorry for the late reply.
After reading @mrjj 's answer, I added readyRead.// Constructor MotorPort::MotorPort(QSerialPort* parent) : QSerialPort(parent) { // Connect signals to slots. connect(this, SIGNAL(readyRead()), this, SLOT(getData())); // Default port connection parameters. defaultBaudRate = QSerialPort::Baud9600; defaultDataBits = QSerialPort::Data8; defaultStopBits = QSerialPort::OneStop; defaultParity = QSerialPort::NoParity; } // Destructor MotorPort::~MotorPort() { } bool MotorPort::openMotorPort(const QString &portName) { setPortName(portName); setBaudRate(defaultBaudRate); setDataBits(defaultDataBits); setStopBits(defaultStopBits); setParity(defaultParity); bool openning; opening = open(QIODevice::ReadWrite); return openning; } void MotorPort::getData() { Output = QIODevice::readAll(); // Output(QByteArray) is private member of MotorPort } QByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); getData(); return Output; }
and in mainwindow.cpp
bool open = rls->openMotorPort("COM5"); if (open==true) { ui->statusencoder->append("success"); QByteArray data=rls->getresponse(); ui->statusencoder->append(QString(data)); int array[10]; //I tried to choose return value type as int for (int i=0;i<10;i++) { array[i]=7; ui->statusencoder->append(QString::number(array[i])); array[i]=data[i]; ui->statusencoder->append(QString::number(array[i])); } }
After running this code, My QTextBrowser(statusencoder) shows like this one
success 7 0 7 0 7 0 7 0 7 0 7 0 7 0 7 0 7 0 7 0
the reference software says encoder's position is 3.032mm. so I expect any different value. but
QByteArray data
seems to be NULL. Am I still making code wrong? -
Hi
Its asynchronous so i think the issue lies hereQByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); // send getData();// you just call it so might be nothing to read yet. its not called by serialport due to incoming data return Output; }
So you cant really do it this way. it has to be like this
You send something
Serialport issues one or more readyRead signals
in getData you read and append to a bufferOutput += QIODevice::readAll(); // note the plus
then when data contains a CR, we know you got full set.
Then you can send signal to mainWindow that data is ready.
and it that slot in main window, you can then use the data.I know it seems a bit complicated but thats how async programming is.
If you really find it hard to get work, you can use the blocking api of QSrialport
https://doc.qt.io/qt-5/qtserialport-creadersync-example.htmlBut do note that this LAGS the GUI. gui will not redraw etc while code is running and that is
why the async way with signal and slot is preferred. -
Hi
Its asynchronous so i think the issue lies hereQByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); // send getData();// you just call it so might be nothing to read yet. its not called by serialport due to incoming data return Output; }
So you cant really do it this way. it has to be like this
You send something
Serialport issues one or more readyRead signals
in getData you read and append to a bufferOutput += QIODevice::readAll(); // note the plus
then when data contains a CR, we know you got full set.
Then you can send signal to mainWindow that data is ready.
and it that slot in main window, you can then use the data.I know it seems a bit complicated but thats how async programming is.
If you really find it hard to get work, you can use the blocking api of QSrialport
https://doc.qt.io/qt-5/qtserialport-creadersync-example.htmlBut do note that this LAGS the GUI. gui will not redraw etc while code is running and that is
why the async way with signal and slot is preferred.wrote on 25 Jul 2020, 10:13 last edited by@mrjj
Hi. I read your answer but It is a little difficult for me to understand the concept of asynchronous, I googled it and some functions, I changedMotorPort::getresponse()
like below. then it worksQByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); waitForReadyRead(500); return Output; }
Is this the solution of your answer? Actually I don't think I fully understood your answer.
Anyway, Thank you mrjj! -
@mrjj
Hi. I read your answer but It is a little difficult for me to understand the concept of asynchronous, I googled it and some functions, I changedMotorPort::getresponse()
like below. then it worksQByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); waitForReadyRead(500); return Output; }
Is this the solution of your answer? Actually I don't think I fully understood your answer.
Anyway, Thank you mrjj!@H-dragon
Hi
asynchronous means it will happen at another point in time (than right now) and yes it can be
difficult to handle.You used the blocking call
waitForReadyRead(500);
so yes that was what i meant in the second part of the answer.
Even now you kinda mix sync and async but it seems that it fires in right order
so it works :) -
wrote on 27 Jul 2020, 06:30 last edited by H.dragon
@mrjj
HI.
Can I ask you one last question?QByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); waitForReadyRead(500); return Output; }
How the private member
Output
gets some data from serialport when I call the functiongetresponse()
, although there isnt the functiongetData()
? As I know, thewaitForReadyRead(500)
blocks the cell until new data is available.
Is that because I connected signal to slots? (connect(this, SIGNAL(readyRead()), this, SLOT(getData()));
)
Thank you for your continued kindness :) -
@mrjj
HI.
Can I ask you one last question?QByteArray MotorPort::getresponse() { QByteArray buffer = "?"; write(buffer); waitForReadyRead(500); return Output; }
How the private member
Output
gets some data from serialport when I call the functiongetresponse()
, although there isnt the functiongetData()
? As I know, thewaitForReadyRead(500)
blocks the cell until new data is available.
Is that because I connected signal to slots? (connect(this, SIGNAL(readyRead()), this, SLOT(getData()));
)
Thank you for your continued kindness :)@H-dragon
Hi
Yes its due to the readyRead signal calling getData() and fill Output.
So we kinda mixed async and sync calls.
But docs says
"This function blocks until new data is available for reading and the readyRead() signal has been emitted. "
https://doc.qt.io/qt-5/qserialport.html#waitForReadyReadso it does come in right order and then it worked.
-
wrote on 4 Aug 2020, 06:35 last edited by
@mrjj
Hi. Thanks to you, I completed my GUI work. I really appreciate it.
But while writing codes, I came up with a question.
In your second answer, you changedOutput = QIODevice::readAll()
toOutput += QIODevice::readAll()
.
Can you explain why the former doesn't work(my gui terminate)? is it related with asynchronous? -
@mrjj
Hi. Thanks to you, I completed my GUI work. I really appreciate it.
But while writing codes, I came up with a question.
In your second answer, you changedOutput = QIODevice::readAll()
toOutput += QIODevice::readAll()
.
Can you explain why the former doesn't work(my gui terminate)? is it related with asynchronous?Lifetime Qt Championwrote on 4 Aug 2020, 06:46 last edited by mrjj 8 Apr 2020, 07:02Hi
Good to hear
Well there is only a small differenceThis overwrites all that already is in Output
Output = QIODevice::readAll()This Adds to what is already is in Output
Output += QIODevice::readAll().The last is the best due to the following reason.
When you sent something big enough over serial - it will result in multiple pieces of data
so the readyRead() will trigger more than one time.So in such cases,
one has to add the incoming data to a buffer as to collect it all- before using it.
and that is what
Output += QIODevice::readAll().
does. Add data to the Output buffer.
So that is something to keep in mind.
- before using it.
-
wrote on 4 Aug 2020, 08:04 last edited by
@mrjj
Do I understand well?
for example, let's say something big data (123456789) is divided into multiple pieces(123, 456, 789).If I use Output = QIODevice::readAll(), it can cause follow situation
readyRead()
Output is 123
readyRead()
Output is 456
readyRead()
Output is 789but when I use Output+=QIODevice::readAll(),
readyRead()
Output is 123
readyRead()
Output is 123456
readyRead()
Output is 123456789The reason += is the best is It can prevent the former situation. right?
-
@mrjj
Do I understand well?
for example, let's say something big data (123456789) is divided into multiple pieces(123, 456, 789).If I use Output = QIODevice::readAll(), it can cause follow situation
readyRead()
Output is 123
readyRead()
Output is 456
readyRead()
Output is 789but when I use Output+=QIODevice::readAll(),
readyRead()
Output is 123
readyRead()
Output is 123456
readyRead()
Output is 123456789The reason += is the best is It can prevent the former situation. right?
@H-dragon
Hi
Yes that is exactly like that.When it will be broken up depends on the hardware. some have bigger buffers than others and
so on but it does happen. -
@H-dragon
Hi
Yes that is exactly like that.When it will be broken up depends on the hardware. some have bigger buffers than others and
so on but it does happen.wrote on 6 Aug 2020, 05:55 last edited byThanks!!
-
@H-dragon
Np.
In your concrete use case, all feedback from the hardware ends with CR
so its easy to spot when you have read all data.In other cases one has to look at size to know if
all has been read.