QT学习—【属于自己的】串口调试助手

文章目录

  • 一、功能简介
  • 二、串口助手实现
    • 2.1 创建UI
    • 2.2 扫描可用串口
    • 2.3 配置波特率
    • 2.4 配置数据位
    • 2.5 配置停止位
    • 2.6 配置校验位
    • 2.7 打开/关闭串口
    • 2.8 刷新串口
    • 2.9 发送新行
    • 2.10 串口发送
    • 2.11 串口接收显示
    • 2.12 清空接收窗口
    • 2.13 定时发送
    • 2.14 固定窗口大小
  • 三、总结
    • 3.1 将信号与槽函数关联
    • 3.2 优化方向

一、功能简介

最近尝试用QT实现了一个串口调试驻守于,作为一个刚接触QT的小白,当然是站在巨人的肩膀上完成了这个小项目。在实现过程中学习了许多内容,这里简单总结一下。

本次设计的串口调试助手只实现了一些基本功能

  • 打开/关闭串口
  • 刷新串口
  • 串口收/发
  • 定时发送
  • 清空接收窗口
  • 选择串口,配置波特率,数据位,停止位和校验位

实现效果如下

串口调试助手

二、串口助手实现

下面首先再明确一下功能。打开串口时会提示“串口打开成功”或者“串口打开失败”。打开成功后会禁用选择串口,刷新串口,配置波特率,数据位,停止位和校验位的功能。关闭串口后恢复使用。

功能禁用

由于使能和失能控件的方法比较简单,就在这介绍,不再单独介绍了。

  • 失能控件
ui->控件名->setEnabled(false);
  • 使能控件
ui->控件名->setEnabled(true);

2.1 创建UI

在开始程序编写前,先创建UI界面。创建UI时使用的控件如果和博主的不同的话,程序可能会不能直接复用,需要注意一下。本项目主要用到了这些控件

  • QLabel
    该控件是标签,用来提示,比如UI中的“串口”,“波特率”等字样,就是用的QLabel控件。
  • QComboBox
    该控件为多选下拉框。UI中可选串口号,波特率,数据为,停止位,校验位这些都是使用的该控件。双击控件可以编辑下拉框成员。
  • QPushButton
    该控件为按钮。UI中的发送,打开/关闭串口等,都是使用的该控件。
  • QLineEdit
    QLineEdit是一个单行文本编辑器,UI中定时时间输入,发送内容输入框都是使用的该控件。
  • QCheckBox
    QCheckBox为复选框控件,UI中“定时发送”和“发送新行”使用的就是该控件。该控件可以添加一个“stateChange(int)”槽函数。可以通过int变量的值来判断复选框是否被选中。如果复选框被选中,int变量的值为2,未被选中,int变量的值为0。
  • QTextBroswer
    该控件是一个文本阅读器,UI中串口接收内容的显示用到了该控件。

2.2 扫描可用串口

扫描可用串口的方法是

    // 搜索所有可用串口foreach (const QSerialPortInfo &inf0, QSerialPortInfo::availablePorts()) {serialNamePort<<inf0.portName();}

扫描可用串口用在两个地方,首先是用在刚打开软件时,扫描当前可用串口。扫描到可用串口后,需要将可用串口号显示到UI的控件上。

    // 将可用串口显示到serialBoxui->serialBox->addItems(serialNamePort);

其次用到扫描可用串口的地方就是“刷新串口”按键,后面会有介绍。

2.3 配置波特率

打开串口时,会根据UI界面波特率的下拉框中选择的值配置波特率。配置方法是直接获取下拉框中的字符,将其转换成int型变量,然后配置波特率。

        // toInt将baudrateBox中的字符串转换成整型数serialPort->setBaudRate(ui->baudrateBox->currentText().toInt());   // 波特率

2.4 配置数据位

配置数据位时,无法像配置波特率一样,直接获取下拉框中的字符串,转换成int型直接赋值。这里选择先将数据位下拉框内容转换成int型,然后用switch语句配置数据位

        // 用switch语句设置数据位switch (ui->databitBox->currentText().toInt()){case 5:serialPort->setDataBits(QSerialPort::Data5);   // 5位break;case 6:serialPort->setDataBits(QSerialPort::Data6);   // 6位break;case 7:serialPort->setDataBits(QSerialPort::Data7);   // 7位break;case 8:serialPort->setDataBits(QSerialPort::Data8);   // 8位break;default:serialPort->setDataBits(QSerialPort::Data8);   // 8位break;}

2.5 配置停止位

