手把手教你用Qt写个串口上位机

原创 电子电路开发学习 2024-03-13 19:30


前言

最近刚学了一点Qt开发上位机,尝试着做个小软件练练手。查找了很多资料,做了一个简单的串口助手,可以实现串口基本发送和接收功能,支持中文显示,还可以控制STM32开发板上的两个LED。

1.软件界面

2.主要功能:

  • 启动自动搜索本机串口,或者手动点击搜索键扫描串口

  • 自定义波特率

  • 支持中文显示

  • 支持发送新行

3.实际效果:

(GIF压缩后根本没法看。。。。)

花了大概3天时间吧,找了很多资料,功能很简单, 但想着是自己一点一点开发的,还是挺有成就感的哈!

写这篇文章是为了总结一下开发的过程和一些知识点,主要包括两部分,上位机的实现和STM32端程序的实现。

Qt上位机的实现

0.新建一个Dialog项目

新建一个Dialog项目,这3种基类的区别可以根据你的程序来确定。

  • 如果需要嵌入到其他窗体中,则基于QWidget创建。

  • 如果是主窗体,则基于QMainWindow创建,有菜单栏,状态栏,工具栏等。

  • 如果是顶级对话框,则基于QDialog创建。


1.软件UI界面的设计

使用Qt Designer添加所需要的控件,并进行合理布局,尽量每一个控件,起一个合理易懂的名字。

2.串口库的添加

pro文件添加一行:

  1. QT += serialport

对应的头文件包含:

  1. #include <QSerialPort>

  2. #include <QSerialPortInfo>

3.串口自动搜索功能的实现

自动搜索本机串口,并在ComboBox中添加串口号

  1. ui->cbb_com->clear();

  2. //运行开始查找可用串口

  3. foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())

  4. {

  5. ui->cbb_com->addItem(info.portName()); //串口号下拉菜单,增加一个条目,为串口号COM4

  6. qDebug() << "串口搜索完成";

  7. }

4.串口的配置和打开关闭

  1. //打开串口按钮

  2. void Dialog::on_btn_uart_Ctrl_clicked()

  3. {

  4. // static bool flag; //也可以用标志位实现

  5. if(this->ui->btn_uart_Ctrl->text() == "打开串口") //初始状态,配置串口参数

  6. {

  7. serial.setPortName(ui->cbb_com->currentText()); //设置串口号、

  8. serial.setBaudRate(ui->cbb_baud->currentText().toInt()); //设置波特率

  9. serial.setDataBits(QSerialPort::Data8); //设置串口数据位8

  10. serial.setParity(QSerialPort::NoParity); //无校验位

  11. serial.setStopBits(QSerialPort::OneStop); //1位停止位

  12. serial.setFlowControl(QSerialPort::NoFlowControl);

  13. //打开串口

  14. if(!serial.open(QIODevice::ReadWrite))

  15. {

  16. QMessageBox::critical(NULL, "提示", "串口打开失败");

  17. return;

  18. }

  19. qDebug() << "串口打开成功";

  20. this->ui->btn_uart_Ctrl->setText("关闭串口");

  21. }

  22. else

  23. {

  24. //关闭串口

  25. serial.close();

  26. this->ui->btn_uart_Ctrl->setText("打开串口");

  27. }

  28. }

5.串口发送数据

  1. serial.write("A1\n"); //串口发送A1

6.串口数据的接收和显示,支持中文

QT默认的编码是unicode,不能显示中文的,windows默认使用(GBK/GB2312/GB18030),使用了fromLocal8Bit()函数,实现了从Unicode到本地字符集GBK的转换,用于处理汉语显示乱码等问题

槽函数的实现:

  1. //串口数据接收并显示

  2. void Dialog::serialPort_readyRead()

  3. {

  4. QByteArray rx_buf = serial.readAll(); //读取串口接收的数据

  5. if(rx_buf.endsWith("\r\n")) //判断接收最后是否是回车换行,即接收完成标志

  6. {


  7. }

  8. QString rx_buf_tmp = QString::fromLocal8Bit(rx_buf); //转换为中文格式

  9. qDebug() << rx_buf_tmp; //控制台输出


  10. ui->tb_rx_buf->append(rx_buf_tmp);


  11. rx_buf_tmp.clear();

  12. rx_buf.clear();

  13. }

