必备条件

在**.Pro**文件中添加

QT += serialport    

在**.h**中需要添加的头文件

#include <QSerialPort>
#include <QSerialPortInfo>

我会把源码虚拟串口串口调试助手,分开打包放再资料里面,供大家参考和测试,如果有遇到下载问题或代码问题可以留言!!!

项目源码
https://download.csdn.net/download/qq_48974566/88632554
UartAssist串口调试助手
https://download.csdn.net/download/qq_48974566/88632557
虚拟串口工具 下载连接
https://download.csdn.net/download/qq_48974566/88632541
网盘包含全部:https://pan.baidu.com/s/1y6STtmUzVWZB7sx5Ii-yvg?pwd=nj51
提取码:nj51

主界面UI

image-20231215141121343

弹窗串口设置UI

image-20231215141212796

程序演示

Serialport 00_00_00-00_00_30

主线程中使用QSerialPort

如果说没有需要创建线程需求,并且串口打开操作都在主线程中,那么这部分内容就可以满足你的需求

这个部分其实很简单,直接上代码CV即可(Ps: 个人觉得注释还是挺全的一眼董)

在**.Pro**文件中添加

QT += serialport

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
// 线程 相关 Bgein ------------
#include "./configrwserialport.h"
#include "./uiserialport.h"
//------------ 线程 相关 End

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_btn_openConsole_clicked();

    void on_btnSend_clicked();

    void on_conserialport_clicked();

private:
    Ui::Widget *ui;
    QSerialPort *serial_1;

    // 线程 相关变量 Bgein ------------
    QThread *threadserialport;
    configRWserialport *confSeriaPort;
    uiSerialPort *uiserialport;
    //------------ 线程 相关变量 End

    void SerialPortConfigInit();
    void readData();

};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 初始化串口配置 ----- 主线程
    serial_1 = new QSerialPort();
    SerialPortConfigInit();
    // -------------- end 主线程


    // confSeriaPort = new configRWserialport();
    // 串口配置界面
    uiserialport = new uiSerialPort();


#if 1
    // 线程 Begin -------------
    confSeriaPort = new configRWserialport();
    threadserialport = new QThread;

    confSeriaPort->moveToThread(threadserialport);
    // 回收 串口数据处理类
    connect(threadserialport, &QThread::finished, confSeriaPort, &configRWserialport::deleteLater);
    // 回收 子线程变量
    connect(threadserialport, &QThread::finished, threadserialport, &QThread::deleteLater);
    // 通知串口配置初始化
    connect(threadserialport, &QThread::started, confSeriaPort, &configRWserialport::slot_serialporInit);
    // 启动线程
    threadserialport->start();

    // 点击打开串口 触发 线程 设置线程波特率、串口名... 打开串口
    connect(uiserialport, &uiSerialPort::signal_setConfigSerialPort,
            confSeriaPort, &configRWserialport::slot_configSrialport);
    // 关闭串口
    connect(uiserialport, &uiSerialPort::signal_closeOpen,
            confSeriaPort, &configRWserialport::slot_closeOpneSrialport);

    connect(confSeriaPort, &configRWserialport::signal_serialStatus,
            uiserialport, &uiSerialPort::slots_openOrNot);

    // ---------------- end 线程

#endif
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btn_openConsole_clicked()
{
    if (ui->btn_openConsole->text() == tr("打开串口"))
    {
        //设置串口名字
        serial_1->setPortName(ui->comboBox_serialPort->currentText());

        //设置波特率
        serial_1->setBaudRate(ui->comboBox_baudRate->currentText().toInt());

        //设置数据位
        serial_1->setDataBits(QSerialPort::Data8);

        //设置奇偶校验位
        serial_1->setParity(QSerialPort::NoParity);

        //设置停止位
        serial_1->setStopBits(QSerialPort::OneStop);

        //设置流控
        serial_1->setFlowControl(QSerialPort::NoFlowControl);

        //打开串口
        if (serial_1->open(QIODevice::ReadWrite))
        {
            ui->comboBox_baudRate->setEnabled(false);
            ui->comboBox_dataBits->setEnabled(false);
            ui->comboBox_parity->setEnabled(false);
            ui->comboBox_serialPort->setEnabled(false);
            ui->comboBox_stopBit->setEnabled(false);
            ui->btn_openConsole->setText(tr("关闭串口"));
            //信号与槽函数关联 串口类readread信号在收到数据后会自动触发的
            connect(serial_1, &QSerialPort::readyRead, this, &Widget::readData);
        }
    }
    else
    {
        //关闭串口
        serial_1->close();
        serial_1->deleteLater();

        //恢复设置功能
        ui->comboBox_baudRate->setEnabled(true);
        ui->comboBox_dataBits->setEnabled(true);
        ui->comboBox_parity->setEnabled(true);
        ui->comboBox_serialPort->setEnabled(true);
        ui->comboBox_stopBit->setEnabled(true);
        ui->btn_openConsole->setText(tr("打开串口"));
    }
}