配置停止位也无法直接使用数字,这里使用另一个方法。获取停止位下拉框中的字符,利用if语句完成停止位的配置。

        // 设置停止位,直接用字符做判断if (ui->stopbitBox->currentText() == "1"){serialPort->setStopBits(QSerialPort::OneStop);   // 1位停止位}else if (ui->stopbitBox->currentText() == "1.5"){serialPort->setStopBits(QSerialPort::OneAndHalfStop);   // 1.5位停止位}else if (ui->stopbitBox->currentText() == "2"){serialPort->setStopBits(QSerialPort::TwoStop);   // 2位停止位}else   // 默认1位停止位{serialPort->setStopBits(QSerialPort::OneStop);   // 1位停止位}

2.6 配置校验位

配置校验位与配置停止位的方法相同,也是使用if语句。

        // 设置校验位,也用if直接判断字符串if (ui->checkBox->currentText() == "None"){serialPort->setParity(QSerialPort::NoParity);   // 无校验}else if (ui->checkBox->currentText() == "Odd"){serialPort->setParity(QSerialPort::OddParity);   // 奇校验}else if (ui->checkBox->currentText() == "Even"){serialPort->setParity(QSerialPort::EvenParity);   // 偶校验}else   // 默认无校验{serialPort->setParity(QSerialPort::NoParity);   // 无校验}

2.7 打开/关闭串口

打开串口和关闭串口使用的是同一个按钮。刚打开是,按钮为“打开串口”。打开串口成功后,将按钮上显示的字符修改为“关闭串口”。点击按钮时,根据按钮上的字符来判断是执行打开串口还是关闭串口。实现框架如下

    // 打开串口if (ui->openButton->text() == "打开串口"){// 打开串口}else   // 关闭串口{// 关闭串口}

当然,也可以使用标志位实现。

打开串口和关闭串口的函数为

    bool open(OpenMode mode) override;void close() override;

2.8 刷新串口

刷新串口的功能是重新扫描当前可用串口,然后将当前可用串口号显示到串口的下拉框中。扫描方法上面已经介绍过了,需要注意的是,点击刷新串口,扫描完当前可用串口后,需要将之前串口下拉框中的显示内容清除掉再重新显示。

// 刷新串口
void MainWindow::on_refrashButton_clicked()
{QStringList serialNamePort;// 先清除一下之前串口号中的显示内容ui->serialBox->clear();// 搜索所有可用串口foreach (const QSerialPortInfo &inf0, QSerialPortInfo::availablePorts()) {serialNamePort<<inf0.portName();}// 将可用串口显示到serialBoxui->serialBox->addItems(serialNamePort);
}

2.9 发送新行

发送新行是使用复选框实现的。在发送前会先检测是否勾选了发送新行,判断方法如下

    // 如果发送新行被勾选if (ui->newLineBox->isChecked()){// 发送新行}

2.10 串口发送

按下“串口发送”按钮,首先获取输入的内容,然后根据是否需要发送新行来判断是否需要在结尾增加换行。“串口发送”按钮的槽函数如下。

// 发送按钮
void MainWindow::on_sendButton_clicked()
{// 如果发送新行被勾选if (ui->newLineBox->isChecked()){// 多行文本框用sendEdit()获取内容// QLineExit内容用text()获取内容serialPort->write(ui->sendEdit->text().toLatin1() + "\r\n");      // 串口发送数据}else{serialPort->write(ui->sendEdit->text().toLatin1());      // 串口发送数据}
}

2.11 串口接收显示

上位机需要显示串口接收到的内容。有一个reayRead信号,一旦上位机接收到数据,就会想应该信号。将该信号绑定到显示接收内容的槽函数,一旦接收到数据,就开始显示。绑定方法如下

    // 将readyRead信号链接到Read_Data函数connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::Read_Data);

显示数据的槽函数如下。

// 读取接收到的数据并显示
void MainWindow::Read_Data()
{QByteArray buf;// 读取全部接收数据buf = serialPort->readAll();// 如果接收内容非空if(!buf.isEmpty()){QString str = ui->receiveBrowser->toPlainText();str += tr(buf);ui->receiveBrowser->clear();ui->receiveBrowser->append(str);}buf.clear();
}

2.12 清空接收窗口

// 清除窗口
void MainWindow::on_clearButton_clicked()
{ui->receiveBrowser->clear();
}

2.13 定时发送

定时发送需要用到定时器,需要先添加定时器的头文件

// 定时器头文件
#include<QTimer>

然后添加一个定时发送时间的类成员

    // 定时发送时间间隔QTimer *timSend;

将倒计时结束信号关联到串口发送槽函数

    // 定时发送timSend = new QTimer;timSend->setInterval(1000);   // 设置默认值1000ms// 定时发送与发送按键函数关联connect(timSend,&QTimer::timeout,this,[=](){on_sendButton_clicked();});

