基于QT显示的示波器

说明:用单片机采集并发送波形数据给QT,在QT上显示波形

        通过 51 单片机与 Qt 应用程序进行串口通信,实现了单片机发送数据到 Qt 应用程序,Qt 应用程序则可以根据接收到的数据生成波形。

1.STC89C51单片机程序

        

        1.数据采集

使用ADC(模数转换器)或其他方法从硬件中读取电压值。

使用uart_init()函数配置串口通信参数,包括波特率、数据位、停止位等,确保与Qt应用程序设置相匹配。

void uart_init()//选择需要的配置
{
	SM0=0;		//设置串口工作模式为 8 位数据位,无校验位,1 位停止位
	SM1=1;	
	PCON=0; //SMOD=0
	TMOD=0X20;//定义定时器T1为方式2
	TH1=TL1=256-3;//设定波特率
	TR1=1;//启动T1
	
	REN=1;		//串口接收功能
}

        2.串口发送数据

使用string()函数发送数据。在本例中,通过串口发送JSON格式的数据,用于向Qt应用程序传递实时数据。

void string(unsigned char *p)//函数用于发送以空字符结尾的字符串
{

	while(*p!=0)
	{
			SBUF=*p;//将字符串中的每个字符发送到串口
			while(TI!=1);//等待发送完成
			TI=0;//清除标志位
		    p++;
	}
	
}

        3.串口接收和中断处理

通过设置串口接收中断函数uart(),实现对从Qt应用程序发送回来的控制指令的接收和处理。

void uart()interrupt 4//uart() 是串口中断处理函数,处理串口接收的数据
{
	if(RI==1)
	{
		temp=SBUF;
		ta_temp[i]=temp;//当接收到数据时,将数据存储在 ta_temp 数组中
		RI=0;
		i++;
		if(temp=='\n')//当接收到换行符 \n 时,将 flag_rx 置为 1,表示接收完成
		{
			flag_rx=1;
			i=0;
			temp=0;
		}
		RI=0;//清除接收中断标志位 RI
	}
}

主要功能

周期性数据发送:在主循环中,单片机周期性地向串口发送数据。这些数据可以是传感器采集到的实时数据,如温度、湿度等。

串口中断处理:当单片机接收到来自Qt应用程序的指令时,通过中断处理函数处理这些指令,以实现远程控制和反馈。

2.QT示波器程序

        示波器简介:在电子工程领域中,示波器是一种不可或缺的工具,它利用电子束在荧光屏上的位置变化来显示波形,帮助我们理解和分析电路的工作状态。而随着计算机技术的快速发展,基于QT的示波器显示技术正逐渐崭露头角,为我们带来了更为便捷和高效的解决方案。

        在基于QT的示波器显示中,波形的生成和显示是关键环节。示波器通过接收电路中的电压信号,将其转换为电子束的位置变化,从而在荧光屏上形成波形。QT框架提供了强大的绘图功能,使得示波器能够实时地将波形数据绘制在界面上。

    1.qcustomplot库

        我用的是qcustomplot库来生成ui界面的波形图

官方下载链接Qt Plotting Widget QCustomPlot - 简介icon-default.png?t=N7T8https://www.qcustomplot.com/index.php/introduction

我们需要在pro文件中加上这串代码,确保能够运行qcustomplot库

QT       += core gui serialport charts

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport

CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
    main.cpp \
    mainwindow.cpp \
    qcustomplot.cpp

HEADERS += \
    mainwindow.h \
    qcustomplot.h

下一步我们需要在头文件.h中添加跟串口相关的声明

