You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4通过Qt读取UART(ttyS0)数据并显示至QML的问题求助

Raspberry Pi 4 UART(ttyS0)数据接收问题(Qt/QML)

我是Raspbian系统和编程新手,在树莓派4的UART(ttyS0)接收ADC转换器的十六进制字符串数据时遇到问题。我用Przemytnik类衔接C++与QML(后续要扩展更多类),采用QSerialPort库编写代码,但数据无法正常显示,修改后仍无效,寻求帮助。


现有代码

SerialReader.h

#ifndef SERIALREADER_H
#define SERIALREADER_H

#include <QObject>
#include <QSerialPort>

class SerialReader : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString data READ data NOTIFY dataChanged)

public:
    explicit SerialReader(QObject *parent = nullptr);

    QString data() const;
    Q_INVOKABLE void readData();
    void writeData(const QString &data);

signals:
    void dataChanged();

private:
    QSerialPort m_serialPort;
    QString m_data;
};

#endif // SERIALREADER_H

SerialReader.cpp

#include <SerialReader.h>
#include <iostream>

SerialReader::SerialReader(QObject *parent) : QObject(parent) {
    m_serialPort.setPortName("/dev/ttyS0");
    m_serialPort.setBaudRate(QSerialPort::Baud115200);
    m_serialPort.setDataBits(QSerialPort::Data8);
    m_serialPort.setParity(QSerialPort::NoParity);
    m_serialPort.setStopBits(QSerialPort::OneStop);
    m_serialPort.setFlowControl(QSerialPort::NoFlowControl);

    if (!m_serialPort.open(QIODevice::ReadOnly)) {
        std::cerr << "Błąd portu szeregowego!";
    }
}

QString SerialReader::data() const { return m_data; }

void SerialReader::readData() {
    if (m_serialPort.isOpen() && m_serialPort.isReadable()) {
        m_data = m_serialPort.readAll();
        emit dataChanged();
    }
}

void SerialReader::writeData(const QString &data) {
    if (m_serialPort.isOpen() && m_serialPort.isWritable()) {
        m_serialPort.write(data.toUtf8());
    }
}

przemytnik.h

#ifndef PRZEMYTNIK_H
#define PRZEMYTNIK_H

#include <QObject>
#include <SerialReader.h>

class Przemytnik : public QObject
{
    Q_OBJECT
    Q_PROPERTY(SerialReader* serialReader READ serialReader WRITE setSerialReader NOTIFY serialReaderChanged)

public:
    explicit Przemytnik(QObject *parent = nullptr);

    SerialReader* serialReader() const;
    void setSerialReader(SerialReader* serialReader);

signals:
    void serialReaderChanged();

private:
    SerialReader* m_serialReader;
};

#endif // PRZEMYTNIK_H

przemytnik.cpp

#include <przemytnik.h>

Przemytnik::Przemytnik(QObject *parent) : QObject(parent), m_serialReader(new SerialReader(this)) {
    m_serialReader->readData();
}

SerialReader* Przemytnik::serialReader() const { return m_serialReader; }

void Przemytnik::setSerialReader(SerialReader* serialReader) {
    if (serialReader != m_serialReader) {
        m_serialReader = serialReader;
        emit serialReaderChanged();
    }
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.3
import port 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Item{
        Przemytnik{
            id: przemytnik
        }
        Text {
            text: przemytnik.serialReader.data
        }
    }
}

问题分析与修复方案

1. 监听串口数据到来事件

当前仅在Przemytnik构造时调用一次readData(),无法自动读取新数据。需要连接QSerialPort的readyRead()信号到readData()槽:

// 修改SerialReader构造函数
SerialReader::SerialReader(QObject *parent) : QObject(parent) {
    m_serialPort.setPortName("/dev/ttyS0");
    m_serialPort.setBaudRate(QSerialPort::Baud115200);
    m_serialPort.setDataBits(QSerialPort::Data8);
    m_serialPort.setParity(QSerialPort::NoParity);
    m_serialPort.setStopBits(QSerialPort::OneStop);
    m_serialPort.setFlowControl(QSerialPort::NoFlowControl);

    if (!m_serialPort.open(QIODevice::ReadOnly)) {
        std::cerr << "Błąd portu szeregowego!";
    } else {
        // 自动响应新数据
        connect(&m_serialPort, &QSerialPort::readyRead, this, &SerialReader::readData);
    }
}

2. 十六进制数据格式转换

ADC返回的原始字节直接转QString会乱码,需转为十六进制字符串:

// 修改readData函数
#include <QDebug>
void SerialReader::readData() {
    if (m_serialPort.isOpen() && m_serialPort.isReadable()) {
        QByteArray rawData = m_serialPort.readAll();
        // 将原始字节转为带空格分隔的十六进制字符串
        m_data = rawData.toHex(' ');
        qDebug() << "Received hex data:" << m_data; // 调试输出
        emit dataChanged();
    }
}

3. 树莓派UART权限配置

普通用户默认无/dev/ttyS0访问权限,执行以下命令并重启:

sudo usermod -a -G dialout $USER

4. 启用树莓派硬件UART

  1. 打开配置工具:sudo raspi-config
  2. 进入Interface Options -> Serial Port
  3. 选择"否"关闭串口控制台,选择"是"启用硬件串口
  4. 重启树莓派生效

5. 移除冗余调用

现在已通过信号自动触发读取,删除Przemytnik构造中的主动调用:

Przemytnik::Przemytnik(QObject *parent) : QObject(parent), m_serialReader(new SerialReader(this)) {
    // 移除该行:m_serialReader->readData();
}

内容的提问来源于stack exchange,提问作者Jimmy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:35:55