Qt/C++ 个人开源项目#串口助手(源码与发布链接)

一、项目概述

该串口助手工具基于Qt/C++开发,专为简化串口通信调试与开发而设计,适合新手快速上手。工具具有直观的用户界面和丰富的功能,旨在帮助用户与串口设备建立可靠通信,便于调试、数据传输和分析。

二、主要功能

波特率:支持常见波特率(如9600、115200等),并支持自定义。

数据位:提供从5到8位的选择。

校验位:支持无校验、奇校验、偶校验等。

停止位:提供1位或2位选择。

接收数据:支持实时显示从串口设备接收的数据,用户可以选择显示格式(如十六进制、ASCII等)。

发送数据:用户可以通过界面输入并发送数据,支持单次发送和定时发送,便于测试连续传输。

  1. 串口自动检测与连接串口助手具备自动检测功能,可以自动识别当前系统中的串口设备。用户通过界面选择设备并一键连接,简化了配置流程。

  2. 串口参数配置用户可以根据实际需求设置以下参数:

  3. 数据收发

三、软件安装与使用

1. 使用

该串口助手提供了编译好的发布包,用户可以自行下载可以直接启动应用。在应用界面中,选择要连接的串口设备,配置相关串口参数,点击“连接”即可开始数据通信。数据收发、等功能可以根据需求自由选择和配置。

四、下载链接

发布包下载链接:串口调试助手.zip

https://pan.baidu.com/s/12RQ_fxREV7zOH-MwqIUzlQ?pwd=cedu

五、源码分享