private:
    Ui::MainWindow *ui;

    /*-------------function----------------*/
    void system_init();
    QStringList getPortNameList();

    /*-------------variable----------------*/
    // 串口声明
    QSerialPort global_port;
    // 状态栏声明
    QLabel *statusLabel;
    QLabel *msgLabel;

    // 串口相关
    QString receivedDdata = "";
    bool receivedFlag = false;
    bool OpenorClose_Flag = false;
    bool stop_flag = true;

    // 示波器相关
    bool oscill_flag = false;
    QVector <QString>   Ptext;  // 每条曲线上的显示的文字
    QVector <QVector<double>>   YData;  // Y轴数据,可具有多个数据曲线
    QVector <double>            XData;  // x轴数据
    double index = 0;                       // 索引
    QString frontData;
    QString backData;
    QString oneData;
    QStringList Received_Keys;  // 标签值
};

  2.与单片机进行串口通信

        在程序中,我们可以使用Qt的串口通信类来实现与单片机的通信,使用Qt的信号与槽机制来处理用户事件。

       

        1.初始化串口配置 :

        

目录

说明:用单片机采集并发送波形数据给QT,在QT上显示波形

        通过 51 单片机与 Qt 应用程序进行串口通信,实现了单片机发送数据到 Qt 应用程序,Qt 应用程序则可以根据接收到的数据生成波形。

1.STC89C51单片机程序

        1.数据采集:

        2.串口发送数据:

        3.串口接收和中断处理:

主要功能

2.QT示波器程序

    1.qcustomplot库

  2.与单片机进行串口通信

        1.初始化串口配置 :

        2.打开或关闭串口 :

        3.发送PID数据 :

        4.发送任意串口数据 :

        5.接收串口数据 :

3.显示波形


在 system_init 函数中,初始化了串口的配置参数,如无奇偶校验位、8位数据位、1位停止位和无流控制。并连接了串口的 readyRead() 信号到 receiveInfo() 槽,这样当串口接收到数据时,就会触发 receiveInfo() 函数来处理数据。

void MainWindow::system_init()
{
    // 这是statusbar的相关初始化
    QLabel *permanent = new QLabel(this);
    permanent->setFrameStyle(QFrame::Box | QFrame::Sunken);
    permanent->setTextFormat(Qt::RichText);
    permanent->setOpenExternalLinks(true);
    ui->statusbar->addPermanentWidget(permanent);
    statusLabel = new QLabel;
    statusLabel->setMinimumSize(150, 20); // 设置标签最小大小
    statusLabel->setFrameShape(QFrame::WinPanel); // 设置标签形状
    statusLabel->setFrameShadow(QFrame::Sunken); // 设置标签阴影
    ui->statusbar->addWidget(statusLabel);
    statusLabel->setStyleSheet("color: white");
    statusBar()->setStyleSheet("background-color : rgb(30,30,30)");

    //PID 控制初始值控制
    ui->lineEdit->setText(tr("0"));
    ui->lineEdit_2->setText(tr("0"));
    ui->lineEdit_3->setText(tr("0"));
    ui->lineEdit_4->setText(tr("0"));

    // 串口初始化配置
    global_port.setParity(QSerialPort::NoParity);  //无奇偶校验位
    global_port.setDataBits(QSerialPort::Data8);   //8位校验位
    global_port.setStopBits(QSerialPort::OneStop); //停止位为1
    global_port.setFlowControl(QSerialPort::NoFlowControl);   //无流控制
    connect(&global_port, SIGNAL(readyRead()), this, SLOT(receiveInfo()));

    // 示波器初始化配置
    ui->customPlot->setBackground(QBrush(QColor("#474848")));
}

        2.打开或关闭串口 :

         on_OpenorClose_clicked 槽函数用于打开或关闭串口。它首先检查 OpenorClose_Flag 变量来决定是打开还是关闭串口。如果打开串口,它会配置端口号和波特率,然后调用 open() 函数打开串口。