定时发送功能时使用复选框实现的。关于复选框上面介绍了,可以根据一个int型变量的值来判断选中状态。定时发送勾选后需要失能定时时间编辑和发送按钮。取消勾选后,恢复定时器时间编辑和发送按钮的使用。定时发送函数如下

// 定时发送
void MainWindow::on_timeSendBox_stateChanged(int arg1)
{// 获取复选框选中状态// 选中值为2,未选中值为0if (arg1 == 0){// 结束计时timSend->stop();// 恢复定时时间可编辑ui->timeEdit->setEnabled(true);// 恢复发送按钮ui->sendButton->setEnabled(true);}else{// 根据设置时间开始计时timSend->start(ui->timeEdit->text().toInt());// 禁用定时时间可编辑ui->timeEdit->setEnabled(false);// 禁用发送按钮ui->sendButton->setEnabled(false);}
}

2.14 固定窗口大小

为了防止窗口大小改变,这里选择禁用最大化按钮,固定窗口大小,防止被鼠标拖动放大。程序实现方法如下

    // 禁用最大化按钮setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint);// 禁止拖动窗口大小setFixedSize(673,620);

窗口大小可以在UI文件中查看,选中窗口,查看右侧属性栏。

查看窗口大小

三、总结

3.1 将信号与槽函数关联

之前一直使用的是右键控件,选择转到槽来实现的关联。这里学习到了利用“connect”关联信号与槽函数。connect基本格式如下

connect(控件名, SIGNAL(要关联的信号), this, SLOT(槽函数));

也可以像上面关联readyRead信号时那样写

connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::Read_Data);

或者像关联定时结束信号时那样写

    connect(timSend,&QTimer::timeout,this,[=](){on_sendButton_clicked();});

3.2 优化方向

正如最开始所说,本文只是实现了简单的串口助手的功能,后续可以优化的方向还有很多。比如

  • 支持显示中文
  • 支持保存接收内容
  • 下方显示接收到的内容字符数
  • 增加时间戳等

但是针对本人平时的使用已经足够了,因此暂时并不考虑优化,后续使用过程中遇到问题再考虑。有意思的是,本人使用该串口助手访问API时,能够看到API返回来的中文。下图是利用WIFI模块访问心知天气API返回的数据。

访问心知天气API返回的信息

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

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

相关文章

本地前端项目使用gitee仓库外链图片加载失败

错误&#xff1a;本地的前端项目&#xff0c;比如vue&#xff0c;纯html使用<img/>标签加载gitee保存的图片文件的时候&#xff0c;浏览器加载失败。 但是gitee可以正常访问图片 解决办法&#xff1a; 在index.html中加入meta标签就可以完美解决 <meta name"r…

centos升级龙蜥

centos升级龙蜥 龙蜥简介龙蜥官方社区centos升级龙蜥首先确认自己的centos版本下载迁移镜像源安装epel源迁移工具安装i686包查看执行迁移脚本结果查看重启机器查看系统信息 龙蜥简介 2021年10月19日的大会上&#xff0c;阿里云发布全新操作系统“龙蜥”并宣布开源。龙蜥操作系…

python 批量下载图片(协程)

要下载的图片网站 1、总共多少页&#xff0c;得到每页的 url 列表 2、每页的图片详情的 ulr 列表&#xff08;因为该高清大图在图片详情页&#xff0c;因此需要去图片详情页拿图片的url) ​​​​​​​ 3、进入图片详情页&#xff0c;获取到图片url 然后下载。 完整代码如下&…

涂鸦智能打造专业家庭智能生活助手,实现人机交互升级

近年来&#xff0c;智能家居设备的品类不断拓展&#xff0c;同时&#xff0c;人们对AI与智能家居的联动愈发憧憬。自然语言交互是未来人机交互的主要趋势之一&#xff0c;其关键在于使AI具备主动理解信息的能力&#xff0c;让用户的交互更轻松。如何将智能场景的交互变得更“善…

SpringBoot中通过自定义Jackson注解实现接口返回数据脱敏

场景 SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文&#xff0c;查询明文&#xff1a; SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文&#xff0c;查询明文_霸道流氓气质的博客-CSDN博客 上面讲的是数据库中存储密文&#xff0…

HTML+CSS+JavaScript:渲染柱形统计图

一、需求 用户输入四个季度的数据&#xff0c;根据数据生成柱形统计图&#xff0c;浏览器预览效果如下 二、完整代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content&q…

【图像分割 2023 CVPR】CFNet

文章目录 【图像分割 2023 CVPR】CFNet摘要1. 简介2. 相关工作2.1 稠密预测的主干网设计2.2 多尺度特征融合 3. 方法3.1 整体架构3.2 过渡块3.4 结构变体 【图像分割 2023 CVPR】CFNet 论文题目&#xff1a;CFNet: Cascade Fusion Network for Dense Prediction 中文题目&#…

