如何将Arduino UART发送的二维数组存入Qt QList<QString>并在QML显示
我来帮你一步步解决这个问题,看起来主要卡在三个地方:Arduino的数据传输格式、Qt端的数据解析与存储、QML的数据绑定。咱们逐个击破:
1. 修复Arduino的数据传输格式
你现在的Arduino代码直接连续打印double值,导致所有数据连在一起,Qt根本没法区分每个元素(比如1.012.02这种字符串,谁知道是两个数还是一个?)。所以必须给每个数据加分隔符,每行结束加换行标识一行完成:
void setup(){ pinMode(LED_BUILTIN,OUTPUT); analogWrite(LED_BUILTIN,255); Serial.begin(115200); } void loop(){ double data[17][17]; if(Serial.available()){ delay(100); for(int i=0; i<17; i++){ for(int j=0; j<17; j++){ data[i][j] = i+j+0.01; sendData(data[i][j]); delay(10); } Serial.println(); // 每行结束发送换行,标记一行数据完成 } } return; } void sendData(double data){ Serial.print(data); Serial.print(","); // 每个数据后加逗号作为分隔符 }
2. 改进Qt端的串口数据解析与存储
你的readSerial函数目前只是读取数据并打印,没有做解析和存储。需要添加缓冲区累积数据,拆分分隔符,填充到QList<QString>并触发更新信号:
修改serial.h
添加缓冲区变量,调整Q_PROPERTY名称(和QML里的调用一致):
#include <QQmlApplicationEngine> #include <QSerialPort> #include <QSerialPortInfo> #include <QtDebug> class serial: public QObject { Q_OBJECT // 把Q_PROPERTY的名称改成model_data,和QML里的调用对应 Q_PROPERTY(QList<QString> model_data READ text NOTIFY textChanged) public: explicit serial(QQmlApplicationEngine *engine, QObject *parent = nullptr); ~serial(); void setupSerial(); Q_INVOKABLE QList<QString> text(){ return m_text; } private slots: void readSerial(); private: QQmlApplicationEngine* m_engine; QSerialPort arduino; bool arduino_is_avaiable; QString portName; QByteArray m_buffer; // 新增:缓存串口数据,防止一次读不全 QList<QString> m_text; signals: void textChanged(); }; #endif // SERIAL_H
修改readSerial函数
实现数据解析、填充和更新通知:
void serial::readSerial(){ // 把读取到的数据累积到缓冲区 m_buffer += arduino.readAll(); // 循环处理每一行数据(直到缓冲区里没有换行符) while (m_buffer.contains('\n')) { // 提取一行数据 QByteArray line = m_buffer.left(m_buffer.indexOf('\n')); // 从缓冲区移除已处理的行 m_buffer.remove(0, m_buffer.indexOf('\n') + 1); // 用逗号拆分一行里的所有数据 QStringList rowElements = QString(line).split(',', Qt::SkipEmptyParts); if (rowElements.size() != 17) { qWarning() << "收到无效行,数据个数不对:" << rowElements.size(); continue; } // 静态变量记录已收到的行数,满17行就重置并通知QML static int receivedRows = 0; if (receivedRows == 0) { m_text.clear(); // 开始接收新的17x17数组时清空旧数据 } m_text.append(rowElements); // 把当前行的17个元素加入列表 receivedRows++; if (receivedRows == 17) { receivedRows = 0; emit textChanged(); // 触发信号,通知QML数据已更新 qDebug() << "已接收完整17x17数据,总元素数:" << m_text.size(); } } }
确保串口初始化正确
在setupSerial函数里完成串口配置和信号连接(如果之前没写的话):
void serial::setupSerial(){ // 遍历可用串口,匹配Arduino的VID/PID(自行根据你的Arduino型号调整) foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){ if(info.vendorIdentifier() == 0x2341 && info.productIdentifier() == 0x0043){ portName = info.portName(); arduino_is_avaiable = true; break; } } if(arduino_is_avaiable){ arduino.setPortName(portName); arduino.open(QSerialPort::ReadOnly); arduino.setBaudRate(QSerialPort::Baud115200); arduino.setDataBits(QSerialPort::Data8); arduino.setParity(QSerialPort::NoParity); arduino.setStopBits(QSerialPort::OneStop); arduino.setFlowControl(QSerialPort::NoFlowControl); // 连接串口就绪信号到读取槽函数 connect(&arduino, &QSerialPort::readyRead, this, &serial::readSerial); qDebug() << "串口已打开:" << portName; } else { qDebug() << "未找到Arduino设备!"; } }
别忘了在serial的构造函数里调用setupSerial():
serial::serial(QQmlApplicationEngine *engine, QObject *parent) : QObject(parent), m_engine(engine){ setupSerial(); }
3. 修正QML的数据绑定
现在QML里的Text绑定已经是Serial.model_data[index],和我们修改的Q_PROPERTY名称一致,只要确保Repeater的model是17*17,索引就能对应到m_text里的每个元素:
import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 17*square_size height: 17*square_size title: qsTr("17x17 Matrix Display") property int square_size: 30 Grid { id: grid columns: 17 Repeater{ id: rpt model: 17*17 Rectangle{ width: square_size height: square_size border.color: "black" border.width: 1 Text { anchors.centerIn: parent // 绑定到Serial的model_data列表,index对应每个矩形的位置 text: Serial.model_data[index] || "" // 为空时显示空字符串 } } } } }
关键注意点
- 确保Arduino和Qt的串口波特率都是115200,参数一致(数据位、停止位、校验位)
- Arduino的VID/PID需要根据你的实际型号调整(比如Nano是0x1A86,PID 0x7523)
- 如果数据更新不及时,检查
textChanged信号是否正确触发,QML会自动响应信号刷新UI
内容的提问来源于stack exchange,提问作者TrungPC
相关产品推荐
相关产品推荐

