QT上位机:串口调试助手
前言
上位机的简单编写可以帮我们测试并完善平台,QT作为一款跨平台的GUI开发框架,提供了非常丰富的常用串口api。本文先从最简单的串口调试助手开始,编写平台软件的串口控制界面
工程配置
QT 串口通信基于QT的QSerialPort类,先在项目文件pro中添加QT += serialport。
避免默认的widget类和ui命名,将串口部分的ui命名为ui_serial,类命名为serial
界面设置
在UI界面可以直接搭建我们想要的界面显示方案,并自动生成相应代码添加头文件,用起来还是非常方便的,注意不要和代码里手动添加的混淆就好了
需要配置的可以选择QComboBox,添加常用的配置项,比如串口号,波特率,数据校验停止位等
添加led指示灯QLabel,可以用来美化界面
点击选中的可以选择QRadioButton,用以单选,直观的给以感受
收发的界面选择文本框QPlainTextEdit,可以多行显示
手动加的短文本框可以用QLineEdit,可以单行显示
其余的用最基础的pushbutton就可以了
为了界面不会被放大缩小导致排版混乱,可以添加弹簧或者直接写死窗口大小
设计完成后,会保存为对应名称比如serial.ui
构造函数里需要将有交互的部分connect起来,将界面按键的初始值做设置
我们可以通过继承QSerialPort类,也可以直接继承Qwidget类,在里面申明Qserialport
class serial : public QWidget
{Q_OBJECTpublic:explicit serial(QWidget *parent = 0);QSerialPort *serialPort;~serial();
private slots:void serialPortReadyRead_Slot();void on_OpenBt_clicked();void on_SendBt_clicked();void on_SaveBt_clicked();void on_ClearBt_clicked();void on_pushButton_clicked();private:QPushButton *m_button;void LED(bool changeColor); //串口连接指示灯void closeEvent(QCloseEvent *event); /***关闭***/void on_comStatus(QString name, bool flag);Ui::serial *ui_serial;};
serial::serial(QWidget *parent) :QWidget(parent),ui_serial(new Ui::serial)
{ui_serial->setupUi(this);setWindowTitle("串口控制界面-HX");this->setFixedSize(980, 600); // 固定窗口的大小/***************定义接收格式数据按钮********************/QButtonGroup *btnGroupRev=new QButtonGroup(this);btnGroupRev->addButton(ui_serial->ASCII_Receive_Box,0); // 将给定的按钮添加到按钮组btnGroupRev->addButton(ui_serial->HEX_Receive_Box,1);ui_serial->ASCII_Receive_Box->setChecked(true); // 设置默认模式/***************定义发送格式数据按钮********************/QButtonGroup *btnGroupSend=new QButtonGroup(this);btnGroupSend->addButton(ui_serial->ASCII_Send_Box,0); // 将给定的按钮添加到按钮组btnGroupSend->addButton(ui_serial->HEX_Send_Box,1);ui_serial->ASCII_Send_Box->setChecked(true); // 设置默认模式serialPort = new QSerialPort(this);connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot()));/***************串口热插拔********************/ComChange::getInstance()->setHWND((HWND)this->winId());connect(ComChange::getInstance(), &ComChange::comStatus, this, &serial::on_comStatus);QStringList strName = ComChange::getAvailablePort(); // 获取所有可用串口ui_serial->SerialCb->addItems(strName);/*连接rtsp界面*/
// m_button = findChild<QPushButton*>("pushButton_3"); // 查找已有的pushButton3对象
// qDebug()<<"m_button is :"<<m_button;
// connect(this, &serial::buttonClicked_ctrl_left, this, &serial::on_pushButton_3_clicked);
// 连接信号与槽//}
考虑到热插拔的问题封装getAvailablePort获取当前可用串口
ComChange* ComChange::m_comChange = nullptr;
ComChange *ComChange::getInstance()
{if(m_comChange == nullptr){static QMutex mutex; //实例互斥锁。QMutexLocker locker(&mutex); //加互斥锁。if(m_comChange == nullptr){m_comChange = new ComChange();}}return m_comChange;}/*** @brief 获取系统中所有可用的串口名* @return*/
QStringList ComChange::getAvailablePort()
{QStringList strName;foreach(const QSerialPortInfo& info, QSerialPortInfo::availablePorts()){QSerialPort port(info);if(port.open(QIODevice::ReadWrite)){strName << info.portName();port.close();}}return strName;
}
串口的热插拔
/*函 数:on_comStatus描 述:串口热插拔操作。有comchange的h文件、cpp文件和该函数,才能支持串口热插拔操作,缺一不可。移植请注意。输 入:串口名称:name, 连接标志:flag输 出:无
*/
void serial::on_comStatus(QString name, bool flag)
{if(flag) ui_serial->SerialCb->addItem(name); // 串口插入时自动添加串口名else{ui_serial->SerialCb->removeItem(ui_serial->SerialCb->findText(name)); // 串口拔出时自动移除串口名LED(false); //红色LED 表示关闭串口serialPort->close(); //关闭串口ui_serial->OpenBt->setText("打开串口");}}
串口的初始化
在点击打开串口的时候做初始化,使用open(QIODevice::ReadWrite)
用ReadWrite 的模式尝试打开串口,打开成功后设置串口通信的波特率,校验方式等配置。(打开方式有多种,只读(r/o)、只写(w/o)或读写(r/w)模式)
直接使用serialPort的相关API
setPortName
将当前串口的名字设置为系统可用串口的名字
setBaudRate
设置波特率
setDataBits
设置数据位
setStopBits
设置停止位
setParity
设置校验位
close
关闭串口
注意:串口始终以独占访问方式打开(即没有其他进程或线程可以访问已打开的串口)。
/*函 数:on_OpenBt_clicked描 述:打开串口时初始化串口输 入:无输 出:无
*/
void serial::on_OpenBt_clicked()
{if(ui_serial->OpenBt->text()=="打开串口"){serialPort->setPortName(ui_serial->SerialCb->currentText()); // 将当前串口的名字设置为系统可用串口的名字qint32 baudrate = ui_serial->BaundCb->currentText().toInt(); // 获取期望的波特率serialPort->setBaudRate(baudrate); // 设置波特率//设置数据位switch(ui_serial->DataCb->currentText().toInt()){case 8:serialPort->setDataBits(QSerialPort::Data8); break;case 7:serialPort->setDataBits(QSerialPort::Data7); break;case 6:serialPort->setDataBits(QSerialPort::Data6); break;case 5:serialPort->setDataBits(QSerialPort::Data5); break;}//设置停止位if(ui_serial->StopCb->currentText() == "1"){serialPort->setStopBits(QSerialPort::OneStop);}else if(ui_serial->StopCb->currentText() == "1.5"){serialPort->setStopBits(QSerialPort::OneAndHalfStop);}else if(ui_serial->StopCb->currentText() == "2"){serialPort->setStopBits(QSerialPort::TwoStop);}//设置校验位if(ui_serial->CheckCb->currentText() == "None"){serialPort->setParity(QSerialPort::NoParity);}else if(ui_serial->CheckCb->currentText() == "Even"){serialPort->setParity(QSerialPort::EvenParity);}else if(ui_serial->CheckCb->currentText() == "Odd"){serialPort->setParity(QSerialPort::OddParity);}LED(true); //绿色LED 表示打开串口//串口连接失败提示if(serialPort->open(QIODevice::ReadWrite) == false){QMessageBox::critical(this, "提示", "串口连接失败");LED(false); //红色LED 表示关闭串口}ui_serial->OpenBt->setText("关闭串口");}else{LED(false); //红色LED 表示关闭串口serialPort->close(); //关闭串口ui_serial->OpenBt->setText("打开串口");}
}
串口的收发
根据hex和ASCII在收发时做判断serialPort->readAll();
可以接收所有信息,serialPort->write(SendTextByte)
; /可以通过串口将数据发送出去
/*函 数:serialPortReadyRead_Slot描 述:上位机接收数据输 入:无输 出:无
*/
void serial::serialPortReadyRead_Slot()
{QByteArray buf = serialPort->readAll(); //从串口读取信息if(ui_serial->ASCII_Receive_Box->isChecked()) //如果设置接收ASCII{ui_serial->ReceiveEdit->insertPlainText(QString::fromLocal8Bit(buf)); // 对串口接收的数据进行编码}else if(ui_serial->HEX_Receive_Box->isChecked()) //如果设置接收HEX{QDataStream out(&buf, QIODevice::ReadWrite); //读取数据while(!out.atEnd()) //读取是否完成{qint8 outChar = 0;out >> outChar;QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')); //转换16进制ui_serial->ReceiveEdit->insertPlainText(str+" "); //每显示一次后面加一个空格}}
}/*函 数:on_SendBt_clicked描 述:上位机发送数据输 入:无输 出:无
*/
void serial::on_SendBt_clicked()
{QString sendstr=ui_serial->SendEdit->toPlainText(); //获取将要发送数据if(ui_serial->ASCII_Send_Box->isChecked()) // 如果发送ASCII模式{QByteArray SendTextByte = sendstr.toLocal8Bit(); //将发送的数据转换格式serialPort->write(SendTextByte); // 通过串口将数据发送出去}else if(ui_serial->HEX_Send_Box->isChecked()) // 如果发送HEX{QByteArray SendTextByte = QByteArray::fromHex(sendstr.toLatin1()); // 转换数据格式serialPort->write(SendTextByte); // 通过串口将数据发送出去}
}
接收区清除
为了直观的读取接收区数据,也需要增加清除当前数据的功能
/*函 数:on_ClearBt_clicked描 述:清空接收区的数据输 入:无输 出:无
*/
void serial::on_ClearBt_clicked()
{ui_serial->ReceiveEdit->clear();
}
接收数据的保存
数据量大的时候经常需要保存接收数据的log,所以存log的功能也是必不可少的
file.open(QFile::WriteOnly | QFile::Text)
可以将文本数据框取出并按行排列
/*函 数:on_SaveBt_clicked描 述:以TXT格式保存接收区数据输 入:无输 出:无
*/
void serial::on_SaveBt_clicked()
{QString textFile = QFileDialog::getSaveFileName(this,tr("Save txt"),"",tr("text (*.txt)")); //选择路径//将文本框数据取出并按行排列QFile file(textFile);//文件命名if (!file.open(QFile::WriteOnly | QFile::Text)) //检测文件是否打开{QMessageBox::information(this, "Error Message", "Please Select a Text File!");return;}QTextStream out(&file); //分行写入文件out << ui_serial->ReceiveEdit->toPlainText();
}
指示灯的使用
为了美化界面,直观显示串口是否正常连接,可以加个指示灯,设置绿色表示开红色表示关
/*函 数:closeEvent描 述:关闭窗口时若未关闭串口,则要关闭串口输 入:无输 出:无
*/
void serial::closeEvent(QCloseEvent *event)
{if(serialPort->isOpen()) // 串口处于打开状态{LED(false); //红色LED 表示关闭串口serialPort->close(); // 串口关闭event->accept(); // 界面关闭}
}/*函 数:LED描 述:串口指示灯输 入:bool changeColor输 出:无
*/
void serial::LED(bool changeColor)
{if(changeColor == true){// 显示绿色ui_serial->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(0, 229, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:9px;");}else{// 显示红色ui_serial->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(255, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:9px;");}
}
窗口退出
为了避免退出的时候占用串口,关闭窗口的时候需要关闭串口
/*函 数:closeEvent描 述:关闭窗口时若未关闭串口,则要关闭串口输 入:无输 出:无
*/
void serial::closeEvent(QCloseEvent *event)
{if(serialPort->isOpen()) // 串口处于打开状态{LED(false); //红色LED 表示关闭串口serialPort->close(); // 串口关闭event->accept(); // 界面关闭}
}
具体功能
剩下的就是根据协议规定点击pushbutton发送相应的内容了
相关文章:

QT上位机:串口调试助手
前言 上位机的简单编写可以帮我们测试并完善平台,QT作为一款跨平台的GUI开发框架,提供了非常丰富的常用串口api。本文先从最简单的串口调试助手开始,编写平台软件的串口控制界面 工程配置 QT 串口通信基于QT的QSerialPort类,先在…...

Netty核心原理与基础实战(二)——详解Bootstrap
接上篇:Netty核心原理与基础实战(一) 1 Bootstrap基础概念 Bootstrap类是Netty提供的一个便利的工厂类,可以通过它来完成Netty的客户端或服务端的Netty组件的组装,以及Netty程序的初始化和启动执行。Netty的官方解释是…...
C语言常见面试题:C语言中如何进行比较运算?
在C语言中,比较运算用于比较两个值的大小关系。比较运算符包括等于()、不等于(!)、大于(>)、小于(<)、大于等于(>)和小于等于࿰…...
学习总结14
# 【CSGRound1】天下第一 ## 题目背景 天下第一的 cbw 以主席的身份在 8102 年统治全宇宙后,开始了自己休闲的生活,并邀请自己的好友每天都来和他做游戏。由于 cbw 想要显出自己平易近人,所以 zhouwc 虽然是一个蒟蒻,也有能和 c…...

D盘不见了如何恢复?4个恢复方法(新版)!
“很奇怪!我的电脑d盘不知道为什么突然不见了,我还保存了很多重要的文件在里面呢,有什么恢复d盘的方法吗?” 在我们的日常生活中,电脑已经成为了我们工作、学习和娱乐的重要工具。然而,有时候我们会遇到一些…...

vector类的模拟实现
实现基本的vector框架 参考的是STL的一些源码,实现的vector也是看起来像是一个简略版的,但是看完能对vector这个类一些接口函数更好的认识。 我们写写成员变量,先来看看STL的成元变量是那些 namespace tjl {template<class T>class …...

Topaz Photo AI for Mac v2.3.1 补丁版人工智能降噪软件无损放大
想要将模糊的图片变得更加清晰?不妨试试Topaz Photo AI for Mac 这款人工智能、无损放大软件。Topaz Photo AI for Mac 一款强大的人工智能降噪软件,允许用户使用复杂的锐化算法来提高图像清晰度,还包括肖像编辑选项,如面部重塑、…...

【Unity3D小技巧】Unity3D中UI控制解决方案
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 在开发中总是会控制UI界面,如何优雅的控制UI界面是…...

【状态管理一】概览:状态使用、状态分类、状态具体使用
文章目录 一. 状态使用概览二. 状态的数据类型1. 算子层面2. 接口层面2.1. UML与所有状态类型介绍2.2. 内部状态:InternalKvState 将知识与实际的应用场景、设计背景关联起来,这是学以致用、刨根问底知识的一种直接方式。 本文介绍 状态数据管理&#x…...

SQL--多表查询
我们之前在讲解SQL语句的时候,讲解了DQL语句,也就是数据查询语句,但是之前讲解的查询都是单 表查询,而本章节我们要学习的则是多表查询操作,主要从以下几个方面进行讲解。 多表关系 项目开发中,在进行数据…...

多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测
多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测 目录 多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序…...

RK3568平台 安卓hal3适配usb camera
一.RK安卓hal3 camera框架 Camera hal3 在 android 框架中所处的位置如上图, 对上,主要实现 Framework 一整套 API 接口,响应其 控制命令,返回数据与控制参数结果。 对下, 主要是通 V4l2 框架实现与 kernel 的交互。3a…...

使用 Visual Studio Code 在远程计算机上调试 PostgreSQL
使用 Visual Studio Code 在远程计算机上调试 PostgreSQL 1. 概述 PostgreSQL 是一个功能强大的开源关系数据库管理系统,适用于各种应用程序。在开发过程中,调试 PostgreSQL 对于识别和解决问题至关重要。在本博客中,我们将手把手教你使用客…...
javascript设计模式之建造者
工厂模式不关心过程,只关心结果,这与建造者相反,建造者更关心的是过程, 这里我们创建一个基类,其拥有技能跟爱好两个属性,还有两个实例方法用来获取技能跟爱好 // 基类 let Human function (param {}) …...

安擎科技携手华为云区块链共同打造安全天空
当前,低空经济崛起,无人机多并发、混合运行时引发的网络信息安全、空域安全问题已成行业首要课题。 在2024年1月正式实施的《民用无人驾驶航空器运行安全管理规则》(CCAR-92)第549条中规定,“无人驾驶航空器航行服务提…...
学习数据结构的第一天
结构体 如何定义结构体 1、先定义结构体类型,再定义结构体类型变量 struct student/定义学生结构体类型/ { long number; char name[20]; char sex; int age; float score[3];/三科考试成绩/ }2、定义结构体类型同时定义结构体类型变量 struct student/定义学生结…...

5.electron之主进程起一个本地服务
如果可以实现记得点赞分享,谢谢老铁~ Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中,因此它允许你仅需一个代码仓库,就可以撰写支持 Windows、…...

爬取58二手房并用SVR模型拟合
目录 一、前言 二、爬虫与数据处理 三、模型 一、前言 爬取数据仅用于练习和学习。本文运用二手房规格sepc(如3室2厅1卫)和二手房面积area预测二手房价格price,只是练习和学习,不代表任何实际意义。 二、爬虫与数据处理 import requests import cha…...

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RichText组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RichText组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、RichText组件 鸿蒙(HarmonyOS)富文本组件,…...

7.electron之渲染线程发送事件,主进程监听事件
如果可以实现记得点赞分享,谢谢老铁~ Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中,因此它允许你仅需一个代码仓库,就可以撰写支持 Windows、…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...