How to Make My Program in Qt Continually Send a String to My Arduino

How Do I Make My Program in Qt Continually Send A String to My Arduino?

I suggest you expand on your design somewhat:

  • have a repeating QTimer with an interval depending on the rate you want to send the string at, and the timer to the function that sends the string
  • connect the button's pressed signal to start the timer
  • connect the button's released signal to stop the timer

Events are sent only once, thus the handlers will be executed only once, if you want to keep on repeating it, you will have to use a timer or some other event driven way. You cannot use a loop as that would block the GUI thread and your application will stop responding.

Sure, you could use the button's auto repeat, and there is the option to adjust the triggering and repeating intervals, but a solution that puts a line between logic and GUI is better. You should really rely on the GUI for storing data or controlling the internal logic. The GUI should only be a front end.

You need more work on the serial port though. If you are going to use it from the GUI thread, you will have to use the non-blocking API. Which will require to extend on your implementation a little bit more. There is a good example on how to achieve that, you only need to modify it to simply enable the sending of further payloads once the previous payload has been successfully sent. In pseudo code:

on button press
start timer
on button release
stop timer
onTimeout
if (can send)
send
can send = false
onBytesWritten
accumulate bytes
if (payload is completed)
can send = true
reset payload byte counter

Of course, you will also have to do some error checking, you can't just expect it to work. The example linked contains basic error handling.

Serial Communication Timeout in QT with Arduino

You are using blocking approach to transmit data via serial port. Unless you are using threads I don't see possibility to send any additional data during execution of previous loop.
BTW: Your program, for example, will block indefinitely if Arduino manages to keep sending something within 10ms periods.

Add couple of QDebug() << "I'm here"; lines to check where your code gets stuck; it is possible that you are blocking somewhere outside code you pasted here. Alternative is to use debugger.

What if previous 'command' you tried to send is still in the buffer ? You'll end up filling output buffer. Check with QDebug how many bytes are in output buffer before writing more data to it. Buffer should be empty. (qint64 QIODevice::bytesToWrite() const).

Connect Arduino with Qt

Problem has been solved:

Qt:

if (serial.isOpen() && serial.isWritable())
{

QByteArray ba("R");
serial.write(ba);
serial.flush();
qDebug() << "data has been send" << endl;
serial.close();
}

Arduino:

int led = 13, avlb = 0; 

void setup()
{
Serial.begin(9600);
pinMode(led, OUTPUT);
Serial.println("started");
}

void loop()
{
if (Serial.available() > 0)
{
Serial.println("available");
Serial.println(Serial.available());
delay(2000);
if(Serial.read())
{
Serial.println("read");
Serial.println(Serial.read());
delay(2000);
}
}

else
{
Serial.println("not available");
delay(1000);
}

}

N.B.: Don't forget to put baudrate in Arduino IDE correctly;

In monitor, 9600 baudrate

Qt reading serial data - working code but needs to be more reliable

I didn't much look into it, but it seems the problem might be related to this line:

if(serialData.length()==2*datalength)

So if you got some extra data you just give up on the whole thing? It is not guaranteed that data will arrive at neatly discrete blocks after all.

You should read in the data if length is greater or equal, read in the specified length and leave the remaining data because it is part of the next block.

It would also explain why your function hangs - if you happen to exceed 2*datalength the condition is never true.

But even if you fix this, the implementation is kinda naive and not something that can be considered fullproof. There are other things that can go wrong, and you will need to have more descriptive block data so you can figure out what went wrong and how to fix it or skip errors without throwing a wrench in the gears so to speak.

Double way Serial communication between Arduino and Qt 5.7

You have no packetization whatsoever: there are no delimiters between individual chunks of data - other than time passing.

  1. On the Arudino side, instead of write, you should use println so that each message is a complete line.

  2. On the Qt side, process complete lines. You're not guaranteed to get a complete response from the serial port after waitForReadyRead. All that you're guaranteed is that at least 1 byte is available to read. That is the source of your problem. Note how you got LE, then sometime later you got D OFF immediately followed by LED ON. You must wait for data until complete line(s) are available.

The following should work on the Qt end of things - also note that you don't need as many includes, and you can use QTextStream instead of iostream, to lower the number of APIs that you use. Finally, you don't need app.exec since you write blocking code.

// https://github.com/KubaO/stackoverflown/tree/master/questions/arduino-read-40246601
#include <QtSerialPort>
#include <cstdio>

int main(int argc, char *argv[])
{
QCoreApplication a{argc, argv};
QTextStream in{stdin};
QTextStream out{stdout};

QSerialPort port;
port.setPortName("COM6");
port.setBaudRate(9600);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setStopBits(QSerialPort::OneStop);
port.setFlowControl(QSerialPort::NoFlowControl);

if (!port.open(QSerialPort::ReadWrite)) {
out << "Error opening serial port: " << port.errorString() << endl;
return 1;
}

while(true)
{
out << "> ";
auto cmd = in.readLine().toLatin1();
if (cmd.length() < 1)
continue;

port.write(cmd);

while (!port.canReadLine())
port.waitForReadyRead(-1);

while (port.canReadLine())
out << "< " << port.readLine(); // lines are already terminated
}
}

If you wish, you can also easily turn it into a GUI application, it's only a few lines to do so:

#include <QtSerialPort>
#include <QtWidgets>

int main(int argc, char *argv[])
{
QApplication app{argc, argv};
QWidget ui;
QFormLayout layout{&ui};
QLineEdit portName{"COM6"};
QTextBrowser term;
QLineEdit command;
QPushButton open{"Open"};
layout.addRow("Port", &portName);
layout.addRow(&term);
layout.addRow("Command:", &command);
layout.addRow(&open);
ui.show();

QSerialPort port;
port.setBaudRate(9600);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setStopBits(QSerialPort::OneStop);
port.setFlowControl(QSerialPort::NoFlowControl);

QObject::connect(&open, &QPushButton::clicked, &port, [&]{
port.setPortName(portName.text());
if (port.open(QSerialPort::ReadWrite)) return;
term.append(QStringLiteral("* Error opening serial port: %1").arg(port.errorString()));
});

QObject::connect(&command, &QLineEdit::returnPressed, &port, [&]{
term.append(QStringLiteral("> %1").arg(command.text()));
port.write(command.text().toLatin1());
});

QObject::connect(&port, &QIODevice::readyRead, &term, [&]{
if (!port.canReadLine()) return;
while (port.canReadLine())
term.append(QStringLiteral("< %1").arg(QString::fromLatin1(port.readLine())));
});
return app.exec();
}

Add GUI to a QT Project with Arduino

The GUI project is completely unrelated to anything Arduino. The page you linked to shows how to use Qt Creator as an IDE to work on Arduino projects, as a replacement to the Arduino IDE. This has nothing to do with GUIs or Qt, you'd be reusing Qt Creator as a general-purpose IDE that it is.

What you need and want is to create a standard Qt project in Qt Creator and go from there. You can also leverage Qt to "simulate" Arduino code without running real Arduino hardware, see this answer for an example.

Arduino doesn't receive data after reconnecting to USB

OK, so, after hours of debugging I've found what caused the problem.

The root of it was that after reconnecting the Arduino, each time I called serial.open in QT, Arduino did a reset (indicated by the blink of the LED) and by the time it was after the bootloader stage and was running the code, the main program had already passed the serial.write QT command without receiving the data.

So, what I did to solve the problem was to just add a Sleep(uint(2000)); after serial.open in order to let Arduino finish booting and then start sending data.

Thank you all for your help and immediate answers!



Related Topics



Leave a reply



Submit