Qt串口QSerialPortd的多线程(moveTo + 信号 + 槽)和非线程版
Qt串口QSerialPortd 使用多线程(moveTo + 信号 + 槽)和咋主线程中可以直接创建,可以定时发送等
必备条件
在**.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

弹窗串口设置UI

程序演示

主线程中使用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中大部分是都不支持跨线程的)

因此不能在主线程(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 ;
}
更多推荐


所有评论(0)