一.前言

  • 闲了好久没更新博客,偷懒的我就拿了去年暑假备战电赛时做的一个串口版“示波器”来充充水。抛砖引玉哈。
  • 因为以前发过一篇主题一样的文章,所以就当该文就相当于上版的升级版(其实两者没啥关系,仅是主题一样,以前那篇是单纯为赛题弄的,这篇更有通用性)
  • 是当时为电赛准备的(吐槽一下,原本我组准备的电源题,怎么想着也会用上adc、pwm啥的吧,结果19年的A题一出来真是让我一言难尽啊)
  • 实现的功能有:自定义数据格式,多个数据图线显示,自动和手动两种模式,显示鼠标当前的位置
  • 因为时间有点久,很多注释没写到还请谅解。

二.效果介绍

  • 因为一直宅在家,又没带板子回来,所以就只能看看界面了,红色字体为说明

三.软件思路介绍

  1. 大概思路,串口接收数据,然后按照自定义格式解析数据,最后绘画波形图,因为总代码有点多,就不全贴出来,有空我上传到github上去,也可以评论发邮箱号我来发给你
  2. 这里用到到绘画波形图的库是qcustomplot,不清楚的可以百度一下,它的官网介绍得挺详细的。
  3. 先是定义一个Handle类里有串口的自动检测,即如果检测有串口出现会自动加到串口端口的栏中,和串口数据的接收、数据解析和曲线图的绘画(放在一个线程里执行,防止界面显示卡死)代码如下,先是头文件:
#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include "qcustomplot.h"
#include <QVector>
#define MAX_COUNT       1500            // x轴可显示的最大范围
#define cout qDebug() << __LINE__ << ":"
class Handle : public QObject
{Q_OBJECT
public:explicit Handle(QCustomPlot *P,QObject *parent = nullptr);
signals:void finish();                      // 数据解析完成时发出信号
public slots:void getValidPort(QComboBox* p);    // 获取有效串口端口void getText(QString t);void analyData();                   // 解析数据void setFlag(QString b = "[",QString m=",",QString e="]"){begin = b;mid = m; end = e;}                                   // 自定义数据格式,分隔符void clear();                      // 数据清空void setAuto(bool e){                // 是否设置为自动模式isAuto = e;}void setRun(bool e){               // 是否设置为运行isRun = e;}void setOpen(bool e){             // 是否打开串口isPortOpen = e;}bool getOpen(){return isPortOpen;}    // 获取串口打开状态bool getRun(){return isRun;}     // 获取串口是否在运行bool getAuto(){return isAuto;}      // 获取是否为自动模式
private:QString begin,mid,end;              // 自定义数据格式QString text;bool isPortOpen;                    // 标识串口端口是否打开QStringList list;QCustomPlot *Plot;                  // 图层QVector <QCPItemTracer *>   trace;  // 曲线上的跟随点QVector <QCPItemText *  >   Ptext;  // 每条曲线上的显示的文字QVector <QVector<double>>   YData;  // Y轴数据,可具有多个数据曲线QVector <double>            XData;  // x轴数据QVector<QPen>               pen;    // 曲线颜色的区分int Clk,xMid;                       // x轴的刻度int countLine;                      // 曲线的数量int firstLine;bool isAuto,isRun;                  // 标识是否自动,是否在运行
};
  1. 再贴点串口数据解析函数的代码
