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

news/2024/12/22 15:10:56/

一、项目概述

该串口助手工具基于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.ppmy.cn/news/1522175.html

相关文章

Flutter集成Firebase中的 A/B Testing

前提 完成Flutter集成Firebase中的远程配置流程 A/B Test的使用流程 我们先通过远程配置设置变量&#xff0c;应用程序根据变量值展示不同的界面创建一个A/B Test实验&#xff0c;在实验中创建满足条件的用户才能加入到这个实验中&#xff0c;并且在A/B 实验中修改远程配置变…

shell 学习笔记:变量、字符串、注释

目录 1. 变量 1.1 定义使用变量 1.2 变量命名规则 1.3 只读变量 1.4 删除变量 1.5 变量类型 1.5.1 字符串变量 1.5.2 整数变量 1.5.3 数组变量 1.5.3.1 整数索引数组 1.5.3.2 关联数组 1.4 环境变量 1.5 特殊变量 2. 字符串 2.1 单引号字符串 2.2 双引…

使用NetBackup GUI 图形化进行oracle备份和恢复

转载 一、环境介绍&#xff1a; 这个实验都是在vmware workstation里完成的。由于NetBackup7只能装在64位的系统上&#xff0c;所以这里采用了64位的rhel5.5系统&#xff0c;以及oracle 10gr2 for linux_x64的软件包。数据库的数据文件存储在ASM中。安装rhel、oracle、netback…

C++字符串中的string类操作

愿我如星君如月&#xff0c;夜夜流光相皎洁。 ——《车逍遥篇》【宋】范成大 目录 正文&#xff1a; 主要特点&#xff1a; 基本操作&#xff1a; 代码演示&#xff1a; 总结&#xff1a; 今天我们接着上次的章节继续&#xff0c;这次我们来说一个为解决上个方法的缺陷而诞…

Linux 文件权限与属性管理

概述 Linux 系统是一种典型的多用户系统&#xff0c;不同的用户处于不同的地位&#xff0c;拥有不同的权限。为了保护系统的安全性&#xff0c;Linux 对不同用户访问同一文件&#xff08;包括目录文件&#xff09;的权限做了详细的规定。 文件属性查看 在 Linux 中&#xff0…

目标检测-YOLOv3

YOLOv3介绍 YOLOv3 (You Only Look Once, Version 3) 是 YOLO 系列目标检测模型的第三个版本&#xff0c;相较于 YOLOv2 有了显著的改进和增强&#xff0c;尤其在检测速度和精度上表现优异。YOLOv3 的设计目标是在保持高速的前提下提升检测的准确性和稳定性。下面是对 YOLOv3 …

牛客(除2!)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 给一个数组&#xff0c;一共有 n n\ n 个数。 你能进行最多 k k\ k 次操作。每次操作可以进行以下步骤&#xff1a; 选择数组中的一个偶数 aia_iai​&#xff0c;将其变成 ai/2a_i/…

使用 JAXB 将内嵌的JAVA对象转换为 xml文件

使用 JAXB 将内嵌的JAVA对象转换为 xml文件 1. 需求2. 实现&#xff08;1&#xff09;FileDesc类&#xff08;2&#xff09;MetaFileXml类&#xff08;3&#xff09;生成对应的xml文件 1. 需求 获取一个目录下所有文件的元数据信息&#xff08;文件名、大小、后缀等&#xff0…