所有教程由网友发布,仅供参考,请谨慎采纳。科创不对教程的科学性、准确性、可靠性负责。
QT上位机搭建教程
李艺良
全桥整流2025/05/23原创 秋名山最速传说 IP:广东

前言:

用正点原子的串口助手通过串口指令控制MCU有点不够智能,参数配置全是字母数字,配置起来也不直观,用QT搞个上位机出来控制MCU玩玩。上位机有按钮,文本框,下拉选择框,图片,数字控件。下位机就是串口,LED闪烁。

这篇文章主要目的是怎么使用QT搓出一个能用的上位机,更复杂的功能直接用简单功能拓展就行,毕竟本质还是串口(USB也有可能)互传数据(加个传输协议啥的),只不过给了个UI界面。这篇文章是教程性质,重点放在上位机基础工程的搭建(下位机串口接收教程很多,本文重点不在这方面)。


正文(上位机编写):

1、首先是程序功能设计,在上位机界面中可以通过下拉选择框选择点亮RGB灯中的任意一盏灯,数字控件控制对应LED灯的闪烁次数和频率,文本框显示使用说明和串口收发的数据,按钮控制数据的发送。


2、MCU的上位机开发一般使用Qt Creator,也有使用VS+QT,但我更喜欢前者UI界面且可以敏捷开发,因此选用Qt Creator。Qt Creator的安装教程省略,重点是要上QT官网注册账号,不注册账号无法正常安装,建议安装5.14.2之前的版本,之后的版本要手动编译比较麻烦,不是开箱即用,安装的组件全选就行,免得后面出什么奇怪bug。安装完成之后需要手动创建Qt Creator的快捷方式,可以使用Everything.exe(一款高效检索工具)搜索qtcreator.exe,或者进入下面路径查找...\Qt5.14.2\Tools\QtCreator\bin\qtcreator.exe。安装相关链接放在文章末尾。


3、验证QT_Creator是否安装成功参考文末的参考文章,一个完整的上位机设计一般有UI设计、代码逻辑编写、上位机图标(可以没有)、程序打包这几个步骤。下面我们开始编写上位机,新建工程时工程名及工程路径不要有中文字符。

image.png

image.png

image.png

image.png

image.png

剩下三个按照默认配置就行。


4、项目生成后,我们的项目的没有配置套件,需要手动配置,如下图配置套件,默认是Debug构建。

image.png


5、进入工程下的Forms文件夹下的widget.ui即可开始UI设计,如下图是制作好的UI界面,先在左边把需要的组件拖到灰色框(程序显示的大小)内,并排列组件。

image.png


6、重命名组件(名字任意,清晰可读即可)。

image.png

增加打开关闭串口按钮,方法和上面类似

image.png


7、导入串口库和添加类

QT += core gui serialport

image.png

#include <QSerialPort>
#include <QSerialPortInfo>

image.png

QSerialPort *serialPort;

image.png


8、搜索串口,在构造函数中创建一个串口对象并搜索串口(这样导致必须先插入USB-TTL再打开上位机才能搜索到串口,也有一段时间刷新一次的,这里为了简便没有用自动刷新)

{
    QStringList serialNamePort;
    ui->setupUi(this);
    this->setWindowTitle("LED测试 By:LYL");

   /* 创建一个串口对象 */
   serialPort = new QSerialPort(this);

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

}

image.png


9、将打开串口,关闭串口,发送配置按钮分别转为槽,然后选择信号,进而在槽函数中编辑业务代码。

image.png

image.png



10、编写打开串口槽函数,功能是读取下拉框选择的参数配置,并初始化打开串口,如果打开成功货失败均弹窗提示。

void Widget::on_open_pushButton_clicked()
{
    /* 串口设置 */
    serialPort->setPortName(ui->COM_comboBox->currentText());
    serialPort->setBaudRate(ui->Baud_comboBox->currentText().toInt());
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setParity(QSerialPort::NoParity);

    /* 打开串口提示框 */
    if (true == serialPort->open(QIODevice::ReadWrite))
    {
        QMessageBox::information(this, "提示", "串口打开成功");
    }
    else
    {
        QMessageBox::critical(this, "提示", "串口打开失败");
    }
}

image.png

还需要在widget.h文件引入QMessageBox库

#include <QMessageBox>


11、编写关闭串口槽函数

void Widget::on_close_pushButton_clicked()
{
    serialPort->close();
    QMessageBox::information(this, "提示", "串口关闭");
}

image.png


12、编写串口数据收发读取显示函数,新建槽函数,注意.h文件中要声明。同时在构建函数中进行信号-槽连接用于对象间的通信,系统在串口收到数据时自动调用onSerialPortReadyRead函数来处理这些数据。

void onSerialPortReadyRead();

image.png

connect(serialPort, &QSerialPort::readyRead, this, &Widget::onSerialPortReadyRead);

image.png

void Widget::onSerialPortReadyRead()
{
    QThread::msleep(1);
    QByteArray data = serialPort->readAll();  // 读取所有可用数据
    ui->textBrowser->insertPlainText(QString("[接收] %1").arg(QString(data))+"\n");
}

image.png

由于引入了延时函数,因此在widget.h文件引入QMessageBox库

#include <QThread>


13、读取使能的LED,读取闪烁次数,读取闪烁频率,填充成一组一组的指令(没有使用空闲串口接收,因此使每次发送的指令的字符串数量都相等,方便下位机处理)。