/** 串口数据的解析*/
void Handle::analyData()
{// 进行数据提取,比如begin="[",mid=",",end="]",串口数据为,30][10,20,30][...// int _end = text.indexOf(begin);text.remove(0,_end+1);        // 移除前面多余的数据,比如移除,30][,还剩10,20,30][...if( _end < 0 || !isRun){return ;}// 将数据分段,比如分出10,20,30]和下一段[...QStringList _be = text.split(begin,QString::SkipEmptyParts);for(auto _b:_be){int _e = _b.indexOf(end);   // 找出数据段里的]的位置if(_e > 0){QStringList _list = _b.left(_e).split(mid,QString::SkipEmptyParts);    // 将数据10,20,30中的各个数据分离出来countLine = 0;         // 统计一段数据里的数据个数for(auto i:list){        // 分离出的数据放入各个曲线数据里YData[countLine].push_back(i.toDouble());if(YData[countLine].count() >= MAX_COUNT){YData[countLine].pop_front();}countLine ++;}XData.push_back(Clk++);if(XData.count() >= MAX_COUNT){XData.pop_front();}for(int _i = firstLine; _i < countLine && _i < 6; _i ++){firstLine = countLine;Plot->addGraph();Plot->graph(_i)->setPen(pen.at(_i));   // 给数据曲线上色Plot->graph(_i)->setVisible(true);      // 曲线显示trace[_i] = new QCPItemTracer(Plot);    // 生成一个跟随点trace[_i]->setPen(pen.at(_i));         // 设置点的颜色trace[_i]->setSize(10);                 // 设置点的大小trace[_i]->setBrush(QBrush(pen.at(_i).color()));trace[_i]->setGraph(Plot->graph(_i)); // 设置在该曲线显示trace[_i]->setStyle(QCPItemTracer::tsCircle); // 圆形点trace[_i]->setInterpolating(true);Ptext[_i] = new QCPItemText(Plot);  // 跟随点的文本信息Ptext[_i]->setPen(pen.at(_i));Ptext[_i]->setText(QString("Graph:%1").arg(_i));Ptext[_i]->setRotation(4);Ptext[_i]->setTextAlignment(Qt::AlignRight | Qt::AlignBottom|Qt::AlignJustify);Ptext[_i]->setPositionAlignment(Qt::AlignRight | Qt::AlignBottom|Qt::AlignJustify);Ptext[_i]->position->setType(QCPItemPosition::ptPlotCoords);Ptext[_i]->setFont(QFont("Helvetica [Cronyx]", 12));Ptext[_i]->setPadding(QMargins(8, 0, 0, 0));YData[_i].resize(MAX_COUNT);}for(int _i = 0; _i < countLine; _i ++){Plot->graph(_i)->setData(XData,YData[_i]);if(Clk <= xMid){Plot->xAxis->setRange(0,Clk);}else{Plot->xAxis->setRange(Clk-xMid,Clk);}Ptext[_i]->position->setCoords(Clk,YData[_i].last());   // 文本显示的位置Ptext[_i]->setText(QString("%1:(%2,%3)").arg(_i+1).arg(Clk).arg(YData[_i].last())); // 文本内容trace[_i]->setGraphKey(Clk);          // 跟随点的位置if(isAuto){                                // 是否自动适配缩放Plot->yAxis->rescale(true);}}}}Plot->replot();              // 图层更新if(text.length() > 200){  // 判断串口接收数据是否过多,过多久丢弃text.clear();}emit finish();
}
  1. 然后在widget类中,这里比较简单,开了个线程给Handle类,然后绑定各种信号与槽,先上头文件:
