Part 0:基础知识

以下内容可能会对读者更好的理解Qt存在帮助,可以按需阅读。

Qt绘图基础知识:https://blog.csdn.net/gongdiwudu/article/details/125256206

Qt基本绘图对象:https://blog.csdn.net/qq_29331365/article/details/105691223

QtCharts简介:https://blog.csdn.net/qq21497936/article/details/106528645

创建一个QtCharts图表:https://blog.csdn.net/qq_43627907/article/details/124520432

 

Part 1:QtCharts基础功能开发

QtChartQt为开发者提供的一种功能强大的图标控件集,可以快速绘制折线图、柱状图、饼图等多种图形,其易于使用的特点为广大开发者所青睐,接下来我们将以此为基础为大家展示如何搭建QtCharts控件。

Step 1:新建QtCharts控件容器

在主界面创建一个Graphics View控件,并命名为OscView。此Graphics View控件不能直接作为QCharts的实现载体,故需要新建一个C++类。

Step 2:新建用于QtCharts的派生类

  • 在菜单栏打开“File->New File or Project
  • 左侧选择“C++”,右侧选择“C++ Class”,创建一个空白类

  • 点击“Choose”之后,输入类名“QChartView”,并选择基类为“QWidget”,注意更改存储路径为当前文件夹。

  • 按照默认设置,将新建立的类添加至当前工程,之后点击“Finish

Step 3:将步骤1中的OscView与步骤2中的QChartView类建立联系(提升)

  • 在界面设计页面右键OscView,选择“Promote to ...

  • 在弹出的窗口中,按照步骤2中所创建类的信息,为OscView执行“提升”

 

Step 4:为mainwindow.h加入头文件并引用QCharts命名空间

  • 添加头文件
#include <QtCharts>
  • 引用命名空间
using namespace QtCharts;
  • MainWindow的私有变量列表中添加趋势线和图标指针
QLineSeries* series;
QChart* chart;

 Step 5:为QCharts图表加入初始化代码,并简单配置

mainwindow.c的构造函数中加入如下代码:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    myserial = new QSerialPort();

    QObject::connect(myserial, &QSerialPort::readyRead, this, &MainWindow::on_SerialRecv);
    ui->comboBoxSpeed->setCurrentIndex(9);

    series = new QLineSeries();
    series->setName("Test Series");

    qreal SyncArray[]={0x53,0x59,0x4E,0x43,0x00,0xFF,0x00,0xFF};
    QList<QPointF> points;
    for(int i = 0; i < 8; i++)
        points.append(QPointF(i, SyncArray[i]));
    series->replace(points);

    chart = ui->OscView->chart();
    chart->addSeries(series);
    chart->createDefaultAxes();
    chart->setTitle("Test Chart");

    ui->OscView->setRenderHint(QPainter::Antialiasing);

}