static const char blankString[] = QT_TRANSLATE_NOOP("SettingsDialog", "N/A");
void Widget::SerialPortConfigInit()
{
    //获取可以用的串口
    QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();

    QString description;
    QString manufacturer;
    QString serialNumber;

    //输出当前系统可以使用的串口个数
     qDebug() << "Total numbers of ports: " << serialPortInfos.count();

     //将所有可以使用的串口设备添加到ComboBox中
     for (const QSerialPortInfo &serialPortInfo : serialPortInfos) {
         QStringList list;
         description = serialPortInfo.description();
         manufacturer = serialPortInfo.manufacturer();
         serialNumber = serialPortInfo.serialNumber();

         list << serialPortInfo.portName()
              << (!description.isEmpty() ? description : blankString)
              << (!manufacturer.isEmpty() ? manufacturer : blankString)
              << (!serialNumber.isEmpty() ? serialNumber : blankString)
              << serialPortInfo.systemLocation()
              << (serialPortInfo.vendorIdentifier() ? QString::number(serialPortInfo.vendorIdentifier(), 16) : blankString)
              << (serialPortInfo.productIdentifier() ? QString::number(serialPortInfo.productIdentifier(), 16) : blankString);

         ui->comboBox_serialPort->addItem(list.first(), list);
     }

     ui->comboBox_serialPort->addItem(tr("custom"));

     //设置波特率
    // ui->comboBox_baudRate->addItem(QStringLiteral("4800"), QSerialPort::Baud4800);
    ui->comboBox_baudRate->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
    ui->comboBox_baudRate->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
    ui->comboBox_baudRate->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
    ui->comboBox_baudRate->addItem(QStringLiteral("57600"), QSerialPort::Baud57600);
    ui->comboBox_baudRate->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);
    ui->comboBox_baudRate->addItem(tr("Custom"));

    //设置数据位
    ui->comboBox_dataBits->addItem(QStringLiteral("5"), QSerialPort::Data5);
    ui->comboBox_dataBits->addItem(QStringLiteral("6"), QSerialPort::Data6);
    ui->comboBox_dataBits->addItem(QStringLiteral("7"), QSerialPort::Data7);
    ui->comboBox_dataBits->addItem(QStringLiteral("8"), QSerialPort::Data8);
    ui->comboBox_dataBits->setCurrentIndex(3);

    //设置奇偶校验位
    ui->comboBox_parity->addItem(tr("None"), QSerialPort::NoParity);
    ui->comboBox_parity->addItem(tr("Even"), QSerialPort::EvenParity); // 偶
    ui->comboBox_parity->addItem(tr("Odd"), QSerialPort::OddParity); // 奇
    ui->comboBox_parity->addItem(tr("Mark"), QSerialPort::MarkParity);
    ui->comboBox_parity->addItem(tr("Space"), QSerialPort::SpaceParity);

    //设置停止位
    ui->comboBox_stopBit->addItem(QStringLiteral("1"), QSerialPort::OneStop);
    ui->comboBox_stopBit->addItem(QStringLiteral("2"), QSerialPort::TwoStop);

#if 0
    //添加流控
    ui->comboBox_flowBit->addItem(tr("None"), QSerialPort::NoFlowControl);
    ui->comboBox_flowBit->addItem(tr("RTS/CTS"), QSerialPort::HardwareControl);
    ui->comboBox_flowBit->addItem(tr("XON/XOFF"), QSerialPort::SoftwareControl);
#endif
}

void Widget::readData()
{

    QByteArray buf = serial_1->readAll();
    if (!buf.isEmpty()) {
        char* rawBuf=buf.data();
        qDebug() << rawBuf;
        // qDebug()<<"read current value "<< *(uint16_t*)(rawBuf + 3);
    }
    return ;
}

void Widget::on_btnSend_clicked()
{
    QByteArray msg;
    msg = ui->Editmsg->toPlainText().toUtf8();
    if(msg.isEmpty()) return ;
    int ret=serial_1->write(msg);
}


void Widget::on_conserialport_clicked()
{
    uiserialport->show();
}

Qt串口QSerialPortd的多线程(moveTo + 信号 + 槽)

1. QSerialPort的多线程限制

在Qt官方文档中提到,QSerialPort是不不支持跨线程调用的(Ps:在Qt中大部分是都不支持跨线程的)

image-20231214111812333

因此不能在主线程(UI线程)创建QSerialPort,然后传递个指针给子线程,然后在子线程中执行耗时的读写任务。
最好的方式是在子线程里面创建QSerialPort,然后主线程通过信号槽来间接使用(参数还是可以通过QSerialPort的指针来读写)。