void MainWindow::on_OpenorClose_clicked()
{
    /*--------------------------------
     *  打开或者关闭串口
     *-------------------------------*/
    if (!this->OpenorClose_Flag)
    {
        // 打开串口
        ui->OpenorClose->setText("关闭串口");
        this->OpenorClose_Flag = true;



        QString portId;
        portId = ui->portId->currentText();
        qDebug() << "portIds: " << portId;
        global_port.setPortName(portId);  //配置端口号

        QString baudRate;
        baudRate = ui->baudRate->currentText();
        qDebug() << "baudRate: " << baudRate;
        global_port.setBaudRate(baudRate.toInt(), QSerialPort::AllDirections); //配置波特率

        // 配置完成,开启串口
        global_port.open(QIODevice::ReadWrite);
        qDebug() << "Open Serial Successfully";
    }else{
        // 关闭串口
        global_port.close();
        qDebug() << "Close Serial Successfully";
        ui->OpenorClose->setText("打开串口");
        this->OpenorClose_Flag = false;
    }
}

        3.发送PID数据 :

    on_sendPIDData_clicked 槽函数用于发送PID相关数据到串口。在发送前,它会检查串口是否打开,如果打开,则将PID数据(包括P、I、D和目标值)格式化为JSON对象,并转换为字节数组,然后通过 write() 函数发送到串口。

void MainWindow::on_sendPIDData_clicked()
{
    /*--------------------------------
     *  发送PID相关数据
     *-------------------------------*/
    if (global_port.isOpen()){
        QString P, I, D, targetVal;
        QJsonObject sendPIDData;

        P = ui->lineEdit->text();
        I = ui->lineEdit_2->text();
        D = ui->lineEdit_3->text();
        targetVal = ui->lineEdit_4->text();
        sendPIDData.insert("P", P.toFloat());
        sendPIDData.insert("I", I.toFloat());
        sendPIDData.insert("D", D.toFloat());
        sendPIDData.insert("Target", targetVal.toFloat());
        QJsonDocument document;
        document.setObject(sendPIDData);
        QByteArray pidbyte_array = document.toJson(QJsonDocument::Compact);
        QString pidjson_str(pidbyte_array);
        pidjson_str += '\n';
        qDebug() << QString::fromLocal8Bit("PID Data:") << pidjson_str;
        global_port.write(pidjson_str.toLocal8Bit());
    }else{
        QMessageBox box;
        box.setWindowTitle(tr("警告"));
        box.setWindowIcon(QIcon(":/Images/Icons/Alien 2.png"));
        box.setIcon(QMessageBox::Warning);
        box.setText(tr(" 未检测到串口,请确认串口是否打开?"));
        box.exec();
    }
}

        4.发送任意串口数据 :

   on_sendData_clicked 槽函数用于发送任意文本数据到串口。它读取 textEdit 控件中的文本,并发送到串口

void MainWindow::on_sendData_clicked()
{
    /*--------------------------------
     *  发送串口数据
     *-------------------------------*/
    if (global_port.isOpen()){
        QString sendData;

        sendData = ui->textEdit->toPlainText() + '\n';
        qDebug() << sendData;
        ui->textEdit->clear();
        global_port.write(sendData.toLocal8Bit());
    }else{
        QMessageBox box;
        box.setWindowTitle(tr("警告"));
        box.setWindowIcon(QIcon(":/Images/Icons/Alien 2.png"));
        box.setIcon(QMessageBox::Warning);
        box.setText(tr(" 未检测到串口,请确认串口是否打开?"));
        box.exec();
    }
}

        5.接收串口数据 :

   receiveInfo 函数用于处理从串口接收到的数据。它读取所有可用的数据,并检查是否包含完整的JSON对象。如果包含,它会调用 plotCustom 函数来处理这些数据(例如,更新示波器)。

void MainWindow::receiveInfo()
{
    /*--------------------------------
     *  接受串口信息
     *-------------------------------*/
    QString data;
    QByteArray info = global_port.readAll();
    QStringList list;

    if(!info.isEmpty())
    {
        if (info.contains('{'))
        {
            data = info;
            list= data.split("{");
            if (list.length() == 2){
                if (frontData.isEmpty()){
                    frontData = list.at(1);
                    frontData.insert(0,'{');
                    return;
                }
                oneData = frontData + list.at(0);
                frontData = list.at(1);
                frontData.insert(0,'{');
                plotCustom(oneData.toLocal8Bit());  //绘图
                qDebug() << "One data: " << oneData;
            }

            if (list.length() == 3){
                oneData = frontData + list.at(0);
                plotCustom(oneData.toLocal8Bit());          //绘图
                qDebug() << "One data: " << oneData;
                oneData = list.at(1);
                oneData.insert(0,'{');
                plotCustom(oneData.toLocal8Bit());  //绘图
                qDebug() << "One data: " << oneData;
                frontData = list.at(2);
                frontData.insert(0,'{');
            }
         }
    }
}