connect语句:

  1. connect(&serial, & QSerialPort::readyRead, this, &Dialog::serialPort_readyRead);

7.下拉框自定义波特率的实现

  1. //自定义波特率

  2. void Dialog::on_cbb_baud_currentIndexChanged(const QString &arg1)

  3. {

  4. if(this->ui->cbb_baud->currentIndex() == 3)

  5. {

  6. this->ui->cbb_baud->setItemText(3, ""); //调成自定义波特率时,内容设置为空,准备接收输入

  7. this->ui->cbb_baud->setEditable(true);

  8. }

  9. else

  10. {

  11. this->ui->cbb_baud->setItemText(3, "自定义"); //调成自定义波特率时,内容设置为空,准备接收输入

  12. this->ui->cbb_baud->setEditable(false);

  13. }

  14. serial.setBaudRate(ui->cbb_baud->currentText().toInt()); //即使打开串口后,仍然可以设置波特率

  15. }

8.发送新行功能的实现

通过一个全局变量实现,发送新行按钮勾选时,标志位置1,然后发送按钮功能里,根据标志位决定是否在末尾添加换行符。

对应的槽函数实现:

  1. //是否发送新行

  2. void Dialog::on_cb_send_enter_clicked()

  3. {

  4. if(ui->cb_send_enter->isChecked())

  5. {

  6. send_enter_flag = true;

  7. qDebug() << "发送新行";

  8. }

  9. else

  10. {

  11. send_enter_flag = false;

  12. qDebug() << "不发送新行";

  13. }

  14. }

  15. //发送按钮被按下

  16. void Dialog::on_btn_send_clicked()

  17. {

  18. //获取多行输入框的数据并转换为UTF8格式

  19. QByteArray tx_buf = ui->te_tx_buf->toPlainText().toUtf8();


  20. if(send_enter_flag == true)

  21. tx_buf += "\n";


  22. serial.write(tx_buf); //把数据通过串口发送出去

  23. tx_buf.clear();

  24. }

9.只改变标签颜色

本来想着通过改变样式表的方式改变颜色

  1. this->ui->lbe_blue->setStyleSheet("color: rgb(255, 0, 0);");

但是,实际运行时,连字体和大小都改成了默认的,有没有一种只改变颜色其他的格式不变的方法呢?还真有,如下,不过好像只支持标准颜色?

  1. QPalette colr;

  2. colr.setColor(QPalette::WindowText,Qt::red); //设置标签颜色红色

  3. this->ui->lbe_red->setPalette(colr);

10.按钮的使能失能控制

以下两行语句效果相同,都是失能按钮功能:

  1. this->ui->btn_led1_Ctrl->setDisabled(true); //LED控制按钮不可用

  2. this->ui->btn_led1_Ctrl->setEnabled(false); //LED控制按钮不可用

11.文本显示框设置最大显示行数

  1. this->ui->tb_rx_buf->document()->setMaximumBlockCount(10);

程序的图标、标题设置和打包发布

你不希望窗口的标题是“Dialog”吧,所以添加一个标题和一个好看的图标还是很有必要的。

1.添加标题

添加窗口标题还是很简单的,一行代码:

  1. this->setWindowTitle("串口控制LED - By wcc ");

2.添加icon图标

  • 找一个好看的图标,格式一定要是.ico,像素大小推荐128*128

  • 命名为my_app.ico,名字无所谓,不要有中文就好了,放在工程目录下,即和.pro文件和.cpp文件同一个目录。

  • 打开.pro文件,最底下添加一行:RCICONS = myapp.ico

重新编译就可以看到这种效果了。

3.程序文件的生成

构建选项改成Release版本,编译完成后,会在Release目录下生成一个.exe文件,把这个文件单独拷出来放在一个空白的文件夹里,如 D:\QT_Prj\Export\UART_Demo.exe,可以运行试一下,会提示缺少运行所需要的dll组件

而且,这个文件如果单独拷贝到其他没有安装Qt环境的电脑上,也是不能运行的。

所以我们需要添加一些当前程序运行所需要的组件才能正常运行,但是需要添加哪些文件呢?不用担心,Qt早已经想好了,运行MinGW工具:

先进入到exe文件所在的文件夹中: cd/d D:\QT_Prj\Export

然后输入命令: windeployqt UART_Demo.exe

此时,打开exe文件所在的文件夹,可以看到Qt已经为我们添加好了,当前程序运行所需要的组件了。