global.h 这里懒了一下,因为Qt想通过信号与槽机制传自定义类型(如:struct configSerialport {};)需要注册元类型

// 注册元类型,使用MyType标识该类型
qRegisterMetaType<MyType>("MyType");
// 这里简单说一下可以自己添加下试试(Ps:针对本程序可以在widget.cpp 中添加)

进入正题!global.h

#ifndef GLOBAL_H
#define GLOBAL_H

#include "head.h"

struct configSerialport {
    // 串口名
    QString PortName;
    // 波特率
    int BaudRate;
//    QSerialPort::DataBits data;
//    QSerialPort::Parity Parity;
} ;


#endif // GLOBAL_H

global.cpp

#include "global.h"

struct configSerialport confSet;

configrwserialport.h 处理,读、写、串口创建

#ifndef CONFIGRWSERIALPORT_H
#define CONFIGRWSERIALPORT_H

#include <QObject>
#include "head.h"
#include "global.h"

class configRWserialport : public QObject
{
    Q_OBJECT
public:

    explicit configRWserialport(QObject *parent = nullptr);

signals:

    void signal_serialportChanged();
    void signal_serialStatus(bool );

private :
    QSerialPort *serialport = NULL;
    void writeData();
    QTimer *timer_Serialport;

public slots:
    void slot_serialporInit();
    void slot_configSrialport();
    void slot_closeOpneSrialport();
private slots :
    void slots_readData();
};

#endif // CONFIGRWSERIALPORT_H

configrwserialport.cpp

#include "configrwserialport.h"

configRWserialport::configRWserialport(QObject *parent)
    : QObject{parent}
{

}

extern struct configSerialport confSet;
void configRWserialport::slot_configSrialport()
{
    qDebug() << "串口打开 中";
    //设置串口名字   
    serialport->setPortName(confSet.PortName);

    //设置波特率
    serialport->setBaudRate(confSet.BaudRate);

    //设置数据位
    serialport->setDataBits(QSerialPort::Data8);

    //设置奇偶校验位
    serialport->setParity(QSerialPort::NoParity);

    //设置停止位
    serialport->setStopBits(QSerialPort::OneStop);

    //设置流控
    serialport->setFlowControl(QSerialPort::NoFlowControl);

    //打开串口
    if (serialport->open(QIODevice::ReadWrite))
    {
        qDebug() << "串口打开";
        // writeData();
         timer_Serialport->start(300);
        emit signal_serialStatus(true);
        //信号与槽函数关联
        connect(serialport, &QSerialPort::readyRead, this, &configRWserialport::slots_readData);
    }

}

void configRWserialport::slot_closeOpneSrialport() {
    //关闭串口
    serialport->close();
    serialport->deleteLater();
    serialport = NULL;
    delete serialport;
    // 关闭定时器
    timer_Serialport->stop();
    emit signal_serialStatus(false);
    return ;
}

void configRWserialport::slot_serialporInit()
{
    qDebug() << "启动线程";
    serialport = new QSerialPort();
    // 创建定时 - Ps: 如果线程中需要定时一定要在线程中Start
    timer_Serialport = new QTimer();
    connect(timer_Serialport, &QTimer::timeout, this, &configRWserialport::writeData);
}

void configRWserialport::slots_readData()
{
    QByteArray buf = serialport->readAll();
    if (!buf.isEmpty())
    {        
        char* rawBuf=buf.data();
        qDebug() << rawBuf;
        // qDebug()<<"read current value "<< *(uint16_t*)(rawBuf + 3);
    }
    return ;
}

void configRWserialport::writeData()
{
    QByteArray msg = "lalala";
    int ret = serialport->write(msg);
    qDebug() << "ret : " << ret;
}

uiserialport.h 这个就是在主界面点击按钮弹出那个设置波特率、串口名…的UI

#ifndef UISERIALPORT_H
#define UISERIALPORT_H

#include <QWidget>
#include "head.h"
#include "global.h"

class configRWserialport;

namespace Ui {
class uiSerialPort;
}

class uiSerialPort : public QWidget
{
    Q_OBJECT

public:
    explicit uiSerialPort(QWidget *parent = nullptr);
    ~uiSerialPort();

public slots :
    void slots_openOrNot(bool check);

private slots:
    void on_btn_openConsole_clicked();

signals :
    void signal_setConfigSerialPort();
    void signal_closeOpen();
private:
    Ui::uiSerialPort *ui;     
    void SerialPortConfigInit();
};

#endif // UISERIALPORT_H
#include "uiserialport.h"
#include "ui_uiserialport.h"

uiSerialPort::uiSerialPort(QWidget *parent) :
    QWidget(parent),

    ui(new Ui::uiSerialPort)
{
    ui->setupUi(this);
     SerialPortConfigInit();
}

