QSerialPort 有可用字节,但无法读取



我正在编写一个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发送东西的大多数时候,信号都会被发出,并且串行端口->bytesAvailable()返回一个不为零的数字,但是serialPort->waitForReadyRead(20)超时而没有接收到任何东西并且serialPort->readAll()返回一个空的QString。如果我使用serialPort->waitForReadyRead(-1)窗口冻结。

最奇怪的是,在发送东西的随机时刻,一切都很好,函数返回了以前无法读取的所有数据。

下面是一个例子:

第一次尝试(失败)

Qt将PC_REQUESTED_LED_STATE_CHANGE(u8"CHANGELED")写入串行端口

Arduino LED改变其状态(打开)

Arduino将Arduino_TURNED_LED_ON("LEDON")写入串行端口

Qt从Arduino 读取一个空的QString

第二次尝试(失败)

Qt将PC_REQUESTED_LED_STATE_CHANGE(u8"CHANGELED")写入串行端口

Arduino LED改变其状态(关闭)

Arduino将Arduino_TURNED_LED_OFF("LEDOFF")写入串行端口

Qt从Arduino 读取一个空的QString

第三次尝试(这是一次随机尝试,一切正常)

Qt将PC_REQUESTED_LED_STATE_CHANGE(u8"CHANGELED")写入串行端口

Arduino LED改变其状态(打开)

Arduino将Arduino_TURNED_LED_ON("LEDON")写入串行端口

Qt读";LEDONLEDOFFLEDON";来自Arduino,这是以前无法阅读的所有内容。

第4次尝试(失败)

Qt将PC_REQUESTED_LED_STATE_CHANGE(u8"CHANGELED")写入串行端口

Arduino LED改变其状态(关闭)

Arduino将Arduino_TURNED_LED_OFF("LEDOFF")写入串行端口

Qt从Arduino 读取一个空的QString

第5次尝试(这是另一次随机尝试,一切正常)

Qt将PC_REQUESTED_LED_STATE_CHANGE(u8"CHANGELED")写入串行端口

Arduino LED改变其状态(打开)

Arduino将Arduino_TURNED_LED_ON("LEDON")写入串行端口

Qt读";LEDOFFLEDON";来自Arduino,这是以前无法阅读的所有内容。

我使用Arduino IDE串行监视器进行了测试,它按照预期工作:;CHANGELED";,则LED改变并且Arduino回答";LEDON";或";LEDOFF";一直以来。

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

编辑:完整的代码可以在这里找到

Read方法不正确且不必要。您永远不应该使用waitFor方法。在处理简单的ASCII数据时也不应该使用QStringQByteArray可以很好地处理这些数据:

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发送完整的线路-用Serial.println替换Serial.write,你的生活会更轻松。然后线路就是数据包,你不需要自己缓冲数据:

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硬件,请参阅此答案以获取示例。

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

如果你在Linux上,你也可以尝试用将你的设备连接到raw

stty -F /dev/ttyACM0 raw

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

相关内容

  • 没有找到相关文章

最新更新