音视频H265编码; Socket通信实现N对N连接代码示例

H.265编码和Socket通信是两个不同的概念&#xff0c;它们分别涉及视频编码和网络通信。在实现N对N连接时&#xff0c;您可以将它们结合起来&#xff0c;但要注意每个方面的具体实现。 H.265编码&#xff08;视频编码&#xff09;&#xff1a; H.265编码涉及将视频数据进行压缩…

❤️创意网页:打造简洁美观的网页轮播图(HTML简单实现轮播图)操作简单可以直接使用

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

EMC学习笔记(十七)PCB设计中的安规考虑

PCB设计中的安规考虑 1 概述2.安全标识2.1 对安全标示通用准则2.2 电击和能量的危险2.3 PCB上的熔断器2.4 可更换电池 3.爬电距离和电气间隙4.涂覆印制板4.1 PCB板的机械强度4.2 印制电路板的阻燃等级4.3 热循环试验与热老化试验4.4 抗电强度试验4.5 耐划痕试验 5.布线和供电 1…

【智能交互】OPPO接入小布语音技能通关教程:个人开发者实现接口调用

目录 前言实际操作注册OPPO平台账号打开创建技能界面创建技能创建意图槽位解析对话管理对话测试接口代码编写接口创建新建意图对话管理测试猜想测试相关文档前言 适用人群:本教程适合大赛接入小布语音技能的同学以及初次使用小布助手的开发者 本篇文章是博主弄了多次测试才勉…

智慧数据驱动:基于smardaten构建多维数据可视化大屏

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

node基于express+mongodb项目的整体结构搭建和逻辑抽离

一、为什么需要逻辑抽离 这是我用express实现的一个缩减版的注册功能,如下&#xff1a; app.js const express require("express"); const app express();// 连接数据库 const mongoose require("mongoose"); // 连接数据库myTest mongoose.connect(…

关于Windows 11 docker desktop 运行doris 容器时vm.max_map_count=2000000的设置问题

需要一个简单的测试环境&#xff0c;于是准备用docker启动一个1fe 1be的简单玩一下 如果be容器启动后再去修改 /etc/sysctl.conf sysctl -w vm.max_map_count2000000 这个参数是没用的&#xff0c;be仍然会启动失败 这时可以打开cmd wsl --list C:\Users\pc>wsl --list …

ES系列--打分机制

一、文档打分机制 当你通过关键字搜索相关文档时&#xff0c;可能会出现多个文档&#xff0c;这些文档的顺序是通过一个max_score属性的大小从高到低顺序展现出来的&#xff0c;max_score属性就是我们所说的评分。而这个评分是通过一个文档打分机制计算出来的。 二、打分原理 …

JDK 下载 华为云镜像站 地址

通常去 Oracle 官网下载 JDK&#xff0c;速度很慢而且需要账号登入 Oracle 官网下载地址 https://www.oracle.com/cn/java/technologies/downloads/archive/ JDK 下载 华为云镜像站 地址 https://repo.huaweicloud.com/java/jdk/ 我们下期见&#xff0c;拜拜&#xff01;

CentOS 8 GLIBC升级失败系统崩溃抢修实战

CentOS 8 GLIBC升级失败系统崩溃抢修实战 1. 恐怖的问题2. 参考解决方案3. 抢修实战3.1 准备工作3.2 抢修流程3.3 解决启动后Permission Denied3.3.1 参考方案3.3.2 解决 4. 总结 服务器为CentOS 8&#xff0c;支持glibc版本为2.28&#xff0c;但编译一个工具的glibc需求版本为…

MySQL-概述-数据模型SQL简介

数据库&#xff1a;DataBase&#xff08;DB&#xff09;&#xff0c;是存储和管理数据的仓库数据库管理系统&#xff1a;DataBase Management System&#xff08;DBMS&#xff09;&#xff0c;操作和管理数据库的大型软件。SQL&#xff1a;Structured Query Language&#xff0…

spring boot 多模块项目非启动模块的bean无法注入(问题记录)

之前有说我搭了一个多模块项目&#xff0c;往微服务升级&#xff0c;注入的依赖在zuodou-bean模块中&#xff0c;入jwt拦截&#xff0c; Knife4j ,分页插件等等&#xff0c;但是启动类在system中&#xff0c;看网上说在启动类上加SpringBootApplication注解默认扫描范围为自己…

物联网(IoT):连接未来的万物之网

引言&#xff1a; 物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;是指通过各种智能设备和传感器&#xff0c;使物体能够互联互通、收集和共享数据的网络。随着科技的不断进步和智能设备的普及&#xff0c;物联网的应用呈现出爆发式增长&#xff0c;对各…