SerialPortItem对串口再封装一层,省去一些常用的步骤,不用每次都去写类

SerialPortItem

cpp 复制代码
#pragma once

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

enum SerialPortState {
    CloseState,
    Opened,
    OpenFail,
    PortNameError
};
Q_DECLARE_METATYPE(SerialPortState)

class SerialPortItem : public QObject
{
    Q_OBJECT
public:
    using DataCallback = std::function<void(const QByteArray&)>;

    explicit SerialPortItem(DataCallback callback = nullptr, QObject* parent = nullptr);
    ~SerialPortItem() override;

    // 参数设置
    void setPortName(const QString& portName);
    QString portName() const;

    void setBaudRate(int baudRate);
    int baudRate() const;

    void setDataBits(QSerialPort::DataBits bits);
    QSerialPort::DataBits dataBits() const;

    void setStopBits(QSerialPort::StopBits bits);
    QSerialPort::StopBits stopBits() const;

    void setParity(QSerialPort::Parity parity);
    QSerialPort::Parity parity() const;

    // 状态查询
    bool isOpen() const;
    SerialPortState state() const;

    // 打开 / 关闭
    void start();
    void stop();

    // 发送
    void send(const QByteArray& data);
    void send(const char* data, int len);

    // 底层对象
    QSerialPort* serialPort() const;

    // 列出当前系统可用串口
    static QStringList availablePortNames();

signals:
    void RecData(const QByteArray& data, SerialPortItem* self);
    void StateChanged(SerialPortState state);

private:
    void onReadyRead();
    void onError(QSerialPort::SerialPortError err);
    void updateState(SerialPortState s);

    QSerialPort* m_SerialPort = nullptr;
    DataCallback m_datacallback;
    QString m_portName;
    int m_baudRate = 115200;
    QSerialPort::DataBits m_dataBits = QSerialPort::Data8;
    QSerialPort::StopBits m_stopBits = QSerialPort::OneStop;
    QSerialPort::Parity   m_parity   = QSerialPort::NoParity;
    SerialPortState m_state = CloseState;
};

SerialPortItem.cpp

cpp 复制代码
#include "SerialPortItem.h"
#include <QDebug>

SerialPortItem::SerialPortItem(DataCallback callback, QObject* parent)
    : QObject(parent)
    , m_SerialPort(new QSerialPort(this))
    , m_datacallback(std::move(callback))
{
    // 默认选第一个可用串口
    const auto ports = QSerialPortInfo::availablePorts();
    if (!ports.isEmpty()) {
        m_portName = ports.first().portName();
    }

    connect(m_SerialPort, &QSerialPort::readyRead,
            this, &SerialPortItem::onReadyRead);
    connect(m_SerialPort, &QSerialPort::errorOccurred,
            this, &SerialPortItem::onError);

    qRegisterMetaType<SerialPortState>("SerialPortState");
}

SerialPortItem::~SerialPortItem()
{
    stop();
}

// ---------------- getters / setters ----------------

void SerialPortItem::setPortName(const QString& portName) { m_portName = portName; }
QString SerialPortItem::portName() const { return m_portName; }

void SerialPortItem::setBaudRate(int baudRate) { m_baudRate = baudRate; }
int SerialPortItem::baudRate() const { return m_baudRate; }

void SerialPortItem::setDataBits(QSerialPort::DataBits bits) { m_dataBits = bits; }
QSerialPort::DataBits SerialPortItem::dataBits() const { return m_dataBits; }

void SerialPortItem::setStopBits(QSerialPort::StopBits bits) { m_stopBits = bits; }
QSerialPort::StopBits SerialPortItem::stopBits() const { return m_stopBits; }

void SerialPortItem::setParity(QSerialPort::Parity parity) { m_parity = parity; }
QSerialPort::Parity SerialPortItem::parity() const { return m_parity; }

bool SerialPortItem::isOpen() const
{
    return m_SerialPort && m_SerialPort->isOpen();
}

SerialPortState SerialPortItem::state() const
{
    return m_state;
}

QSerialPort* SerialPortItem::serialPort() const
{
    return m_SerialPort;
}

QStringList SerialPortItem::availablePortNames()
{
    QStringList names;
    const auto ports = QSerialPortInfo::availablePorts();
    for (const auto& info : ports) {
        names << info.portName();
    }
    return names;
}

// ---------------- 打开 / 关闭 ----------------

void SerialPortItem::start()
{
    if (isOpen()) {
        return;
    }

    // 1. 校验串口号
    bool found = false;
    const auto ports = QSerialPortInfo::availablePorts();
    for (const auto& info : ports) {
        if (info.portName() == m_portName) {
            found = true;
            break;
        }
    }
    if (!found) {
        qWarning() << "[Serial] 串口号不存在:" << m_portName;
        updateState(PortNameError);
        return;
    }

    // 2. 统一设置参数
    m_SerialPort->setPortName(m_portName);
    m_SerialPort->setBaudRate(m_baudRate);
    m_SerialPort->setDataBits(m_dataBits);
    m_SerialPort->setParity(m_parity);
    m_SerialPort->setStopBits(m_stopBits);
    m_SerialPort->setFlowControl(QSerialPort::NoFlowControl);

    // 3. 打开
    if (!m_SerialPort->open(QIODevice::ReadWrite)) {
        qWarning() << "[Serial] 打开失败:" << m_SerialPort->errorString();
        updateState(OpenFail);
    } else {
        qInfo() << "[Serial] 打开成功:" << m_portName << "@" << m_baudRate;
        updateState(Opened);
    }
}

