Arduino和Qt 5.7之间的双向串行通信 [英] Double way Serial communication between Arduino and Qt 5.7
问题描述
我正在尝试将数据从 Arduino 传输到 C++ Qt5.7,并从 Arduino 传输到 C++ Qt5.7 (MinGW) 程序.
I am trying to transfer data from Arduino to a C++ Qt5.7 and from a Arduino to a C++ Qt5.7 (MinGW) program.
我可以毫无问题地将数据从 QT 传输到 ARDUINO.Arduino 完美闪烁.
I am able to transfer the data FROM QT TO ARDUINO without any problems. The Arduino blinks perfectly.
另一方面,从 ARDUINO 传输到 QT 的数据并不总是预期的(当它应该是LED OFF"时发送LED ON"),有时它根本不通信!
On the other hand, the data transfered FROM THE ARDUINO TO QT isnt always the expected (sends "LED ON" when it should be "LED OFF") and sometimes it doesnt communicate at all!
QT 代码:
#include <QCoreApplication>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QThread>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSerialPort serial;
serial.setPortName("COM6");
serial.setBaudRate(9600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
if(serial.open(QSerialPort::ReadWrite))
{
string c;
QByteArray s;
QByteArray received;
while(true)
{
qDebug("TRUE");
//WRITE
cin >> c;
cout << endl;
s = QByteArray::fromStdString(c);
serial.write(s);
serial.waitForBytesWritten(-1);
//serial.flush();
s = serial.readAll();
serial.waitForReadyRead(-1);
cout << s.toStdString() << endl;
//serial.flush();
}
}
else
{
QString error = serial.errorString();
cout << error.toStdString() << endl;
qDebug("FALSE") ;
}
serial.close();
return a.exec();
}
ARDUINO 代码:
The ARDUINO CODE:
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
}
// the loop function runs over and over again forever
void loop() {
delay(1000); // wait for a second
}
void serialEvent()
{
char inChar;
while (Serial.available())
{
// get the new byte:
inChar = (char)Serial.read();
if(inChar == 'a')
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
}
else
{
digitalWrite(LED_BUILTIN, LOW); // turn the LED off (LOW is the voltage level)
}
}
delay(500);
if(inChar == 'a')
{
Serial.write("LED ON");
}
else
{
Serial.write("LED OFF");
}
}
错误的终端图像:
请帮忙!谢谢,
推荐答案
您没有任何分组化:单个数据块之间没有分隔符 - 除了时间流逝.
You have no packetization whatsoever: there are no delimiters between individual chunks of data - other than time passing.
在 Arudino 方面,您应该使用
println
而不是write
,以便每条消息都是完整的一行.
On the Arudino side, instead of
write
, you should useprintln
so that each message is a complete line.
在 Qt 端,处理完整的行.在 waitForReadyRead
之后,您不能保证从串行端口获得完整的响应.您所保证的只是至少有 1 个字节可供读取.这就是你问题的根源.注意你是如何得到 LE
的,然后过了一段时间你得到 D OFF
紧接着 LED ON
.您必须等待数据,直到完整的行可用.
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.
以下内容应该适用于 Qt 端 - 另请注意,您不需要那么多包含,并且您可以使用 QTextStream
而不是 iostream,以减少您使用的 API 数量用.最后,您不需要 app.exec
,因为您编写了阻塞代码.
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
}
}
如果您愿意,也可以轻松地将其转换为 GUI 应用程序,只需几行代码即可:
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();
}
这篇关于Arduino和Qt 5.7之间的双向串行通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!