#ifndef WIDGET_H
#define WIDGET_H#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QWidget>
#include <QDebug>
#include <QMessageBox>
#include "qcustomplot.h"
#include <QVector>
#include <QTimer>
#include <QPen>
#include <QMouseEvent>
#include <QToolTip>
#include "handle.h"
#include <QThread>
namespace Ui {class Widget;
}
class Widget : public QWidget
{Q_OBJECT
public:explicit Widget(QWidget *parent = nullptr);~Widget();void goClear();                // 清除void autoHandle();         // 没用上
signals:void analy(QString t);      void clearT();void getValidP(QComboBox* p);void startA();
private slots:void on_pushOpen_clicked();void on_pushClear_clicked();void on_pushRun_clicked();void on_pushAuto_clicked();
private:Ui::Widget *ui;Handle *hand;QCustomPlot *Plot;QSerialPort *SerialPort;QThread *thread;
};
#endif // WIDGET_H
  1. widget类构造函数里的各种信号与槽的绑定
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);SerialPort = new QSerialPort(this);Plot = ui->widget;Plot->setMouseTracking(true);    // 使能图层鼠标跟随// 开启图层上的图层刻度可手动调动Plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);connect(Plot->xAxis, SIGNAL(rangeChanged(QCPRange)), Plot->xAxis2, SLOT(setRange(QCPRange)));connect(Plot->yAxis, SIGNAL(rangeChanged(QCPRange)), Plot->yAxis2, SLOT(setRange(QCPRange)));connect(Plot,&QCustomPlot::mouseMove,[=](QMouseEvent *e){double _x = Plot->xAxis->pixelToCoord(e->x()),_y = Plot->yAxis->pixelToCoord(e->y());ui->labelWhere->setText(QString("(%1,%2)").arg(_x).arg(_y));});connect(Plot,&QCustomPlot::plottableClick,[=](QCPAbstractPlottable * plottable,int ,QMouseEvent * ){ui->labelGraph->setText(plottable->name());});ui->tabWidget->setTabText(0,"Gui");ui->tabWidget->setTabText(1,"Data");hand = new Handle(Plot);thread = new QThread(this);hand->moveToThread(thread);// 获取自定义数据hand->setFlag(ui->lineEditBegin->text(),ui->lineEditMid->text(),ui->lineEditEnd->text());// 绑定清除按键的响应connect(this,&Widget::clearT,hand,&Handle::clear,Qt::QueuedConnection);// 有串口信息时,将数据给Handle类处理connect(this,&Widget::analy,hand,&Handle::getText,Qt::QueuedConnection);// 绑定获取有效串口端口信息    connect(this,&Widget::getValidP,hand,&Handle::getValidPort,Qt::QueuedConnection);// 这个也没用上,还请注意    connect(hand,&Handle::finish,this,&Widget::autoHandle,Qt::QueuedConnection);connect(SerialPort,&QSerialPort::readyRead,[=](){emit analy(SerialPort->readAll());});connect(SerialPort,&QSerialPort::errorOccurred,[=](QSerialPort::SerialPortError e){cout << "error";if(e == QSerialPort::DeviceNotFoundError){SerialPort->close();hand->setOpen(false);on_pushClear_clicked();}});thread->start();       // 开启线程goClear();
}

四.完结

注:这个程序有个小问题,就是当窗口全屏时,就会发生数据丢失加剧的现象。当时的我本想试着再加一个线程来专门处理曲线绘画的,后来发现数据丢失的现象更严重,就没加那个线程了。数据丢失是由下位机发信息太过于频繁,比如频率大于1000HZ时,频率降低可解决。

