QtQuick 串口通讯demo

SerialPortHandler.h

#ifndef SERIALPORTHANDLER_H
#define SERIALPORTHANDLER_H

#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>

class SerialPortHandler : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
    Q_PROPERTY(QString receivedData READ receivedData NOTIFY dataReceived)

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

    Q_INVOKABLE void openSerialPort(const QString &portName, int baudRate);
    Q_INVOKABLE void closeSerialPort();
    Q_INVOKABLE void sendData(const QString &data);
    Q_INVOKABLE QStringList availablePorts();

    bool connected() const;
    QString receivedData() const;

signals:
    void connectedChanged(bool connected);
    void dataReceived(const QString &data);
    void errorOccurred(const QString &error);

private slots:
    void handleReadyRead();
    void handleError(QSerialPort::SerialPortError error);

private:
    QSerialPort *m_serialPort;
    QString m_receivedData;
    bool m_connected;
};

#endif // SERIALPORTHANDLER_H

SerialPortHandler.cpp

 

#include "SerialPortHandler.h"
#include <QDebug>

SerialPortHandler::SerialPortHandler(QObject *parent)
    : QObject(parent), m_connected(false)
{
    m_serialPort = new QSerialPort(this);
    connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortHandler::handleReadyRead);
    connect(m_serialPort, &QSerialPort::errorOccurred, this, &SerialPortHandler::handleError);
}

void SerialPortHandler::openSerialPort(const QString &portName, int baudRate)
{
    if(m_serialPort->isOpen()) {
        closeSerialPort();
    }

    m_serialPort->setPortName(portName);
    m_serialPort->setBaudRate(baudRate);
    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::ReadWrite)) {
        m_connected = true;
        emit connectedChanged(true);
    } else {
        emit errorOccurred(tr("打开串口失败: ") + m_serialPort->errorString());
    }
}

void SerialPortHandler::closeSerialPort()
{
    if (m_serialPort->isOpen()) {
        m_serialPort->close();
        m_connected = false;
        emit connectedChanged(false);
    }
}

void SerialPortHandler::sendData(const QString &data)
{
//    if (m_serialPort->isOpen()) {
//        m_serialPort->write(data.toUtf8());
//        if (!m_serialPort->waitForBytesWritten(1000)) {
//            emit errorOccurred(tr("发送超时"));
//        }
//    }
}

QStringList SerialPortHandler::availablePorts()
{
    QStringList ports;
    for (const QSerialPortInfo &info : QSerialPortInfo::availablePorts()) {
        ports.append(info.portName());
    }
    return ports;
}

bool SerialPortHandler::connected() const {
    return m_connected;
}

QString SerialPortHandler::receivedData() const {
    return m_receivedData;
}

void SerialPortHandler::handleReadyRead()
{
    QByteArray data = m_serialPort->readAll();
    m_receivedData = QString::fromUtf8(data);
    emit dataReceived(m_receivedData);
}

void SerialPortHandler::handleError(QSerialPort::SerialPortError error)
{
    if (error != QSerialPort::NoError) {
        emit errorOccurred(m_serialPort->errorString());
        closeSerialPort();
    }
}
main.cpp
#include "SerialPortHandler.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
    
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
    QGuiApplication app(argc, argv);
    
    // 注册串口处理类
    qmlRegisterType<SerialPortHandler>("SerialPort", 1, 0, "SerialPortHandler");
    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    
    return app.exec();
}

 

main.qml

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import SerialPort 1.0

ApplicationWindow {
    width: 600
    height: 400
    visible: true
    title: "Qt Serial Port Demo"
    
    SerialPortHandler {
        id: serialPort
        onDataReceived: {
            if(receivedText.lineCount>30){
                
                // 按换行符分割文本
                var lines = receivedText.text.split('\n');
                // 删除第一行(如果存在)
                if (lines.length > 1) {
                    lines.shift(); // 移除数组第一个元素
                    receivedText.text = lines.join('\n');
                } else {
                    receivedText.text = ""; // 只剩一行时清空
                }
            }
            
            receivedText.append("接收: " + data)
        }
        onErrorOccurred: {
            statusLabel.text = "错误: " + error
        }
    }
    
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 10
        
        // 串口选择
        RowLayout {
            Label { text: "选择串口:" }
            ComboBox {
                id: portComboBox
                Layout.fillWidth: true
                model: serialPort.availablePorts()
            }
            
            Label { text: "波特率:" }
            ComboBox {
                id: baudComboBox
                model: [9600, 19200, 38400, 57600, 115200]
                currentIndex: 4  // 默认115200
            }
            
            Button {
                text: serialPort.connected ? "断开" : "连接"
                onClicked: {
                    if(serialPort.connected) {
                        serialPort.closeSerialPort()
                    } else {
                        serialPort.openSerialPort(portComboBox.currentText, baudComboBox.currentText)
                    }
                }
            }
        }
        
        // 发送区域
        GroupBox {
            title: "发送数据"
            Layout.fillWidth: true
            ColumnLayout {
                TextField {
                    id: sendField
                    Layout.fillWidth: true
                    placeholderText: "输入要发送的数据"
                    onAccepted: sendButton.clicked()
                }
                Button {
                    id: sendButton
                    text: "发送"
                    onClicked: {
                        if(sendField.text.length > 0) {
                            serialPort.sendData(sendField.text)
                            receivedText.append("发送: " + sendField.text)
                            sendField.clear()
                        }
                    }
                }
            }
        }
        
        // 接收区域
        GroupBox {
            title: "接收数据"
            Layout.fillWidth: true
            Layout.fillHeight: true
            
            ScrollView {
                anchors.fill: parent
                TextArea {
                    id: receivedText
                    readOnly: true
                    wrapMode: Text.Wrap
                }
            }
        }
        
        // 状态栏
        Label {
            id: statusLabel
            Layout.fillWidth: true
            text: serialPort.connected ?
                      "已连接: " + portComboBox.currentText + " @ " + baudComboBox.currentText + " bps" :
                      "未连接"
        }
    }
}

 

posted @ 2025-06-04 16:53  liliyou  阅读(35)  评论(0)    收藏  举报