此段代码的主要功能为:

        创建趋势线(Series

        为趋势线命名

        为趋势线添加点集

 

        获取OscView的绘图对象

        为绘图对象添加趋势线

        为绘图对象创建默认坐标轴

        为绘图对象设置标题

 

        开启OscView的抗锯齿模式

 

Step 6:编译运行,查看效果

前面的步骤为界面添加了一条趋势线,并将“同步序列”的数据点集添加进去,运行成功后会出现如下运行结果。

Tips:上述步骤实现的界面是“绝对位置”定位,在窗口大小变化时,界面中各个组件的大小不会改变,会出现很大的白边区域,接下来将简单介绍如何通过格栅布局实现控件大小动态改变。

  • 右键串口选择框,选择“Size Constricts->Set Minimum Size

  • 添加一个“Vertical Spacer

  • 选择界面布局为“格栅布局”

此后再拖动边沿时,界面上的各个组件尺寸就会跟随界面自动变化,使得界面上不会存在多余的空白区域。

 

Part 2:QtCharts示波器显示功能开发

前文中已经讲解过如何将STM32示波器的数据通过串口解包,也介绍过如何将数据添加至QtCharts中,本节将把二者结合,实现基础的示波功能。

mainwindow.c的串口接收函数中加入如下代码:

void MainWindow::on_SerialRecv(void)
{
    static QByteArray RecvBuff;
    if(myserial->isOpen())
    {
        QByteArray QBArecv =myserial->readAll();
        RecvBuff.append(QBArecv);
        char SyncArray[]={0x53,0x59,0x4E,0x43,0x00,0xFF,0x00,0xFF};
        QByteArray Sync=QByteArray(SyncArray,8);
        if(RecvBuff.indexOf(Sync)!=-1)
        {
            QByteArray Packed=RecvBuff.left(RecvBuff.indexOf(Sync)+8);
            RecvBuff=RecvBuff.mid(RecvBuff.indexOf(Sync)+8);

            QBArecv=Packed;
            QString Recv="";
            if(1)
            {
                QString Temp;
                int cnt=0;
                QList<QPointF> points;
                foreach(QChar dat,QBArecv)
                {
                    Recv+=Temp.sprintf("%02X ",(unsigned int)dat.unicode());
                    if(cnt<(QBArecv.length()-8))points.append(QPointF(cnt++,(unsigned int)dat.unicode()));
                }
                series->replace(points);
                chart->axisX()->setRange(0,cnt-1);
            }
            else Recv+=QString::fromLocal8Bit(QBArecv);
            qDebug()<<Recv;
            qDebug()<<"Lenth="<<Packed.length();
        }
    }
}

本段函数的主要功能是在原有串口数据包解析的基础上,针对数据包中的每一个字节,将之作为数据中的一个数据点显示在QtCharts中(符合现在定义的简单数据格式,后期会使用更为复杂的数据格式,目前先以此格式简单测试)。

编译运行后,效果如下图所示:

整体效果图如下图所示:

Part 3:STM32示波器上位机配置功能开发

STM32示波器支持如下格式的命令参数设置,可以用于修改示波器运行参数:

<命令集>:<命令>.参数;<\r\n>

目前支持的命令有:

system: SetTime.<时间参数>; <\r\n>
function: TrigLevel.<触发电平>; <\r\n>
function: SmitLevel.<施密特触发电平差值>; <\r\n>
function: SimpleRate.<采样率 >; <\r\n>
function: WindowLenth.<采样窗长>; <\r\n> 
function: OscSync.<同步模式>; <\r\n> 
function: OscMode.<运行模式>; <\r\n>

接下来将针对采样率和采样窗长的控制方式进行详细介绍,以点带面,展示指令发送过程。

Step 1:按照下图为示波器界面添加分组框和下拉框

Step 2:为两个下拉框分别设置可选参数

下拉框1comboBoxBuffer

参数:128256512102420484096

下拉框1comboBoxSampleRate

参数:5001k2.5k5k10k25k50k100k250k500k1M

Step 3:为采样窗长下拉框(上)链接槽函数

按照标准的槽函数添加步骤,为采样窗长下拉框添加槽函数,函数选择“currentIndexChanged(QString)”,此时可以通过在槽函数中将文本转换为数值直接发送给STM32

Step 4:编写槽函数

void MainWindow::on_comboBoxBuffer_currentIndexChanged(const QString &arg1)
{
     QString Tx;
     Tx.sprintf("function:WindowLenth.%d;\r\n", (int)arg1.toInt());
     if(myserial->isOpen())myserial->write(Tx.toLocal8Bit());
}

上述代码主要功能为:将下拉框中的文本转换为Int类型,然后格式化输出至Tx字符串,并通过串口发送给STM32示波器。

Step 5:为采样速度下拉框(下)链接槽函数

按照标准的槽函数添加步骤,为采样窗长下拉框添加槽函数,函数选择“currentIndexChanged(int)”,此时需要通过在槽函数中建立查找表才能选择合适的数据发送给STM32

Step 6:编写槽函数

void MainWindow::on_comboBoxSampleRate_currentIndexChanged(int index)
{
    int SampleMap[]={500,1000,2500,5000,10000,25000,50000,100000,250000,500000,1000000};
    QString Tx;
    Tx.sprintf("function:SimpleRate.%d;\r\n", SampleMap[index]);
    if(myserial->isOpen())myserial->write(Tx.toLocal8Bit());
} 

上述代码主要功能为:将下拉框的索引值通过查找表SampleMap转换为实际采样率,然后格式化输出至Tx字符串,并通过串口发送给STM32示波器。

Step 7:运行测试

点击界面左下角的绿色运行三角(无debug标志),即可编译生成工程查看效果。

Part 4:Qt示波器实机演示效果

此示波器的基础功能到此已经开发完毕,后续将会从触发、网络通信等方面进行完善,以下是将旭日X3派接上触摸屏后的运行效果:

可以直接触摸界面上的按钮、下拉框实现示波器配置,并可以从左侧大屏上观察到波形情况。

 Part 5:源码下载

本章节中提到的代码可以从如下链接下载:

链接:https://pan.baidu.com/s/1t4DzPNG56PBeH8chUSD-lA?pwd=Yuki  

提取码:Yuki