Qt5-实现串口助手版“示波器”相关推荐

  1. 基于Qt5 的串口助手开发

    目录 前言 一.最终效果图 二.操作方法 1.创建一个新的Widgets Appliaction工程 2.用Qt Designer 设计上位机的界面 3.代码部分 1.mainwindow.h文件内容 ...

  2. H7-TOOL迎来新版固件V2.09,WiFi压缩图传,FDCAN/Modbus助手波形打印上线,完善串口助手/RTT/Lua小程序,脱机烧增加新型号

    目录 H7-TOOL所有资源汇总(含操作手册): PC机软件:升级PC软件到V2.0.9 更新说明: 1.升级新版注意事项 2.脱机烧录 (1)升级STM32G0xx系列,增加STM32G050, S ...

  3. Qt5学习笔记之串口助手四:增加16进制/ASCII切换、周期发送

    目录 1. 概述 2. 16进制/ASCII发送 2.1 功能实现 2.2 界面修改 3. 接收框显示发送内容 3.1 以16进制/ASCII显示 3.1.1 界面修改 3.1.2 功能实现 3.2 ...

  4. Qt5学习笔记之串口助手三:打包成Windows软件

    这里写目录标题 添加图标 打包程序 测试打包好的软件 添加图标 图标的获取可以参考我的另一篇文章:Qt5学习笔记之图标下载和转换,这里只记录下Qt中使用图标的方法. 1.切换到release模式下进行 ...

  5. 【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程

    这章来学习串口数据流操作.仿照已有成品制作一个用Qt开发的串口调试助手. 介于篇幅有限,本篇只介绍一个最简单的能收发的串口调试助手的制作.后续篇幅会陆续对剩余代码进行讲解,并添加各种功能,对显示.操作 ...

  6. Qt5学习笔记之串口助手一:基本界面设计

    这里写目录标题 概述 界面基本元素 添加串口参数 添加串口号 概述 从这一篇文章开始,跟着视频实现一个串口助手.当然,这里实现的串口功能比较简单,只有最基础的串口参数设置.发送.接收.在之后的拓展学习 ...

  7. PB12.5版串口助手

    参考了别人的串口通讯程序加上自己的理解完成了串口通讯程序,已经是非常完美,涉及了多线程和系统API和对象调用. 经过测试已经到达市面上串口助手的功能,PB还是可很牛逼.

  8. c++实现sscom串口助手循环发送_串口通讯你真的会了吗?不妨看看这些经验

    点击上方「嵌入式大杂烩」,选择「置顶公众号」第一时间查看编程笔记! 平时使用串口打印出现乱码的绝大部分原因是串口波特率没对.那么我们怎么测量实际的波特率呢?在这之前,顺便一起回顾一下波特率的概念. 什 ...

  9. 通过编写串口助手工具学习MFC过程——(三)Unicode字符集的宽字符和多字节字符转换...

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

最新文章

  1. ffmpeg 常用命令
  2. javascript--arguments callee caller
  3. Visual Studio中的TabControl控件的用法
  4. chrome使用 postwoman_Postman的情敌,Postwoman了解一下
  5. 机房配电系统与配电电缆线径的选择及巡查
  6. python3 asyncio 爬虫_python3 asyncio异步新浪微博爬虫WeiboSpider
  7. LPTSTR、LPCSTR、LPCTSTR、LPSTR的意义
  8. Java实验8 T1.编程包含一个标签和一个按钮,在“你好”和“再见”之间切换
  9. 非平衡电桥电阻计算_双臂电桥(QJ44)的功能介绍与使用
  10. 大数据用kettle还是python_Kettle学习系列之Kettle能做什么?(三)
  11. java重命名文件(附道客巴巴文档下载方法)
  12. 龙芯CPU芯片介绍说明
  13. 张家界3天旅游攻略(带你的想象给我游玩一遍)
  14. 《从零开始的 RPG 游戏制作教程》第十五期:地图发布,以及再见
  15. 联想第二季度业绩创纪录 所有业务实现强劲增长
  16. FastQC软件下载
  17. 【uniapp基础篇】上传图片
  18. SSE和WebSocket的用法和比较
  19. hashmap底层源码详解
  20. msvcp110.dll丢失修复,哪种修复方法效率高?

热门文章

  1. 记录一次:com.badlogic.gdx.utils.GdxRuntimeException: Error loading audio file: startAni.mp3
  2. AI智能识别技术如何助力校园智慧食堂建设、保障餐饮卫生安全?
  3. GOOGLE的强大功能(转载)
  4. 如何设计稳定性横跨全球的 Cron 服务
  5. 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】
  6. cmd执行命令行程序时有时会卡住
  7. 24 款必备的 Linux 桌面应用(2016 版)
  8. 4、SaaS、PaaS、IaaS
  9. 洛阳台达服务器维修,fanuc洛阳数控机床维修中心主轴放大器报警故障
  10. 2021-09-29