这个时候,如果想给别人分享你开发好的上位机软件,就可以直接把这个文件夹拷贝给他。当然也可以安装一个 EnigmaVirtualBox软件,把当前目录下的所有文件打包成一个exe文件。

STM32端程序的实现

连接串口模块,发送接收短接,可以看出Qt上位机的的收发都是正常的。下一步就是编写STM32端的程序了,很简单,当接收到字符串"A1"时,点亮红灯;当接收到字符串“A2”时,熄灭红灯;当接收到字符串“B1”时,点亮蓝灯;当接收到字符串“B2”时,熄灭蓝灯,每个字符串结尾都有换行符“\n”。

实现思路也很简单,即把接收到的字符存入一个字符数组,当接收到“\n”换行标志时,意味着接收完成,判断此时数组的内容,分别和命令比较,如果一致,执行相应的操作,串口1中断服务函数:

  1. void USART1_IRQHandler(void)

  2. {

  3. char dat;

  4. char flag = 0;

  5. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断

  6. {

  7. dat = USART1->DR;

  8. if(usart1Len >= 64) //防止数据过多,导致内存溢出

  9. usart1Len = 0;

  10. if(dat == 0x0D || dat == 0x0A) //回车换行,接收完成,此时的buf不含回车换行

  11. {

  12. if(strcmp(usart1Buf, "A2") == 0) //字符串比较

  13. {

  14. UsartPrintf(USART1, "红灯熄灭\r\n");

  15. GPIO_SetBits(GPIOB, GPIO_Pin_9);

  16. }

  17. else if(strcmp(usart1Buf, "A1") == 0)

  18. {

  19. UsartPrintf(USART1, "红灯点亮\r\n");

  20. GPIO_ResetBits(GPIOB, GPIO_Pin_9);

  21. }

  22. else if(strcmp(usart1Buf, "B2") == 0)

  23. {

  24. UsartPrintf(USART1, "蓝灯熄灭\r\n");

  25. GPIO_SetBits(GPIOB, GPIO_Pin_6);

  26. }

  27. else if(strcmp(usart1Buf, "B1") == 0)

  28. {

  29. UsartPrintf(USART1, "蓝灯点亮\r\n");

  30. GPIO_ResetBits(GPIOB, GPIO_Pin_6);

  31. }

  32. usart1Len = 0;

  33. memset(usart1Buf,0,64);

  34. }

  35. else

  36. {

  37. usart1Buf[usart1Len++] = dat;

  38. }

  39. USART_ClearFlag(USART1, USART_FLAG_RXNE);

  40. }

  41. }

程序还是很简单。板子是用的中移的麒麟座Mini板,基于F103C8T6的,串口1连接上位机,波特率115200,PB9-红灯,PB6-绿灯,都是低电平点亮。

改进和优化的地方

  • 按钮发送字符可自定义

  • 界面UI的设计优化

  • 数据波形的显示

  • 发送和接收,16进制和字符模式的切换

  • 定时发送功能

  • 接收内容保存成文件

  • 一个小Bug,不支持多个串口的自动搜索。

Qt工程和STM32工程下载

由于国内Github下载速度实在令人着急,Qt工程文件和STM32工程文件,还包括EnigmaVirtualBox的安装包,我都已经上传到国内的码云Gitee上了,有需要的朋友可以在Git中使用以下命令下载:

  1. git clone https://gitee.com/whik/qt_uart_demo.git

或者是在公众号后台回复【串口助手】,我会把下载链接发送给你。

当然,如果有朋友也在学习Qt开发上位机,欢迎互相交流学习。

​​

更多

  • 使用STM32获取东京奥运奖牌榜

  • 使用STM32获取疫苗接种数据

  • 使用STM32获取新冠肺炎疫情数据

  • 如何写出易于维护的Verilog代码?

  • FPGA如何进行片上调试

  • 一文看懂Modbus协议

  • 一文看懂I2C协议

  • 一文看懂SPI协议