在以上代码中,global_port 是一个 QSerialPort 对象,它提供了与串口通信所需的所有功能。通过配置这个对象的参数,连接信号和槽,以及调用它的方法(如 open()write()readAll()),MainWindow 类实现了与单片机的串口通信。

需要注意的是,处理接收到的串口数据时,代码采用了字符串分割的方式来处理JSON数据的拼接,这可能不是最优的方式,尤其是当数据量较大或数据格式复杂时。在实际应用中,可能需要使用更健壮的JSON解析库来处理接收到的数据。此外,代码中的 frontData 和 oneData 变量用于处理跨多个 readyRead() 信号调用的数据拼接,这也是处理串口数据流时常见的做法。

3.显示波形

 最后我们单片机连接QT上位机显示波形

由于我这边单片机没有给按钮,所以单片机程序写的是固定的值

51单片机连接上位机,把程序下载到单片机,打开qt代码运行,通过电压直接就生成波形了

总结:一个完整的Qt应用程序,包含了串口通信、数据处理、示波器绘图以及用户界面交互等功能。每个函数或槽都负责一个特定的任务,并通过Qt的信号和槽机制进行通信。通过这种方式,应用程序能够响应用户的操作,读取串口数据,并在示波器上实时显示这些数据。

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 对于串口Qt示波器的源代码,以下是一个简单的示例: 首先,需要引入Qt的串口和图形库头文件: ``` #include <QSerialPort> #include <QSerialPortInfo> #include <QtCharts/QChartView> #include <QtCharts/QLineSeries> ``` 接下来,可以创建一个Qt窗口类,继承自QWidget,并将其设置为主窗口: ``` class MainWindow : public QWidget { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); private: QSerialPort *serialPort; QtCharts::QChartView *chartView; QtCharts::QLineSeries *series; private slots: void readData(); }; ``` 在构造函数中进行初始化设置,包括串口的初始化和示波器图形的初始化。 ``` MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { // 初始化串口 serialPort = new QSerialPort(this); serialPort->setPortName("COM1"); serialPort->setBaudRate(QSerialPort::Baud9600); serialPort->setDataBits(QSerialPort::Data8); serialPort->setParity(QSerialPort::NoParity); serialPort->setStopBits(QSerialPort::OneStop); serialPort->setFlowControl(QSerialPort::NoFlowControl); serialPort->open(QIODevice::ReadOnly); // 初始化示波器图形 chartView = new QtCharts::QChartView(this); chartView->setRenderHint(QPainter::Antialiasing); series = new QtCharts::QLineSeries(); chartView->chart()->addSeries(series); chartView->chart()->setTitle("Serial Port Oscilloscope"); chartView->chart()->createDefaultAxes(); chartView->chart()->axisX()->setTitleText("Time"); chartView->chart()->axisY()->setTitleText("Voltage"); chartView->chart()->legend()->setVisible(false); // 设置读取串口数据的槽函数 connect(serialPort, SIGNAL(readyRead()), this, SLOT(readData())); } ``` 最后,实现读取串口数据的槽函数,并对数据进行处理和更新图形: ``` void MainWindow::readData() { QByteArray data = serialPort->readAll(); // 根据串口数据进行处理,更新示波器图形 // ... // 示例:假设串口数据为一串实数,表示电压值 foreach (const auto &value, data.split(' ')) { qreal voltage = value.toDouble(); series->append(series->count(), voltage); } } ``` 以上是一个简单的串口Qt示波器的源代码示例,通过这段代码可以实现读取串口数据并在示波器图形上进行实时显示。 ### 回答2: 串口 Qt示波器源代码是一个使用Qt库编写的程序,它可以通过串口与设备进行通信,并且能够显示设备发送的数据以及将发送的数据通过串口发送给设备。 以下是一个简单的串口Qt示波器源代码的示例: ```cpp #include <QtSerialPort/QSerialPort> #include <QtSerialPort/QSerialPortInfo> #include <QApplication> #include <QWidget> #include <QVBoxLayout> #include <QLabel> #include <QChartView> #include <QSplineSeries> #include <QValueAxis> #include <QTimer> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建串口对象 QSerialPort serial; serial.setPortName("COM1"); // 设置串口名称 serial.setBaudRate(QSerialPort::Baud9600); // 设置波特率 serial.setDataBits(QSerialPort::Data8); // 设置数据位 serial.setParity(QSerialPort::NoParity); // 设置奇偶校验 serial.setStopBits(QSerialPort::OneStop); // 设置停止位 serial.setFlowControl(QSerialPort::NoFlowControl); // 设置流控制 // 创建示波器曲线 QSplineSeries *series = new QSplineSeries(); QChart *chart = new QChart(); chart->addSeries(series); chart->createDefaultAxes(); chart->axisX()->setRange(0, 100); // 设置X轴范围 chart->axisY()->setRange(0, 100); // 设置Y轴范围 // 创建示波器视图 QChartView *chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); // 创建主窗口布局 QVBoxLayout *layout = new QVBoxLayout(); layout->addWidget(chartView); // 创建主窗口 QWidget window; window.setLayout(layout); window.show(); // 创建定时器,定时更新示波器数据 QTimer timer; timer.setInterval(100); // 设置定时器间隔 QObject::connect(&timer, &QTimer::timeout, [&]() { // 从串口读取数据 if (serial.isOpen() && serial.isReadable()) { QByteArray data = serial.readAll(); // 处理数据,并显示示波器上 foreach(char value, data) { int val = static_cast<int>(value); // 将字节转换为整数值 series->append(series->count(), val); // 将数据添加到示波器曲线上 } } }); // 打开串口 if (serial.open(QIODevice::ReadOnly)) { // 启动定时器 timer.start(); // 运行应用程序 return app.exec(); } else { return -1; } } ``` 以上是一个简单的串口Qt示波器源代码示例,该程序可以打开指定的串口,读取串口数据,并将读取的数据显示示波器曲线上。使用者可以根据需要进行修改和扩展。 ### 回答3: 串口 Qt示波器源代码的实现可以通过以下步骤进行: 1. 首先,在Qt的项目中引入串口库和绘图库,可以使用Qt的串口和绘图模块,也可以使用第三方库,如QSerialPort和QtCharts。 2. 创建一个主窗口,可以使用Qt的MainWindow类来实现,该窗口用于显示示波器的界面和图形。 3. 在主窗口中添加一个串口设置界面,可以包括串口号、波特率和其他设置选项,以便用户可以选择需要连接的串口和相应的参数。 4. 创建一个串口对象,并在串口设置界面中设置相应的参数。使用Qt的QSerialPort类可以轻松地进行串口通信。 5. 在主窗口中添加一个绘图区域,用于绘制示波器的波形。可以使用Qt的绘图类来实现,如QPainter和QPen。 6. 在串口对象中设置数据接收槽函数,当串口接收到数据时,调用槽函数读取并解析数据,然后将数据传递给绘图区域进行绘制。可以使用Qt的信号与槽机制来实现数据的传递和处理。 7. 在主窗口的界面中添加一些控件,如开始按钮、停止按钮和清空按钮,以实现示波器的控制功能。 8. 在开始按钮的点击事件中,打开串口并开始接收数据;在停止按钮的点击事件中,关闭串口和停止接收数据;在清空按钮的点击事件中,清除绘图区域的波形。 9. 最后,运行程序,连接串口,启动示波器,并可以看到串口接收到的数据在绘图区域中实时绘制出来。 以上是一个基本的串口Qt示波器的源代码实现步骤,你可以根据需求和具体情况进行相应的修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值