Qt小项目之串口助手控制LED

前言

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

1.软件界面

2.主要功能:

  • 启动自动搜索本机串口,或者手动点击搜索键扫描串口
  • 自定义波特率
  • 支持中文显示
  • 支持发送新行

3.实际效果:

花了大概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文件,最底下添加一行:RC_ICONS = my_app.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已经为我们添加好了,当前程序运行所需要的组件了。

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

STM32端程序的实现

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

上位机发送 单片机执行
A1 红灯点亮
A2 红灯熄灭
B1 蓝灯点亮
B2 蓝灯熄灭

实现思路也很简单,即把接收到的字符存入一个字符数组,当接收到“\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工程下载

Qt工程文件和STM32工程文件,还包括Enigma_Virtual_Box的安装包,我都已经上传CSDN资源,有需要的朋友可下载:qt_uart_demo.rar

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


历史精选文章:


欢迎大家关注我的个人博客

或微信扫码关注我的公众号

Qt小项目之串口助手控制LED的更多相关文章

  1. 用 PYQT5 和 QT Dseingner 写的串口助手

    最近公司做项目需要写串口助手,于是从网上找教程着手写了一下,基本的功能可以实现了,但是想要一个表盘的功能一直没有找到教程,有些遗憾.大神们会的话给指导指导  谢谢啦 ! 下边有源码的连接,欢迎大家下载 ...

  2. Qt:小项目仿QQ修改头像界面,技术点记录

    最近写了一个修改头像功能的UI,布局参考了QQ目前的修改头像界面.如下图 这里主要说明一下两个地方的技术:1.头像图片上层的遮罩层,圆形外部为灰色,内部为全透明:2.上传图片宽高比例可以通过鼠标拖拽移 ...

  3. Qt 新手实战项目之手把手打造一个串口助手

    一前景 很多时候我们在学习一门新的语言,一直在学习各种语法和记住各种关键字,很容易产生枯燥的情绪,感觉学习这些玩意儿不知道用在什么地方,心里很是苦恼,这不,我在这记录下我学习Qt的第一个的小项目-串口 ...

  4. C#与Arduino通过串口通信来控制LED灯的状态

    一.引言 最近摆弄了一段时间的Arduino,发现Arduino做一些电子类项目.监控.机器人.电子玩具比较容易,并且Arduino与.NET程序集成也不难.接下来介绍一个简单的小程序,C#做的一个W ...

  5. 18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED

    https://www.cnblogs.com/yangfengwu/p/11112015.html 先规定一下协议 aa 55 02 01 F1 4C 控制LED点亮  F1 4C为CRC高位和低位 ...

  6. STM32学习笔记(二)——串口控制LED

    开发板芯片:STM32F407ZGT6 PA9-USART1_TX,PA10-USART1_RX; PF9-LED0,PF10-LED1; 一.串口1配置过程(不使用串口中断): 1.使能时钟,包括G ...

  7. STM32学习笔记(四)——串口控制LED(中断方式)

    目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类 ...

  8. QT串口助手(三):数据接收

    作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.前言 开发环境:Qt5.12.10 + MinGW 实现的功能 串口数据的接收 ascii字符形式显示与hex字符形式显 ...

  9. QT串口助手(四):数据发送

    作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.前言 开发环境:Qt5.12.10 + MinGW 实现的功能 串口数据的发送 ascii字符与hex字符的相互转换 自 ...

随机推荐

  1. Java并发编程(十三)线程间协作的两种方式:wait、notify、notifyAll和Condition

    在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果 ...

  2. Spring 事件

    JDK事件 java通过java.util.EventObject类和java.util.EventListener接口描述事件和监听器 事件源,事件的产生者,任何一个EventObject都必须拥有 ...

  3. JMeter—后置处理器(十)

    参考<全栈性能测试修炼宝典JMeter实战>第六章 JMeter 元件详解中第五节后置处理器后置处理器是用来处理采样器发送的请求后得到的响应数据 一.Debug PostProcessor ...

  4. Android 接收系统广播(动态和静态)

    1.标准广播:是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎会在同一时刻接收到这条广播信息,它们之间没有先后顺序.效率高.无法被截断. 2.有序广播:是一种同步执行的广播,在广播发出后 ...

  5. .net core 导出Excel(epplus 创建excel )

    [Route("getopenfrequencyexcel")] [HttpGet] public IActionResult GetOpenFrequencyExcel(int ...

  6. [HDFS_2] HDFS 的 Shell 操作

    0. 说明 在 Shell 下完成对 HDFS 的增删改查操作 1. 在 Shell 下完成对 HDFS 的增删改查操作 [1.0 查看帮助] [centos@s101 ~]$ hdfs dfs -h ...

  7. Django【进阶篇】

    目录 一.Model 二.admin 三.Form组件 四.Cookie 五.Session 六.分页 七.序列化 一.Model 数据库的配置 1.django默认支持sqlite,mysql, o ...

  8. GUI_事件监听机制与ActionListener演示

    事件监听机制组成: 事件源:(awt包或者swing包中的那些图形界面组件)(被打的那个人,被点击的组件,可以承受某些事件,但不是所有事件都能承受) 事件:每个事件源都有自己特有的对应事件和共性事件( ...

  9. IO流_SequenceInputStream(序列流)

    SequenceInputStream(序列流):就是将多个流合成一个有序的流 需求:将三个文件中的数据合并到一个文件中 import java.io.FileInputStream; import ...

  10. C#接口的显隐实现

    显示接口实现与隐式接口实现 何为显式接口实现.隐式接口实现?简单概括,使用接口名作为方法名的前缀,这称为“显式接口实现”:传统的实现方式,称为“隐式接口实现”.下面给个例子. IChineseGree ...