当前位置: 首页 > 知识库问答 >
问题:

QSerialPort有字节可用但无法读取

微生昌勋
2023-03-14

我正在编写一个Qt GUI应用程序,它通过串行方式接收数据并将数据发送到Arduino。它写得正确,但当尝试阅读时,它不起作用。

我的问题是:

我有一个Arduino代码可以通过串行方式发送信息,我将其编程为根据接收到的数据打开和关闭针脚13上的LED:

#define ARDUINO_TURNED_LED_ON "LEDON"
#define ARDUINO_TURNED_LED_OFF "LEDOFF"
#define PC_REQUESTED_LED_STATE_CHANGE u8"CHANGELED"

void setup() 
{
 // put your setup code here, to run once:
 Serial.begin(9600);
 pinMode(13, OUTPUT);
}

String serialCmd = "";
bool ledState=false;

void loop()
{
 // put your main code here, to run repeatedly:
 if (Serial.available())
 {
  serialCmd=Serial.readString();

  if (serialCmd==PC_REQUESTED_LED_STATE_CHANGE)
  {
   if (ledState)
   {
     digitalWrite(13, LOW);
     Serial.write(ARDUINO_TURNED_LED_OFF);
   }
   else
   {
    digitalWrite(13, HIGH);
    Serial.write(ARDUINO_TURNED_LED_ON);
   };

   ledState=!ledState;
   serialCmd = "";

  }  

 }

}

我在MainWindow类中使用以下信号和插槽:

#define ARDUINO_TURNED_LED_ON "LEDON"
#define ARDUINO_TURNED_LED_OFF "LEDOFF"
#define PC_REQUESTED_LED_STATE_CHANGE u8"CHANGELED"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
    ui->setupUi(this);

/* Create Object the Class QSerialPort*/
    serialPort = new QSerialPort(this);

    /* Create Object the Class Arduino to manipulate read/write*/
    arduino = new Arduino(serialPort);
    
    //connect signal:
    connect(serialPort, SIGNAL(readyRead()), this, SLOT(ReadData()));
}

//slot
void MainWindow::ReadData()
{
    QString received = arduino->Read();
    qDebug() << "received data:" << received;

    if (received==ARDUINO_TURNED_LED_ON)
    {
        qDebug() << "led on";
    }
    else if (received==ARDUINO_TURNED_LED_OFF)
    {
        qDebug() << "led off";
    }
}

以及前一个插槽调用的Arduino::Read()方法:

QString Arduino::Read()
{
 QString bufRxSerial;

 qDebug() << "bytes available:" << serialPort->bytesAvailable();

 /* Awaits read all the data before continuing */
 while (serialPort->waitForReadyRead(20)) {
     bufRxSerial += serialPort->readAll();
 }
 return bufRxSerial;
}

当向Arduino写入数据时,它工作正常,LED按其应有的方式变化,当Qt尝试读取回复的数据时,就会出现问题。

在大多数时候,Arduino发送的东西,信号发出和串行端口-

最奇怪的是,在发送某个内容的随机时刻,一切都正常工作,html" target="_blank">函数返回以前无法读取的所有数据。

这里有一个发生的例子:

Qt将PC\u REQUESTED\u LED\u STATE\u CHANGE(u8“CHANGELED”)写入串行端口

Arduino LED改变其状态(打开)

Arduino将Arduino\u开启的LED\u(“LEDON”)写入串行端口

Qt将PC\u REQUESTED\u LED\u STATE\u CHANGE(u8“CHANGELED”)写入串行端口

Arduino LED改变其状态(关闭)

Arduino将Arduino\u关闭的LED\u(“LED关闭”)写入串行端口

Qt将PC\u REQUESTED\u LED\u STATE\u CHANGE(u8“CHANGELED”)写入串行端口

Arduino LED改变其状态(打开)

Arduino将Arduino\u开启的LED\u(“LEDON”)写入串行端口

Qt从Arduino读取“LEDONLEDOFFLEDON”,这是以前无法读取的所有内容。

Qt将PC\u REQUESTED\u LED\u STATE\u CHANGE(u8“CHANGELED”)写入串行端口

Arduino LED改变其状态(关闭)

Arduino将Arduino\u关闭的LED\u(“LED关闭”)写入串行端口

Qt将PC\u REQUESTED\u LED\u STATE\u CHANGE(u8“CHANGELED”)写入串行端口

Arduino LED改变其状态(打开)

Arduino将Arduino\u开启的LED\u(“LEDON”)写入串行端口

Qt从Arduino中读取“LEDOFFLEdon”,这是以前无法读取的所有内容。