电子电路开发学习 单片机点灯小能手,电子行业从业者。开发板评测、嵌入式开源项目分享、学习笔记记录。可能不会经常更新,但每一篇都是精心编写。
评论
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 76浏览
  • 自动化已成为现代制造业的基石,而驱动隔离器作为关键组件,在提升效率、精度和可靠性方面起到了不可或缺的作用。随着工业技术不断革新,驱动隔离器正助力自动化生产设备适应新兴趋势,并推动行业未来的发展。本文将探讨自动化的核心趋势及驱动隔离器在其中的重要角色。自动化领域的新兴趋势智能工厂的崛起智能工厂已成为自动化生产的新标杆。通过结合物联网(IoT)、人工智能(AI)和机器学习(ML),智能工厂实现了实时监控和动态决策。驱动隔离器在其中至关重要,它确保了传感器、执行器和控制单元之间的信号完整性,同时提供高
    腾恩科技-彭工 2025-01-03 16:28 166浏览
  • 光耦合器,也称为光隔离器,是一种利用光在两个隔离电路之间传输电信号的组件。在医疗领域,确保患者安全和设备可靠性至关重要。在众多有助于医疗设备安全性和效率的组件中,光耦合器起着至关重要的作用。这些紧凑型设备经常被忽视,但对于隔离高压和防止敏感医疗设备中的电气危害却是必不可少的。本文深入探讨了光耦合器的功能、其在医疗应用中的重要性以及其实际使用示例。什么是光耦合器?它通常由以下部分组成:LED(发光二极管):将电信号转换为光。光电探测器(例如光电晶体管):检测光并将其转换回电信号。这种布置确保输入和
    腾恩科技-彭工 2025-01-03 16:27 171浏览
  •     为控制片内设备并且查询其工作状态,MCU内部总是有一组特殊功能寄存器(SFR,Special Function Register)。    使用Eclipse环境调试MCU程序时,可以利用 Peripheral Registers Viewer来查看SFR。这个小工具是怎样知道某个型号的MCU有怎样的寄存器定义呢?它使用一种描述性的文本文件——SVD文件。这个文件存储在下面红色字体的路径下。    例:南京沁恒  &n
    电子知识打边炉 2025-01-04 20:04 82浏览
  • 本文介绍Linux系统更换开机logo方法教程,通用RK3566、RK3568、RK3588、RK3576等开发板,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。制作图片开机logo图片制作注意事项(1)图片必须为bmp格式;(2)图片大小不能大于4MB;(3)BMP位深最大是32,建议设置为8;(4)图片名称为logo.bmp和logo_kernel.bmp;开机
    Industio_触觉智能 2025-01-06 10:43 72浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 89浏览
  • 物联网(IoT)的快速发展彻底改变了从智能家居到工业自动化等各个行业。由于物联网系统需要高效、可靠且紧凑的组件来处理众多传感器、执行器和通信设备,国产固态继电器(SSR)已成为满足中国这些需求的关键解决方案。本文探讨了国产SSR如何满足物联网应用的需求,重点介绍了它们的优势、技术能力以及在现实场景中的应用。了解物联网中的固态继电器固态继电器是一种电子开关设备,它使用半导体而不是机械触点来控制负载。与传统的机械继电器不同,固态继电器具有以下优势:快速切换:确保精确快速的响应,这对于实时物联网系统至
    克里雅半导体科技 2025-01-03 16:11 178浏览
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 110浏览
  • PLC组态方式主要有三种,每种都有其独特的特点和适用场景。下面来简单说说: 1. 硬件组态   定义:硬件组态指的是选择适合的PLC型号、I/O模块、通信模块等硬件组件,并按照实际需求进行连接和配置。    灵活性:这种方式允许用户根据项目需求自由搭配硬件组件,具有较高的灵活性。    成本:可能需要额外的硬件购买成本,适用于对系统性能和扩展性有较高要求的场合。 2. 软件组态   定义:软件组态主要是通过PLC
    丙丁先生 2025-01-06 09:23 71浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 93浏览
  • 随着市场需求不断的变化,各行各业对CPU的要求越来越高,特别是近几年流行的 AIOT,为了有更好的用户体验,CPU的算力就要求更高了。今天为大家推荐由米尔基于瑞芯微RK3576处理器推出的MYC-LR3576核心板及开发板。关于RK3576处理器国产CPU,是这些年的骄傲,华为手机全国产化,国人一片呼声,再也不用卡脖子了。RK3576处理器,就是一款由国产是厂商瑞芯微,今年第二季推出的全新通用型的高性能SOC芯片,这款CPU到底有多么的高性能,下面看看它的几个特性:8核心6 TOPS超强算力双千
    米尔电子嵌入式 2025-01-03 17:04 48浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 97浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