Arduino和Qt 5.7之间的双向串行通信 [英] Double way Serial communication between Arduino and Qt 5.7

查看:92
本文介绍了Arduino和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.

  1. 在Arudino方面,您应该使用println而不是write,以便每条消息都是完整的一行.

  1. On the Arudino side, instead of write, you should use println 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问题-还请注意,您不需要那么多的include,并且可以使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