void SerialPortItem::stop()
{
    if (m_SerialPort->isOpen()) {
        m_SerialPort->close();
        qInfo() << "[Serial] 已关闭:" << m_portName;
    }
    updateState(CloseState);
}

// ---------------- 收数据 ----------------

void SerialPortItem::onReadyRead()
{
    const QByteArray buffer = m_SerialPort->readAll();
    if (buffer.isEmpty()) {
        return;
    }

    emit RecData(buffer, this);

    if (m_datacallback) {
        m_datacallback(buffer);
    }
}

// ---------------- 发送 ----------------

void SerialPortItem::send(const QByteArray& data)
{
    if (!isOpen() || data.isEmpty()) {
        return;
    }
    m_SerialPort->write(data);
}

void SerialPortItem::send(const char* data, int len)
{
    if (!isOpen() || data == nullptr || len <= 0) {
        return;
    }
    m_SerialPort->write(data, len);
}

// ---------------- 错误 / 状态 ----------------

void SerialPortItem::onError(QSerialPort::SerialPortError err)
{
    if (err == QSerialPort::NoError) {
        return;
    }

    qWarning() << "[Serial] 错误:" << err << m_SerialPort->errorString();

    // 断线 / 设备被拔掉,自动关闭并通知
    if (err == QSerialPort::ResourceError ||
        err == QSerialPort::DeviceNotFoundError ||
        err == QSerialPort::PermissionError) {
        if (m_SerialPort->isOpen()) {
            m_SerialPort->close();
        }
        updateState(CloseState);
    }
}

void SerialPortItem::updateState(SerialPortState s)
{
    if (m_state == s) {
        return;
    }
    m_state = s;
    emit StateChanged(m_state);
}

main.cpp(示范用法)

cpp 复制代码
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include "SerialPortItem.h"

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);

    // 1. 打印当前可用串口
    const QStringList ports = SerialPortItem::availablePortNames();
    qInfo() << "可用串口:" << ports;
    if (ports.isEmpty()) {
        qWarning() << "没有找到串口设备,程序退出";
        return 0;
    }

    // 2. 创建串口对象,传入收数据回调
    auto* sp = new SerialPortItem([](const QByteArray& data) {
        qInfo() << "[回调] 收到数据:" << data;
    }, &app);

    // 3. 配置参数(默认就是 115200/8/1/无校验,这里只改串口名)
    sp->setPortName(ports.first());
    sp->setBaudRate(115200);

    // 4. 监听状态变化
    QObject::connect(sp, &SerialPortItem::StateChanged,
                     [](SerialPortState s) {
        switch (s) {
        case CloseState:    qInfo() << "状态: 已关闭";     break;
        case Opened:        qInfo() << "状态: 已打开";     break;
        case OpenFail:      qInfo() << "状态: 打开失败";   break;
        case PortNameError: qInfo() << "状态: 串口号错误"; break;
        }
    });

    // 5. 监听数据信号(和回调二选一即可,这里都示范一下)
    QObject::connect(sp, &SerialPortItem::RecData,
                     [](const QByteArray& data, SerialPortItem*) {
        qInfo() << "[信号] 收到数据:" << data;
    });

    // 6. 打开串口
    sp->start();

    // 7. 定时发送测试数据
    int counter = 0;
    QTimer sendTimer;
    QObject::connect(&sendTimer, &QTimer::timeout, [&]() {
        if (sp->isOpen()) {
            const QByteArray msg = QString("Hello %1\n").arg(counter++).toUtf8();
            sp->send(msg);
            qInfo() << "[发送]" << msg.trimmed();
        }
    });
    sendTimer.start(1000);

    // 8. 10 秒后关闭串口并退出
    QTimer::singleShot(10000, [&]() {
        qInfo() << "10 秒到,关闭串口并退出";
        sp->stop();
        sendTimer.stop();
        app.quit();
    });

    return app.exec();
}
相关推荐
用户83344239661413 小时前
从批量操作到任务中心,再到现场工作台:DeviceForge v2.10—v2.12 完整演进
qt
宛 禾15 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
打工仔折腾 AI20 小时前
Qt网络编程实战:UDP、TCP到HTTP的落地经验与选型
网络·人工智能·后端·python·qt·udp·ai agent 实战
Lhan.zzZ20 小时前
Linux + Qt/QML:解决 QtQuick.VirtualKeyboard.Plugins 模块加载失败与环境变量配置
linux·数据库·qt
誰能久伴不乏1 天前
QT工业上位机一次「指令静默丢失」的排查
qt·docker·github
扶尔魔ocy2 天前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行并进行态势标绘(四)
qt·opengl·osg
橙橙笔记2 天前
QT安卓软件的制作
android·git·qt·软件
芦芭荞2 天前
QT使用xml模版生成word文档
xml·qt·word
mengzhi啊2 天前
qt把结构体数据存入json文件
qt·json