手把手教你写一个串口调试助手
硬件攻城狮 2022-05-20 14:05 发表于广东
果果小师弟.
电子信息工程硕士在读,分享单片机、嵌入式linux、物联网等知识,致力于打造最硬核的嵌入式技术公众号。
摘要:前段时间发布了一个用QT写的串口调试助手,很多小伙伴在后台留言要源码。其实网上有很多免费开源好用的上位机,大家搜一下就能找到,为了大家方便学习QT以及如何写一个上位机,今天推荐一下学习资源,顺带带大家写一个非常简单的串口调试助手。
相信很多小伙伴还没有接触过QT,如果想用QT写一个调试助手,首先是会一点C++语法。了解即可,也就是看得懂C++的代码。只要能看懂简单的C+++语法,就能很快的写一个串口调试助手。
先推荐两个视频教程,感兴趣可以看看!
1、B站Jomse工
B站Jomse工
看完你基本知道串口调试助手大概是个啥样了,有了大致的了解然后再去看和修改别人的代码。
2、B站lililanglang
B站lililanglang
把这两个视频看完后,基本你就能够自己写一个串口调试助手了,视频很短没有废话,全程都是干货。而且别人也给出了源码。
为了大家方便理解,果子哥还是写一篇手把手教你学QT串口调试助手吧!
3、新建工程
1、首先你要安装QT的开发工具Qt Creator
。安装过程我这里就不在重复说了,大家可以看我的CSDN博客
号前面发的一些文章,有介绍的。
打开QtCreator
新建一个项目
项目名称根据需求自己指定即可,在指定项目的存储路径的时候, 路径中不能包含中文, 不能包含中文, 不能包含中文
直接写一步
Class name
可以随便写一个,一般默认不变
Base name
有QMainWindow
、QWidget
、QDialog
随便选一个即可
编译套件用于项目文件的编译, 如果安装了多个编译套件, 在这里选择其中一个就可以了
版本控制工具没有的话可以不选,主要用于团队开发,点击完成
这样我们就新建好了一个项目工程
双击ui文件即可进入设计模式,进入界面设计器Qt Designer
编辑状态,开始进行设计器( Qt Designer )编程。
在这个界面我们可以拖动左边的常用界面的空间到编辑窗口,然后生成可视化的界面。
样式1
样式2
可以看到通过拖动控件与修改控件属性就可以做出上面这样的界面,我个人觉得还是非常的美观nice的。这里只是给大家一个参考的界面和模板,排版和配色大家按照自己喜欢的就可以了!
一、导入库
1、在项目.pro文件中加入serialport
QT += core gui
QT += serialport
2、引入qt中串口通信需要的头文件
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
二、配置串口初始化
1、查找可用的串口。
通过创建一个comobox
,将可用串口的列表展示出来,并用于配置时选择要连接的串口
//查找可用串口,刷新串口信息
void MainWindow::GetAveriablePort()
{ui->uartReadPlain->insertPlainText("串口初始化:\r\n");//先清除所有串口列表ui->portBox->clear();foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){QSerialPort serial;serial.setPort(info);if(serial.open(QIODevice::ReadWrite)){ui->uartReadPlain->insertPlainText("可用:"+serial.portName()+"\r\n");ui->portBox->addItem(serial.portName());serial.close();}else{ui->uartReadPlain->insertPlainText("不可用:"+serial.portName()+"\r\n");}}
}
2、配置串口。
(1)串口的配置至少应当包含串口号、波特率、数据位、停止位、奇偶校验位、流控,这些都可以通过串口实例调用函数配置。可以加入几个comobox或者文本框来选择,也可以默认初始化时就配好。
//配置串口初始化
void MainWindow::PortConfigureInit()
{//填入串口选项ui->rateBox->addItem("115200","115200");ui->rateBox->addItem("38400","38400");ui->rateBox->addItem("19200","19200");ui->rateBox->addItem("9600","9600");ui->dataBox->addItem("8",8);ui->dataBox->addItem("7",7);ui->checkBox->addItem("无校验",0);ui->stopBox->addItem("1位",1);ui->stopBox->addItem("2位",2);
}
(2)加入一个打开关闭串口的按钮,文本显示“打开串口”时,点击可以关闭串口。文本显示“关闭串口“则相反。
(3)打开串口时,把配置的项的box都disable,使其不可修改,关闭时恢复
//串口开关按钮
void MainWindow::on_openSerialButton_clicked()
{//尝试打开串口if(ui->openSerialButton->text() == tr("打开串口")){if(ui->portBox->currentText() == "" ){QMessageBox::warning(NULL, "警告", "无可开启串口!\r\n\r\n");return;}serial = new QSerialPort;//设置串口名serial->setPortName(ui->portBox->currentText());//打开串口serial->open(QIODevice::ReadWrite);//设置波特率serial->setBaudRate(ui->rateBox->currentText().toInt());//设置数据位switch (ui->dataBox->currentData().toInt()){case 8:serial->setDataBits(QSerialPort::Data8);break;case 7:serial->setDataBits(QSerialPort::Data7);break;default:break;}//设置校验位switch (ui->checkBox->currentIndex()){case 0:serial->setParity(QSerialPort::NoParity);break;default:break;}//设置停止位switch(ui->stopBox->currentIndex()){case 0:serial->setStopBits(QSerialPort::OneStop);break;case 1:serial->setStopBits(QSerialPort::TwoStop);break;default:break;}//设置流控制serial->setFlowControl(QSerialPort::NoFlowControl); //设置为无流控制//关闭设置菜单使能ui->portBox->setEnabled(false);ui->dataBox->setEnabled(false);ui->checkBox->setEnabled(false);ui->stopBox->setEnabled(false);ui->rateBox->setEnabled(false);ui->openSerialButton->setText("关闭串口");fTimeCounter.restart(); //计时器重新计数//连接信号和槽函数,串口有数据可读时,调用ReadData()函数读取数据并处理。QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);}else{uartRecDataTimer->stop () ; //定时器停止if(serial->isOpen()) //原先串口打开,则关闭串口{serial->close();}//释放串口delete serial;serial = NULL;//恢复使能ui->portBox->setEnabled(true);ui->rateBox->setEnabled(true);ui->dataBox->setEnabled(true);ui->checkBox->setEnabled(true);ui->stopBox->setEnabled(true);ui->openSerialButton->setText("打开串口");}
}
三、读取串口数据
1、为了读取数据,要创建一个定时器和一个计时器。因为要解决2个问题,一是我们需要一个超时间隔,用于在串口一定时间收不到数据时,判断一次接收完成,处理数据并清空buff
。二是需要一个计数,统计串口已经连续接收了多久,即使数据一直不断,我们也要在一个固定时时间点强制判断一次接收完成,处理数据并清空buff,否则可能会导致数据永远得不到处理。
1、初始化定时器
//设置uart接收缓冲超时定时器uartRecDataTimer = new QTimer(this);uartRecDataTimer->stop();uartRecDataTimer->setInterval(uartRecOvertimeCount*1000); //设置定时周期,单位:毫秒uartRecDataTimer->setSingleShot(true); //设置为单次触发connect(uartRecDataTimer,SIGNAL(timeout()),this,SLOT(uartRec_timeout())); //设置槽
2、实现ReadData
在计时器超出一个指定间隔后,强制处理已经接收完的buff缓冲,其余时间则是把数据放进缓冲中,重启定时器
//读取串口接收消息
void MainWindow::ReadData()
{//串口可读数据长度int byteLen = serial->bytesAvailable();if(byteLen < 0){return;}rec_buf_len += byteLen;uart_rec_ss.append(serial->readAll()); //读取数据//计时器超过最大间隔仍未填入数据,强制填入if(fTimeCounter.elapsed() >2000 && uart_rec_ss.size()>0){ui->uartReadPlain->moveCursor(QTextCursor::End); //光标移动到结尾ui->uartReadPlain->insertPlainText(uart_rec_ss);ui->uartReadPlain->moveCursor(QTextCursor::End); //光标移动到结尾uart_rec_ss.clear();}//定时器开始工作、定时器重启uartRecDataTimer->start();
}
3、数据内容做填充
定时器接收完成处理(一段时间没有数据接收,定时器超时)根据时间戳是否被选择,将数据内容做填充,插入到存放数据的文本框里。
//定时器触发打印串口数据
void MainWindow::uartRec_timeout()
{if(!uart_rec_ss.isEmpty()){curDateTime = QDateTime::currentDateTime();ui->uartReadPlain->moveCursor(QTextCursor::End); //光标移动到结尾if(ui->timeZoneCheckBox->isChecked()){ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"R:");ui->uartReadPlain->moveCursor(QTextCursor::End); //光标移动到结尾ui->uartReadPlain->insertPlainText(uart_rec_ss);}else{ui->uartReadPlain->insertPlainText(uart_rec_ss);}ui->uartReadPlain->moveCursor(QTextCursor::End); //光标移动到结尾uart_rec_ss.clear();fTimeCounter.restart();ui->RXLenLabel->setText(QString::number(rec_buf_len)+"bytes");}
}
4、配置超时间隔的选项
(1)初始化时加入一个配置框
//设置时间输入框只允许使用数字
ui->overTimeRecEdit->setValidator(new QRegExpValidator(QRegExp("^([0-9]{1,4}(.[0-9]{1,3})?)$")));
ui->overTimeRecEdit->setText(QString::number(uartRecOvertimeCount));
(2)运行中配置超时间隔
//超时间隔设置
void MainWindow::on_overTimeRecEdit_returnPressed()
{if(ui->overTimeRecEdit->text().toFloat()>60){QMessageBox::warning(NULL,"警告","超时时间不要超过1分钟");ui->overTimeRecEdit->setText("0.1");return;}uartRecOvertimeCount = ui->overTimeRecEdit->text().toFloat();ui->uartReadPlain->insertPlainText("设置超时时间为:"+QString::number(uartRecOvertimeCount*1000)+"ms");uartRecDataTimer->setInterval(uartRecOvertimeCount*1000); //设置定时周期,单位:毫秒fTimeCounter.restart();uartRecDataTimer->start();
}
四、发送数据
简单的发送数据没有什么要额外配置的,调用write函数就可以了,可以根据自己的实际情况做一些配置或是校验处理。比如加回车换行什么的
//发送串口数据
void MainWindow::on_sendDataButton_clicked()
{//未打开串口则不准发送if(ui->openSerialButton->text() == "打开串口"){QMessageBox::warning(NULL, "警告", "未打开可用串口,无法发送数据!\r\n\r\n");return;} //获取发送的命令,并选择在结尾加上换行,AT的命令结尾必须有回车换行QString command = ui->uartWritePlain->toPlainText();if(ui->changeLineCheckBox->isChecked()){command += "\r\n";} if(ui->timeZoneCheckBox->isChecked()){curDateTime = QDateTime::currentDateTime();ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"SEND:"+command);} send_buf_len += command.length();ui->TXLenLabel->setText(QString::number(send_buf_len)+"bytes"); serial->write(command.toLatin1());
}
至此,一个最基本的串口调试工具就完成了,下面就是给它添加功能和优化了。你可以加入一些功能比如修改样式、保存数据等等。
开源代码
最后想说的是用QT写上位机的源码例程很多,初学者可以先借鉴别人的代码参考修改,按照自己的喜好以及编程风格进行排版和布局配色即可!
手把手教你写一个串口调试助手相关推荐
- 从零开始,教你写一个串口调试助手
摘要:相信很多小伙伴都没接触过QT,如果想用QT写一个调试助手,首先是要会一点C++语法.只要能看得懂C++的代码,就能很快的写一个串口调试助手. 下面先推荐两个视频教程,感兴趣的可以看一看! 1.B ...
- 手把手教你写一个中文聊天机器人
本文来自作者 赵英俊(Enjoy) 在 GitChat 上分享 「手把手教你写一个中文聊天机器人」,「阅读原文」查看交流实录. 「文末高能」 编辑 | 哈比 一.前言 发布这篇 Chat 的初衷是想和 ...
- 手把手教你写一个生成对抗网络
成对抗网络代码全解析, 详细代码解析(TensorFlow, numpy, matplotlib, scipy) 那么,什么是 GANs? 用 Ian Goodfellow 自己的话来说: " ...
- python k线合成_手把手教你写一个Python版的K线合成函数
手把手教你写一个Python版的K线合成函数 在编写.使用策略时,经常会使用一些不常用的K线周期数据.然而交易所.数据源又没有提供这些周期的数据.只能通过使用已有周期的数据进行合成.合成算法已经有一个 ...
- 手把手教你写一个spring IOC容器
本文分享自华为云社区<手把手教你写一个spring IOC容器>,原文作者:技术火炬手. spring框架的基础核心和起点毫无疑问就是IOC,IOC作为spring容器提供的核心技术,成功 ...
- 手把手教你写一个Matlab App(一)
对于传统工科的学生用的最多的编程软件应该就是matlab,其集成度高,计算能力强,容易上手,颇受大众青睐.今天挖的这个新坑,主要是分享用matlab app designer设计GUI界面的一些方法和 ...
- 后端思维篇:手把手教你写一个并行调用模板
前言 36个设计接口的锦囊中,也提到一个知识点:就是使用并行调用优化接口.所以接下来呢,就快马加鞭写第二篇:手把手教你写一个并行调用模板~ 一个串行调用的例子(App首页信息查询) Completio ...
- 从原理到实现丨手把手教你写一个线程池丨源码分析丨线程池内部组成及优化
人人都能学会的线程池 手写完整版 1. 线程池的使用场景 2. 线程池的内部组成 3. 线程池优化 [项目实战]从原理到实现丨手把手教你写一个线程池丨源码分析丨线程池内部组成及优化 内容包括:C/C+ ...
- 自己写了一个串口调试助手
五叶草串口调试助手(持续更新-) 最新版本v1.1.0.0 介绍 作为一个嵌入式开发者, 经常用到串口, 也经常因为串口调试助手而烦恼. 于是决定自己做一款串口调试助手. 修改日志 v1.1.0.0 ...
最新文章
- ectouch java_ectouch第七讲 之ECshop模板机制整理
- 开源应用架构之​Selenium WebDriver讲解
- UVALive 6508 Permutation Graphs
- GitHub+Vue自动化构建部署
- python3获取用户输入_python3.4控制用户输入与输出
- 有向无环图DAG 拓扑排序 代码解释
- el table 固定表头和首行_vue表格实现固定表头首列
- 透明加密系统设计及实现-绪论
- Solaris 图形化界面登陆的控制
- 【侯捷】C++内存管理机制
- android 谷歌输入法切换,ANDROID谷歌拼音 输入法肿么切换?
- [数据库系统]关系代数表达式的优化算法
- 一个项目从立项到终结
- 企业邮箱管理员在哪里找?域名邮箱如何管理?
- 常规放大电路和差分放大电路
- android如何查看分区信息,【Android】Android如何查看分区情况
- 计划评审方法和关键路线法【PERT/CPM、统筹方法】
- 新型基础测绘体系建设试点技术大纲-思维导图
- JAVA的MySQL字符串拼接_字符串的拼接-MYSQL
- 如何在32、64位Windows7下玩英雄无敌3