#ifndef SERIALWORKER_H
#define SERIALWORKER_H#include <QThread>
#include <QSerialPort>
#include <QQueue>
#include <QMutex>
#include <QWaitCondition>
#include <QString>#define tc(a) QString::fromLocal8Bit(a)class SerialWorker : public QThread
{Q_OBJECTpublic:SerialWorker();~SerialWorker();void setupPort(const QString &portName, qint32 baudRate, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QSerialPort::Parity parity);void addDataToSend(const QByteArray &data);inline void unpackData(const QByteArray& receivedData);public slots:void startWorker(); // 用于替代start(),因为start()是QThread的成员函数void stop();signals:void dataReceived(const QByteArray &data);void errorOccurred(const QString &error);// 新增信号void informations(int index, const QString &msg); // 用于发送一般信息void warnings(int index, const QString &msg);     // 用于发送警告信息void errors(int index, const QString &msg);       // 用于发送错误信息void connected(int index, bool success);          // 用于发送连接状态protected:void run() override;private:QSerialPort *serialPort;QQueue<QByteArray> sendQueue;QMutex mutex;QWaitCondition waitCondition;bool running;// 串口参数QString portName;qint32 baudRate;QSerialPort::DataBits dataBits;QSerialPort::StopBits stopBits;QSerialPort::Parity parity;
};#endif // SERIALWORKER_H
#include "serialworker.h"
#include <QDebug>
#include <QEventLoop>
#include <QTimer>
SerialWorker::SerialWorker(): serialPort(nullptr), running(false)
{
}SerialWorker::~SerialWorker()
{stop();if (serialPort && serialPort->isOpen()) {serialPort->close();}delete serialPort;
}void SerialWorker::setupPort(const QString &portName, qint32 baudRate, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QSerialPort::Parity parity)
{this->portName = portName;this->baudRate = baudRate;this->dataBits = dataBits;this->stopBits = stopBits;this->parity = parity;
}void SerialWorker::addDataToSend(const QByteArray &data)
{QMutexLocker locker(&mutex);sendQueue.enqueue(data);waitCondition.wakeOne();
}void SerialWorker::unpackData(const QByteArray &receivedData)
{emit dataReceived(receivedData);
}void SerialWorker::startWorker()
{if(!isRunning())start();}void SerialWorker::stop()
{QMutexLocker locker(&mutex);running = false;waitCondition.wakeAll();
}void SerialWorker::run()
{serialPort = new QSerialPort();// 设置串口参数serialPort->setPortName(portName);serialPort->setBaudRate(baudRate);serialPort->setDataBits(dataBits);serialPort->setStopBits(stopBits);serialPort->setParity(parity);int index = 0;  // 可以根据需要设置适当的索引值if (!serialPort->open(QIODevice::ReadWrite)) {emit errors(index, serialPort->errorString());emit connected(index, false);delete serialPort;serialPort = nullptr;running=false;return;}running=true;emit connected(index, true);  // 成功连接emit informations(index, tc("串口已打开"));QEventLoop eventLoop;QTimer timer;timer.setInterval(10); // 设置定时器的间隔,控制事件循环的频率connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);timer.start();while (running){QByteArray data;{QMutexLocker locker(&mutex);if (!sendQueue.isEmpty()) {data = sendQueue.dequeue();}}if (!data.isEmpty()){serialPort->write(data);if (!serialPort->waitForBytesWritten()) {emit errors(index, serialPort->errorString());} else {emit informations(index, tc("数据已发送[%1]").arg(QString::fromUtf8(data)));}}if (serialPort->waitForReadyRead(10)) { // 使用一个小的超时时间QByteArray receivedData = serialPort->readAll();emit dataReceived(receivedData);}// 处理事件循环,避免阻塞信号槽机制eventLoop.exec();}serialPort->close();emit informations(index, tc("串口已关闭"));emit connected(index, false);  // 断开连接delete serialPort;serialPort = nullptr;
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "serialworker.h"
namespace Ui {
class MainWindow;
}
enum RunTimeStatus
{Error,            ///< 错误信息Warning,          ///< 警告信息Information,     ///< 常规信息
};
class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();void writeRunTimeMsgs(const QString&msg,const int level);void createSendLinEdit();// 创建配置文件的函数,如果文件不存在则创建void createConfigFile(const QString &fileName, const QStringList &values);// 读取配置文件的函数QStringList readConfigFile(const QString &fileName);private slots:void on_openButton_clicked();void on_closeButton_clicked();void onDataReceived(const QByteArray &data);void onRespondNormalMessage(const int index,const QString&msg);void onRespondWarningMessage(const int index,const QString&msg);void onRespondErrorMessage(const int index,const QString&msg);void onRespondSerialConnectState(const int index,const bool state);void on_clearRecvButton_clicked();private:Ui::MainWindow *ui;SerialWorker *serialwork;
};#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSerialPortInfo>
#include <QDateTime>
#include <QDebug>
#include <QSettings>
#include <QFile>
#include <QTextCodec>
#include "timesendwidget.h"
# define tc(a) QString::fromLocal8Bit(a)
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow), serialwork(new SerialWorker())
{ui->setupUi(this);// 示例值列表QStringList values;values << tc("极客晨风") << tc("1327666247@qq.com")  << tc("微信公众号:码上Qt")<<tc("欢迎关注") ;createConfigFile("config.ini",values);//绘制发送界面createSendLinEdit();// 填充串口选项// 遍历当前系统可用的所有串口,并将它们的名字添加到端口名的QComboBox中foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {ui->portNameComboBox->addItem(info.portName());}// 填充波特率选项// 将常用的波特率值添加到波特率的QComboBox中,数据以“字符串-枚举值”形式存储ui->baudRateComboBox->addItem("9600", QSerialPort::Baud9600);        // 波特率9600ui->baudRateComboBox->addItem("19200", QSerialPort::Baud19200);      // 波特率19200ui->baudRateComboBox->addItem("38400", QSerialPort::Baud38400);      // 波特率38400ui->baudRateComboBox->addItem("115200", QSerialPort::Baud115200);    // 波特率115200ui->baudRateComboBox->setCurrentIndex(0);  // 设置默认选项为第一个(9600)// 填充数据位选项// 将串口通信中常用的数据位数添加到数据位的QComboBox中,数据以“字符串-枚举值”形式存储ui->dataBitsComboBox->addItem("5", QSerialPort::Data5);   // 5个数据位ui->dataBitsComboBox->addItem("6", QSerialPort::Data6);   // 6个数据位ui->dataBitsComboBox->addItem("7", QSerialPort::Data7);   // 7个数据位ui->dataBitsComboBox->addItem("8", QSerialPort::Data8);   // 8个数据位(通常最常用)ui->dataBitsComboBox->setCurrentIndex(3);  // 设置默认选项为8个数据位(索引3)// 填充停止位选项// 将串口通信中常用的停止位添加到停止位的QComboBox中,数据以“字符串-枚举值”形式存储ui->stopBitsComboBox->addItem("1", QSerialPort::OneStop);            // 1个停止位ui->stopBitsComboBox->addItem("1.5", QSerialPort::OneAndHalfStop);   // 1.5个停止位(较少使用)ui->stopBitsComboBox->addItem("2", QSerialPort::TwoStop);            // 2个停止位ui->stopBitsComboBox->setCurrentIndex(0);  // 设置默认选项为1个停止位// 填充奇偶校验选项// 将串口通信中常用的奇偶校验方式添加到奇偶校验的QComboBox中,数据以“字符串-枚举值”形式存储ui->parityComboBox->addItem("None", QSerialPort::NoParity);          // 无校验(最常用)ui->parityComboBox->addItem("Even", QSerialPort::EvenParity);        // 偶校验ui->parityComboBox->addItem("Odd", QSerialPort::OddParity);          // 奇校验ui->parityComboBox->addItem("Mark", QSerialPort::MarkParity);        // 标志位校验(较少使用)ui->parityComboBox->addItem("Space", QSerialPort::SpaceParity);      // 空格位校验(较少使用)ui->parityComboBox->setCurrentIndex(0);  // 设置默认选项为无校验connect(serialwork, &SerialWorker::dataReceived, this, &MainWindow::onDataReceived);// 连接信号与槽connect(serialwork, &SerialWorker::informations, this, &MainWindow::onRespondNormalMessage);connect(serialwork, &SerialWorker::warnings, this, &MainWindow::onRespondWarningMessage);connect(serialwork, &SerialWorker::errors, this, &MainWindow::onRespondErrorMessage);connect(serialwork, &SerialWorker::connected, this, &MainWindow::onRespondSerialConnectState);}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::writeRunTimeMsgs(const QString &msg, const int level )
{QString Level;switch (level) {case Error:      Level=tc("[ ***错误信息*** ]");break;case Warning:    Level=tc("[ ***警报信息*** ]");break;case Information:Level=tc("[ ***正常信息*** ]");break;}ui->statusBar->showMessage(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ") +Level+msg );
}void MainWindow::createSendLinEdit()
{for(auto val:readConfigFile("config.ini")){TimeSendWidget *sendWidget=new TimeSendWidget;sendWidget->setLinText(val);connect(sendWidget,&TimeSendWidget::sendLineData,[=](const QByteArray &data ){if(ui->openButton->isEnabled()){writeRunTimeMsgs(tc("串口未打开,无法发送"),Error);return ;}if(data.isEmpty()){writeRunTimeMsgs(tc("信息为空,拒绝发送"),Warning);return ;}//主界面显示if(ui->isShowSendButton->isChecked()){QString msg;if(ui->isShowTimeButton->isChecked())msg.append(QDateTime::currentDateTime().toString("hh:mm:ss.(zzz)  "));msg.append(tc("发送  "));msg.append(ui->isShowHexButton->isChecked()? data.toHex(' ').toUpper():QString::fromLocal8Bit(data));ui->receiveTextEdit->append(msg);}//更新显示信息ui->sendByte->setValue(ui->sendByte->value()+data.size());ui->sendFram->setValue(ui->sendFram->value()+1);serialwork->addDataToSend(data);});ui->sendGroup->layout()->addWidget(sendWidget);}}void MainWindow::createConfigFile(const QString &fileName, const QStringList &values)
{// 检查文件是否存在QFile file(fileName);if (file.exists())return;QSettings settings(fileName, QSettings::IniFormat);settings.setIniCodec(QTextCodec::codecForName("UTF-8"));// 根据传入的值动态创建组和键值对int groupIndex = 1;for (const QString &value : values){QString groupName = QString("%1").arg(groupIndex);settings.beginGroup(groupName);settings.setValue(QString("%1").arg(groupIndex), value);settings.endGroup();groupIndex++;}}QStringList MainWindow::readConfigFile(const QString &fileName)
{QStringList iniinfors;QSettings settings(fileName, QSettings::IniFormat);settings.setIniCodec(QTextCodec::codecForName("UTF-8"));// 获取所有组并排序QStringList groups = settings.childGroups();groups.sort();for (const QString &group : groups){settings.beginGroup(group);QStringList keys = settings.childKeys();for (const QString &key : keys)iniinfors<< settings.value(key).toString();settings.endGroup();}return  iniinfors;
}
void MainWindow::on_openButton_clicked()
{QString portName = ui->portNameComboBox->currentText();qint32 baudRate = ui->baudRateComboBox->currentData().toInt();QSerialPort::DataBits dataBits = static_cast<QSerialPort::DataBits>(ui->dataBitsComboBox->currentData().toInt());QSerialPort::StopBits stopBits = static_cast<QSerialPort::StopBits>(ui->stopBitsComboBox->currentData().toInt());QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(ui->parityComboBox->currentData().toInt());serialwork->setupPort(portName, baudRate, dataBits, stopBits, parity);serialwork->startWorker();
}void MainWindow::on_closeButton_clicked()
{serialwork->stop();}void MainWindow::onDataReceived(const QByteArray &data)
{if(ui->isShowRecvButton->isChecked()){QString msg;if(ui->isShowTimeButton->isChecked())msg.append(QDateTime::currentDateTime().toString("hh:mm:ss.(zzz)  "));msg.append(tc("接收  "));msg.append(ui->isShowHexButton->isChecked()? data.toHex(' ').toUpper():QString::fromLocal8Bit(data));ui->receiveTextEdit->append(msg);}//更新显示信息ui->recvByte->setValue(ui->recvByte->value()+data.size());ui->recvFram->setValue(ui->recvFram->value()+1);}void MainWindow::onRespondNormalMessage(const int , const QString &msg)
{writeRunTimeMsgs(msg,Information);
}void MainWindow::onRespondWarningMessage(const int , const QString &msg)
{writeRunTimeMsgs(msg,Warning);
}void MainWindow::onRespondErrorMessage(const int , const QString &msg)
{writeRunTimeMsgs(msg,Error);
}void MainWindow::onRespondSerialConnectState(const int , const bool state)
{ui->openButton->setEnabled(!state);ui->closeButton->setEnabled(state);}void MainWindow::on_clearRecvButton_clicked()
{ui->recvByte->setValue(0);ui->recvFram->setValue(0);ui->sendByte->setValue(0);ui->sendFram->setValue(0);ui->receiveTextEdit->clear();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【信创建设】信息系统信创建设整体技方案(word原件完整版)

信创&#xff0c;即“信息技术应用创新”。我国自主信息产业聚焦信息技术应用创新&#xff0c;旨在通过对IT硬件、软件等各个环节的重构&#xff0c;基于我国自有IT底层架构和标准&#xff0c;形成自有开放生态&#xff0c;从根本上解决本质安全问题&#xff0c;实现信息技术可…

多款式随身WiFi如何挑选,USB随身WiFi、无线电池随身WiFi、充电宝随身WiFi哪个好?优缺点分析!

市面上的随身WiFi款式多样琳琅满目&#xff0c;最具代表性的就是USB插电款、无线款和充电宝款。今天就来用一篇文章分析一下这三种款式的优缺点。 USB插电款 优点&#xff1a;便宜&#xff0c;无需充电&#xff0c;在有电源的地方可以随时随地插电使用&#xff0c;比如中兴的U…

Spring Boot 部署方案!打包 + Shell 脚本详解

本篇和大家分享的是springboot打包并结合shell脚本命令部署&#xff0c;重点在分享一个shell程序启动工具&#xff0c;希望能便利工作&#xff1b; profiles指定不同环境的配置 maven-assembly-plugin打发布压缩包 分享shenniu_publish.sh程序启动工具 linux上使用shenniu_p…

python进阶篇-day07-高级语法与正则

day07-python其他高级语法 一. with(上下文管理) 介绍 概述 一个类只要实现了__ enter __ () 和 __ exit __ ()方法, 这个类就是一个上下文管理器类, 该类的对象 上下文管理器对象 目的 节约资源, 提高效率, 避免手动释放资源, 且出bug的时候, 也会自动尝试释放资源 特点…

【Centos】绕开报错ModuleNotFoundError: No module named ‘dnf‘

问题原因&#xff1a; 安装python3.9后不能使用yum Traceback (most recent call last):File "/usr/bin/yum", line 57, in <module>from dnf.cli import main ModuleNotFoundError: No module named dnf绕开yum解决方法&#xff1a; 直接下载相关依赖包 htt…

怎样将手机屏幕(远程)投屏到家里的大电视上?

我不住家里&#xff0c;前几次回去都会替老爸老妈清理手机。这两个星期没空回去&#xff0c;老爸吐槽手机用几天就又卡了&#xff0c;其实就是清理一些手机缓存的问题。 我说我远程控制他的手机&#xff0c;给他清理一下。他一听“控制”就不喜欢&#xff0c;说我大了&#xf…

【Python知识宝库】文件操作:读写文件的最佳实践

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言一、文件读取1. 使用open函数2. 逐行读取3. 使用readlines和readline 二、文件写入1. 写入文本2. 追加内容3. 写入…

使用shell脚本安装mysql8,进行主从备份配置

思路 在3台主机上安装mysql进行主从备份配置 使用rpm包yum安装mysql 首先&#xff0c;我们要准备好安装文件&#xff0c;首先下载rpm包 wget -P "/opt/" https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm 然后执行安装&#xff08;默认已配置…

HMI设计:嵌入式设备和电脑的差异化,工控领域首选。

嵌入式设备属于专机专用&#xff0c;电脑是通用&#xff0c;从性能、用途、特殊能力、成本、通信上嵌入式设备完全优于电脑&#xff0c;是工控领域的首选。 嵌入式设备和电脑在很多方面有着显著的差异&#xff0c;主要体现在以下几个方面&#xff1a; 1. 设计用途&#xff1a…

在js渲染的dom中的事件中传递对象

在某些情况下&#xff0c;可能需要将整个对象或部分对象嵌入到 HTML 元素的属性中&#xff0c;可以将对象数据序列化为 JSON 字符串&#xff0c;存储在 data-* 自定义属性中。这样可以在事件中取出并解析对象数据&#xff1a; <!DOCTYPE html> <html lang"en&qu…

C++万字解读类和对象(上)

1.类的定义 class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。 为了区分成员变量&…

[QT] QT事件与事件重写

一.事件 事件(event)是由系统或者 Qt本身在不同的场景下发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口关闭等都会发出一个相应的事件。 一些事件在用户操作时发出(如鼠标/键盘事件); 另一些事件则是由系统自动发出(如计时器事件)。 Qt窗口中对于产生的一系列事件都…

MarkdownEditor 配置以及使用

MarkdownEditor 配置以及使用 MarkdownEditor是一款基于浏览器的 Markdown 编辑器&#xff0c;虽然他是独立软件&#xff0c;但该软件内嵌一个浏览器。功能非常简单实用、反应速度很快&#xff0c;号称是Markdown领域的NotePad&#xff08;记事本&#xff09;。 MarkdownEdit…

面向对象23种设计模式通俗理解

终点即是起点,自强不息! 设计模式的理解 设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 模式&#xff1a;在某些场景下&#xff0c;针对某类问题的某种通用的解决方案。 场景&#xff1a;项目所在的环境 问题&#xff1a;约束条件&#xff0c;项目目标…

vue3 项目中使用git

一.vue项目创建 二.创建本地仓库并和远程仓库进行绑定 在vue3-project-git 项目文件夹下 初始化一个新的Git仓库&#xff0c;可以看到初始化成功之后就会出现一个.git文件&#xff0c;该文件包含所有必要的 Git 配置和版本控制信息。 创建远程仓库: 打开gitee ,点击右上角 ‘…

MapSet之二叉搜索树

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 前言 1.二叉搜索树 1.1 定义 1.2 操作-查找 1.3 操作-新增 1.4 操作-删除(难点) 1.5 总体实现代码 1.6 性能分析 前言 TreeMap 和 TreeSet 是 Java 中基于搜索树实现的 M…

DELTA_IA-ASD_ASDA-A2简明教程

该文章仅供参考&#xff0c;编写人不对任何实验设备、人员及测量结果负责&#xff01;&#xff01;&#xff01; 0 引言 文章主要介绍电机的硬件连接、软件配置、转动调试以及软件控制。文章中提到的内容在产品手册中都有说明&#xff0c;强烈建议在操作前通读产品手册&#…

RocketMQ高级特性三-消费者分类

目录 前言 概述 区别 PullConsumer 定义与概述 原理机制 使用场景 优缺点 Java 代码示例 SimpleConsumer 定义与概述 原理机制 使用场景 优缺点 Java 代码示例 PushConsumer 定义与概述 原理机制 使用场景 优缺点 Java 代码示例 总结 前言 RocketMQ中的消…

常用排序算法(上)

目录 前言&#xff1a; 1.排序的概念及其运用 1.1排序的概念 1.2排序运用 1.3 常见的排序算法 2.常见排序算法的实现 2.1 堆排序 2.1 1 向下调整算法 2.1 2 建堆 2.1 3 排序 2.2 插入排序 2.1.1基本思想&#xff1a; 2.1.2直接插入排序&#xff1a; 2.1.3 插…

SQL进阶技巧:每年在校人数统计 | 区间重叠问题

目录 0 问题分析 1 数据准备 2 问题分析 3 小结 区间重叠问题 0 问题分析 有一个录取学生人数表 in_school_stu,记录的是每年录取学生的人数及录取学生的学制,计算每年在校学生人数。 1 数据准备 create table in_school_stu as ( select stack(5,1,2001,2,1200,2,2000…