uiSerialPort::~uiSerialPort()
{
    delete ui;
}

static const char blankString[] = QT_TRANSLATE_NOOP("SettingsDialog", "N/A");
void uiSerialPort::SerialPortConfigInit()
{
    //获取可以用的串口
    QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();

    QString description;
    QString manufacturer;
    QString serialNumber;

    //输出当前系统可以使用的串口个数
     qDebug() << "Total numbers of ports: " << serialPortInfos.count();

     //将所有可以使用的串口设备添加到ComboBox中
     for (const QSerialPortInfo &serialPortInfo : serialPortInfos) {
         QStringList list;
         description = serialPortInfo.description();
         manufacturer = serialPortInfo.manufacturer();
         serialNumber = serialPortInfo.serialNumber();

         list << serialPortInfo.portName()
              << (!description.isEmpty() ? description : blankString)
              << (!manufacturer.isEmpty() ? manufacturer : blankString)
              << (!serialNumber.isEmpty() ? serialNumber : blankString)
              << serialPortInfo.systemLocation()
              << (serialPortInfo.vendorIdentifier() ? QString::number(serialPortInfo.vendorIdentifier(), 16) : blankString)
              << (serialPortInfo.productIdentifier() ? QString::number(serialPortInfo.productIdentifier(), 16) : blankString);

         ui->comboBox_serialPort->addItem(list.first(), list);
     }

     ui->comboBox_serialPort->addItem(tr("custom"));

     //设置波特率
    // ui->comboBox_baudRate->addItem(QStringLiteral("4800"), QSerialPort::Baud4800);
    ui->comboBox_baudRate->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
    ui->comboBox_baudRate->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
    ui->comboBox_baudRate->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
    ui->comboBox_baudRate->addItem(QStringLiteral("57600"), QSerialPort::Baud57600);
    ui->comboBox_baudRate->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);
    ui->comboBox_baudRate->addItem(tr("Custom"));

    //设置数据位
    ui->comboBox_dataBits->addItem(QStringLiteral("5"), QSerialPort::Data5);
    ui->comboBox_dataBits->addItem(QStringLiteral("6"), QSerialPort::Data6);
    ui->comboBox_dataBits->addItem(QStringLiteral("7"), QSerialPort::Data7);
    ui->comboBox_dataBits->addItem(QStringLiteral("8"), QSerialPort::Data8);
    ui->comboBox_dataBits->setCurrentIndex(3);

    //设置奇偶校验位
    ui->comboBox_parity->addItem(tr("None"), QSerialPort::NoParity);
    ui->comboBox_parity->addItem(tr("Even"), QSerialPort::EvenParity); // 偶
    ui->comboBox_parity->addItem(tr("Odd"), QSerialPort::OddParity); // 奇
    ui->comboBox_parity->addItem(tr("Mark"), QSerialPort::MarkParity);
    ui->comboBox_parity->addItem(tr("Space"), QSerialPort::SpaceParity);

    //设置停止位
    ui->comboBox_stopBit->addItem(QStringLiteral("1"), QSerialPort::OneStop);
    ui->comboBox_stopBit->addItem(QStringLiteral("2"), QSerialPort::TwoStop);
}

extern struct configSerialport confSet;
void uiSerialPort::on_btn_openConsole_clicked()
{
    if (ui->btn_openConsole->text() == tr("打开串口")) {
        confSet.PortName = ui->comboBox_serialPort->currentText();
        confSet.BaudRate = ui->comboBox_baudRate->currentText().toInt();
        // 信号通知_线程打开串口 - 线程还会回一个信号,处理槽函数signal_openOrNot()
        emit signal_setConfigSerialPort();
        qDebug() << "打开串口";
    } else {
        // 通知线程关闭串口 - 线程还会回一个信号,处理槽函数signal_openOrNot()
        emit signal_closeOpen();
    }
    return ;
}

void uiSerialPort::slots_openOrNot(bool check) {
    if(check) {
        ui->btn_openConsole->setText(tr("关闭串口"));
        ui->comboBox_baudRate->setEnabled(false);
        ui->comboBox_dataBits->setEnabled(false);
        ui->comboBox_parity->setEnabled(false);
        ui->comboBox_serialPort->setEnabled(false);
        ui->comboBox_stopBit->setEnabled(false);
    } else {
        //恢复设置功能
        ui->comboBox_baudRate->setEnabled(true);
        ui->comboBox_dataBits->setEnabled(true);
        ui->comboBox_parity->setEnabled(true);
        ui->comboBox_serialPort->setEnabled(true);
        ui->comboBox_stopBit->setEnabled(true);
        ui->btn_openConsole->setText(tr("打开串口"));
    }
    return ;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