I wrote a simple program to use Qt (version 5.5 built from source for Visual Studio 2013 following this guide) to comunicate with Arduino.
Here is a simple firmware which read from the serial and after 10 seconds prints "1" back:
void setup() {
Serial.begin(9600); //Open Serial connection for debugging
}
void loop() {
if (Serial.available()) {
char user_input = Serial.read();
if (user_input == '1') {
delay(10000);
Serial.print('1');
}
}
Here is the Qt program which send "1" on serial when I press the start button and keeps listening for messages to read:
main.cpp
#include "mainwindow.h"
#include <QApplication>
#pragma comment(lib, "advapi32")
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#pragma once
#include <QMainWindow>
#include "SerialHandler.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow* ui;
SerialHandler serialHandler;
public slots:
void onStart();
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent), ui(new Ui::MainWindow), serialHandler(QString("COM6")) {
ui->setupUi(this);
QObject::connect(ui->startButton, SIGNAL(released()), this, SLOT(onStart()));
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::onStart() {
serialHandler.moveForward();
}
SerialHandler.h
#pragma once
#include <QString>
#include <QtSerialPort>
#include <QtSerialPort/QSerialPort>
class SerialHandler {
public:
SerialHandler(QString& serialName);
~SerialHandler();
void moveForward();
private:
QSerialPort serial;
void writeOnSerial(QByteArray& msg);
private slots:
void handleReadyRead();
};
SerialHandler.cpp
#include "SerialHandler.h"
#include <QDebug>
#include <QObject>
SerialHandler::SerialHandler(QString& serialName){
connect(&serial, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
// Initialize Serial
serial.setPortName(serialName);
if (!serial.setBaudRate(QSerialPort::Baud9600)) {
throw std::runtime_error(QObject::tr("Can't set rate 9600 baud to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()).toStdString());
}
if (!serial.open(QIODevice::ReadWrite)) {
throw std::runtime_error(QObject::tr("Can't open %1, error code %2")
.arg(serial.portName()).arg(serial.error()).toStdString());
}
if (!serial.setDataBits(QSerialPort::Data8)) {
throw std::runtime_error(QObject::tr("Can't set 8 data bits to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()).toStdString());
}
if (!serial.setParity(QSerialPort::NoParity)) {
throw std::runtime_error(QObject::tr("Can't set no patity to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()).toStdString());
}
if (!serial.setStopBits(QSerialPort::OneStop)) {
throw std::runtime_error(QObject::tr("Can't set 1 stop bit to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()).toStdString());
}
if (!serial.setFlowControl(QSerialPort::NoFlowControl)) {
throw std::runtime_error(QObject::tr("Can't set no flow control to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()).toStdString());
}
}
SerialHandler::~SerialHandler(){
if (serial.isOpen()) {
serial.close();
}
}
void SerialHandler::handleReadyRead() {
qDebug() << serial.readAll();
}
void SerialHandler::writeOnSerial(QByteArray& msg) {
if (serial.isOpen() && serial.isWritable()) {
serial.write(msg);
serial.flush();
}
}
void SerialHandler::moveForward(){
QByteArray msg("1");
writeOnSerial(msg);
}
the problem appears in writeOnSerial method (SerialHandler.cpp). The call to serial.write() fires this error:
QObject::startTimer: Timers can only be used with threads started with QThread
the "1" is written on serial and read by the arduino, but the computer never receives anything back after 10 seconds, the readyRead() signal is never fired!
I saw the same error in this post, but in my case the exec loop is there!
Any suggestions?