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

news2024/12/25 0:27:06

文章目录

  • 一、功能简介
  • 二、串口助手实现
    • 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的控件上。

    // 将可用串口显示到serialBox
    ui->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();
    }

    // 将可用串口显示到serialBox
    ui->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,未选中值为0
    if (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.coloradmin.cn/o/772318.html

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

相关文章

手把手教你搭建SpringCloud项目(八)集成Ribbon负载均衡器

一、Ribbon的简介 Ribbon是Neflix发布的开源项目&#xff0c;后由Spring Cloud开发团队封装于Spring Cloud中&#xff0c;可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。功能是提供客户端的软件负载均衡算法和服务调用。Ribbon是一个基于HTTP…

DevOps概念及搭建全过程(Jenkins、Harbor、SonarQube、K8s)

DevOps入门及过程搭建 在如今互联网的格局下&#xff0c;抢占市场变得尤为重要&#xff0c;因此敏捷开发越来越被大家所推崇。于是&#xff0c;慢慢的有了DevOps这个概念&#xff0c;大致意思是开发-运维一体化。 1 DevOps概念 1.1 基本概念 可以看到上图是一个无穷大的一个符…

[SQL系列] 从头开始学PostgreSQL Union Null 别名 触发器

初级的操作就是CRUD&#xff0c;但是高级的操作也是CRUD&#xff0c;只是语句写的更加复杂&#xff0c;不再是select * from table&#xff1b;这样简单&#xff0c;这次咱们学一些稍微高级点的。下面是上一篇文章。 [SQL系列] 从头开始学PostgreSQL 约束连接_Edward.W的博客-…

19c环境创建job报时间格式不对

有项目经理反馈&#xff0c;在19c环境中&#xff0c;创建job报错时间格式不对&#xff0c;报错如下&#xff1a; 解决办法&#xff1a; 在19c环境下&#xff0c;使用 sys.dbms_scheduler.create_job 12c以后 job其实底层还是调用sys.dbms_scheduler.create_job 从ORACLE 19C…

【wifi模块选型指导】数据传输WiFi模块的选型参考_USB/UART接口WiFi模块

数据传输WiFi模块有USB接口和UART接口两大类&#xff0c;为满足行业客户的不同应用需求&#xff0c;SKYLAB研发推出了多款2.4GHz单频&#xff0c;2.4/5GHz双频的USB接口WiFi模块和UART接口WiFi模块&#xff0c;数据传输能力&#xff0c;传输距离各有不同。怎么选才是最适合的呢…

软件测试人员的基本功包括哪些?

什么是基本功&#xff1f;百度到的结果是&#xff1a;从事某种工作所必需的基本的知识和技能。 推理1&#xff1a;“基本”二字&#xff0c;意味着基本功必定是来源测试工作的基本流程。 推理2&#xff1a;“必须”二字&#xff0c;就意味者无论你是高级的测试开发&#xff0c;…

基于JavaScript实现永远加载不满的进度条

fake-progress库的源码如下&#xff1a; var FakeProgress function (opts) {if (!opts) { opts {}; }this.timeConstant opts.timeConstant || 1000;this.autoStart opts.autoStart || false;this.parent opts.parent;this.parentStart opts.parentStart;this.parentEn…

ASUS华硕无双15_K3502ZA工厂模式原装Win11恢复原厂OEM预装系统 带ASUS Recovey恢复功能

ASUS华硕无双15笔记本电脑12代Vivobook_ASUSLaptop K3502ZA出厂Windows11系统工厂包 自带恢复功能、所有驱动、出厂主题壁纸LOGO、Office办公软件、MyASUS等预装程序 所需要工具&#xff1a;32G或以上的U盘 文件格式&#xff1a;HDI,SWP,OFS,EDN,KIT,TLK多个底包 文件大小&…

字符函数和字符串函数1(详解)

❤️ 作者简介 &#xff1a;对纯音乐情有独钟的阿甘 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识&#xff0c;对纯音乐有独特的喜爱 &#x1f4d7; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;如果你也感兴趣的话欢迎关注博主&#xff0c;期待更新 字符函数和…

JDBC编程连接MySQL数据库遇到的两个错误

在进行java与MySQL数据库进行连接的时候我遇到了两个报错&#xff0c;在一开始的时候遇到的报错是Access denied for user yulinlocalhost (using password: YES)&#xff0c;此时我在网络上搜索发现是密码出现错误的问题&#xff08;出现该问题确实是密码错误&#xff09;&…

cloudwatch agent通过squid代理上传指标到cloudwatch

1.安装cloudwatch agent代理 1.1、安装cloudwatch代理包 2.2、更改程序包的目录 3.3.创建cloudwatch代理配置文件 运行以下命令配置向导 sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard 按照提示选择个性化服务 2.安装squid服务器 简…

200行代码写一个简易的C++小黑窗贪吃蛇游戏

分享一个简易的小黑窗贪吃蛇,一共就两百行代码左右(包含注释),很适合初学者巩固语法来练练手. 如果后续需要其他功能也可以再添加. 先小小展示一下: 源码在文末免费领取. 使用工具: VS2019(不是用VS的也可以直接找出cpp和h文件复制到你们用的IDE,甚至是记事本都可以) 闲话…

three.js学习记录(基础)

前言&#xff1a; 页面渲染3D特效&#xff0c;可以从各种图表库&#xff08;例如ECharts&#xff09;中寻找各种适用的模版&#xff0c;也可以寻找第三方插件。。。 一直以来都对three.js充满向往&#xff0c;终于偷闲找了个借口学了起来 参考资料 Three.js – JavaScript 3D…

MySQL数据库(五)

目录 一、数据库的约束 1.1 约束类型 1.1.1 null约束 1.1.2unique约束 1.1.3default默认值约束 1.1.4primary key主键约束 1.1.5foreign key外键约束 二、内容重点总结 一、数据库的约束 1.1 约束类型 not null - 指示某列不能存储 null值。unique - 保证某列的每行必须有唯一…

【C++】入门基础知识

命名空间 由来 在c语言中&#xff0c;任何函数&#xff0c;变量的名字都不能一样&#xff0c;如果是一个人的代码库里还好&#xff0c;大不了自己再改改&#xff0c;但是当和其他人&#xff0c;公司的库合起来&#xff0c;那就很麻烦了&#xff0c;到底是谁的名字改呢&#x…

求Sn=a + aa + aaa + aaaa + aaaaa的前5项之和,其中a是一个数字

求Sna aa aaa aaaa aaaaa的前5项之和&#xff0c;其中a是一个数字。 例如&#xff1a;2 22 222 2222 22222 解析&#xff1a; a aa aaa aaaa aaaaa a a*10a (a*10a)*10 a ((a*10a)*10 a) a ((a*10a)*10 a) a 直接上代码吧&#xff1a; #include&l…

java工作随笔

String s JSONObject.toJSONString(fixedAsset);logger.error("-----------------8------------------" s);CusFixedAssettDTO CusFixedAssettDTO3 JSONObject.parseObject(s, CusFixedAssettDTO.class);父类转子类 相同对象合并 import java.util.Date; Data T…

手把手教你搭建SpringCloud项目(九)集成OpenFeign服务接口调用

一、OpenFeign简介 什么是Feign&#xff1f; Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行封装&#xff0c;使其支持…

要想做好日语翻译,你需要这样做?

我们知道&#xff0c;中日两国一衣带水比邻而居&#xff0c;彼此之间的文化贸易往来非常频繁&#xff0c;对日语翻译的需求也日益增加。那么&#xff0c;想要做好日语翻译&#xff0c;我们该怎么做&#xff1f; 首先&#xff0c;要具备扎实的日语语言能力、较高的母语水平以及灵…

零基础学习,轻松打造物业服务小程序

现如今&#xff0c;物业服务已经成为了人们生活中不可或缺的一部分。为了更好地满足人们对物业服务的需求&#xff0c;许多企业和个人开始开发物业服务小程序&#xff0c;以便提供更加便捷和高效的服务。然而&#xff0c;对于大多数人来说&#xff0c;搭建一个小程序可能需要一…