我使用Arduino IDE串行监视器进行了测试,它按预期工作:我写了“CHANGELED”,然后LED发生了变化,Arduino一直回复“LEdon”或“LEDOFF”。

我能做些什么来解决这个问题?谢谢

编辑:可以在此处找到完整的代码

共有2个答案

赵晨
2023-03-14

这听起来像是缓冲问题。Qt应用程序接收字节,但没有任何信息表明接收完成。我会在每个字符串后添加换行符(\n)作为终止符字符,只需使用串行。println()而不是串行。write()。然后,您可以在Qt中使用readLine(),并始终确保您得到的是一个完整的命令字符串。

如果您在Linux,您还可以尝试将设备设置为原始

stty -F /dev/ttyACM0 raw

让串行字符直接发送而不是默认行缓冲(请参阅“原始”和“熟”设备驱动程序之间有什么区别?)。
请注意,然后您可能会遇到一个新问题:您的Qt应用程序可能太快了,以至于您在回调中一次只能收到一个字母。

岳硕
2023-03-14

Read方法是不正确和不必要的。您永远不应该使用waitFor方法。在处理QByteArray处理的简单ASCII数据时,您也不应该使用QString

class MainWindow : ... {
  QByteArray m_inBuffer;
  ...
};

void MainWindow::ReadData() {
  m_inBuffer.append(arduino->readAll());
  QByteArray match;
  while (true) {
    if (m_inBuffer.startsWith((match = ARDUINO_TURNED_LED_ON))) {
      qDebug() << "led on";
    } else if (m_inBuffer.startsWith((match = ARDUINO_TURNED_LED_OFF))) {
      qDebug() << "led off";
    } else {
      match = {};
      break;
    }
  }
  m_inBuffer.remove(0, match.size());
}

交易很简单:ReadData可以用任意数量的可用字节调用,甚至是单个字节。因此,您必须累积数据,直到收到完整的“数据包”。在您的情况下,只能通过匹配完整响应字符串来描述数据包。

如果Arduino发送了完整的行-替换序列号,您的生活会变得更加轻松。使用串行写入。println。那么这些行就是数据包,您不需要自己缓冲数据:

void MainWindow::ReadData() {
  while (arduino->canReadLine()) {
    auto line = arduino->readLine();
    line.chop(1); // remove the terminating '\n'
    QDebug dbg; // keeps everything on a single line
    dbg << "LINE=" << line;
    if (line == ARDUINO_TURNED_LED_ON)
      dbg << "led on";
    else if (line == ARDUINO_TURNED_LED_OFF)
      dbg << "led off";
  }
}

看到了吗?这样简单多了。

您还可以利用Qt来“模拟”Arduino代码,而无需运行真正的Arduino硬件,请参见以下示例。

 类似资料:
  • 尝试2:有趣的部分是下载文件(只是在浏览器地址栏中粘贴URL),然后执行类似的代码在本地读取文档确实有效: 尝试3:现在是最奇怪的部分。我想文件需要先下载。因此,我首先使用Java下载了它,然后在本地执行前面的代码来读取文档。像第一个案例一样失败! 你知道这是怎么回事吗? 以下异常失败:javax.net.ssl.sslhandShakeException:sun.security.validat

  • 我想从Java程序接收Arduino Uno上的多个字节。arduino在收到数据后立即处理数据,因此我不需要存储它,我使用串行RX缓冲区作为临时存储,直到我实际读取字节为止。完全实现后,每次将发送大约150个字节,但我已经修改了缓冲区大小来解决这个问题。我使用jSerialComm作为java的串行库 我在下面放了一些arduino和java代码。当我从IDE的串行监视器发送字节,按预期点亮le

  • 对不起,如果这个问题是一个迟钝的,但我没有得到一个答案,我正在寻找。 Java docs这样说 通常,对读取器的每个读取请求都会导致对底层字符或字节流的相应读取请求。因此,建议将BufferedReader包装在任何读取()操作可能代价高昂的读取器周围,例如FileReaders>和InputStreamReaders。例如, 将缓冲来自指定文件的输入。如果不进行缓冲,每次调用read()或rea

  • 因此,我试图让我的Arduino与我的Qt项目进行通信,但QSerialPort从未发出readyRead()信号。I试验 https://www.youtube.com/watch?v=AX-HhBXBzGg 我使用此代码建立了串行连接,因此我的arduino的写LED正在闪烁并且它的端口繁忙。当我定期使用函数waitForReadyRead()时,我只能执行readSerial(),这是愚蠢的