void Widget::on_Send_Set_pushButton_clicked()
{
    if (!serialPort->isOpen()) {
        QMessageBox::warning(this, "提示", "串口未打开!");
        return;
    }

//获取RGB的选择
    QString RGB_Choose = ui->LED_EN_comboBox->currentText();
    QString aCmd;
    if (RGB_Choose == "R") aCmd = "A0001";
    else if (RGB_Choose == "G") aCmd = "A0002";
    else if (RGB_Choose == "B") aCmd = "A0003";

//获取翻转次数
    int TG_NUM = ui->TG_NUM_spinBox->value();
    QString bCmd = QString("B%1").arg(TG_NUM, 4, 10, QChar('0'));  // 补齐4位数字

//获取翻转频率
    int HZ_NUM_Str = ui->HZ_spinBox->value();
    QString cCmd = QString("C%1").arg(HZ_NUM_Str, 4, 10, QChar('0'));

    QStringList cmdList = { aCmd, bCmd, cCmd};

    for (const QString &cmd : cmdList) {
        serialPort->write(cmd.toUtf8());
        serialPort->waitForBytesWritten(100);
        ui->textBrowser->insertPlainText(QString("[发送] %1").arg(cmd)+"\n");
        QThread::msleep(1);
    }
}

image.png


14、界面高分屏适配(如果不加入适配,界面有概率会重叠缺失)

QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

image.png


15、导入图片(我这里是label标签导入,图片会比较模糊,鉴于教程性质,不涉及图片清晰度优化)

在工程处右键弹出菜单选ADD

image.png


16、图片移动到工程路径下并导入图片

image.png

image.png

image.png


17、编译运行后尝试回环测试,TX和RX短接,点击发送配置后,可以看到收发数据一致,基本验证了上位机软件功能。

image.png


18、现在这个项目只能在我们自己的电脑上运行,需要将项目打包成发布文件才能在其他终端上运行

image.png

切换发布版后点锤子编译,可以看到路径下出现了这个文件夹

image.png

进入build-Led_Test-Desktop_Qt_5_14_2_MinGW_32_bit-Release\release路径,有个.exe文件,如果直接运行会报错,缺少dll文件,我们需要使用命令行导入依赖文件

image.png

单独把exe文件复制粘贴到一个全英文路径的文件夹中,找到QT的打包工具。

image.png

cd进文件夹然后输入打包命令(根据需要更改程序名称)

windeployqt LED_Test.exe

image.png

image.png

对打包好的程序进行回环测试。

image.png


19、上位机编写至此结束。下位机编写省略,下位机就是一个串口接收数据然后解析,这里不重复写了,网上教程很多。


结束语:

记得及时保存项目......写教程还是挺累的,从开始学习QT到写出文章花了差不多10天,如果是总结性质或者随想性质可能几天完事,这个程序也没有通信校验应答这些步骤,发送失败也没有错误重传机制,只能说是一个功能测试初版Demo。

最近也是回学校搞完毕业答辩和毕业照了,和一位朋友交流过抓取招聘软件的职位信息进而提升职业技能的想法,搞是能搞的,但是否有意义?boss直聘反爬过于严格实在是绕不开,智联招聘就能绕开限制一晚上抓了上万条嵌入式软件相关数据,看着冰冷的数据一顿分析觉得还不如学自己想学的,市场需要的并不一定适合自己学。突然感觉搞技术终究是图一乐(hh),接下来一段时间优先学历史和方法论提升认知。


原始工程:

attachment iconLed_Test.zip412.08KBZIP0次下载

原始工程(Debug方式编译):

attachment iconbuild-Led_Test-Desktop_Qt_5_14_2_MinGW_32_bit-Debug.zip2.63MBZIP0次下载

原始工程(Release方式编译):

attachment iconbuild-Led_Test-Desktop_Qt_5_14_2_MinGW_32_bit-Release.zip1.38MBZIP0次下载

原始工程(打包好的exe,其实很多dll文件都没用到,本文的打包方式是不管有没有用的依赖都塞进去了):

attachment iconLED_Test.zip22.11MBZIP0次下载


QT官网:

XXXXXXXXXXXXXXXXXXXXXXXX

QT5.14.2(可能要科学上网):

如果是win系统,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

如果是其他系统,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

参考文章:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


ps:回复均有KCB

pps:来这写文章五年有余了,感谢KC论坛坛友对我的指导


[修改于 24天9时前 - 2025/05/23 16:39:22]

来自:电子信息 / 电子技术计算机科学 / 软件综合严肃内容:教程/课程
5
 
2
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
zjsx8192
24天0时前 IP:广东
944340

linux下的qt也能这样搞么


+1
科创币
全桥整流
2025-05-25
细节可能会不一样,我认为总体不会有大变化
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
Light_QuantaSeeker
15天8时前 IP:广东
944525

大佬牛逼,狠狠支持一波


+1
科创币
全桥整流
2025-06-02
支持
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
山雨欲来风满楼
15天2时前 IP:海南
944529

有意思,感觉比我手写qt方便很多……

但是不知道对逻辑细节的操控方不方便


+1
科创币
全桥整流
2025-06-02
支持
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
全桥整流作者
14天5时前 IP:中国
944558
引用山雨欲来风满楼发表于3楼的内容
有意思,感觉比我手写qt方便很多……但是不知道对逻辑细节的操控方不方便

这个qt界面虽然可以直接拖控件,但是也提供界面的底层代码供修改,逻辑细节应该是没区别的,都是c++,调库就行。


引用
评论
1
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
小叮当0312
5天11时前 IP:河南
944802

收藏了,非常有用!


引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

全桥整流
进士 学者 机友 笔友
文章
31
回复
290
学术分
1
2020/01/26注册,1天5时前活动

秋名山最速传说! 邮箱:331924204@XXXXXX

主体类型:个人
所属领域:无
认证方式:身份证号
IP归属地:广东
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的