QT串口显示多条曲线(可当作串口助手)

概要

      本人也是借鉴其他人的思路,并按照自己的想法加以改进。我采用的Qt环境是6.2.4MinGW 64-bit,需要事先安装好Qt Serial Port串口模块,Qt  Charts图表模块,

如果没有配置好,跟着下面的操作就行 

     在QT安装路径下找到MaintenanceTool.exe双击进去

 进入到这个界面

本人用的是qt6.2.4版本的,需要在6.2.4里找到Qt Serial Port和Qt Charst这两个模块,打勾后,就可以选择下一步了,然后等待更新完成后即可        (切记,版本的模块要对应版本的编译器)   

 安装完串口模块后就点击工程里的.pro文件    在里面添加QT  += serialport  和Qt   +=charts    然后点那个小锤子编译不运行,告诉编译器你要添加这个模块

环境配置好以后,先说一下思路,先写好串口的代码,然后在用QChart这个类,根据串口传来的数据来画图。

串口的基本属性有 端口号、波特率、停止位,校验位,流控(一般设置为无),用下拉框来选择串口的属性。

首先打开软件后,软件会先检测一下是否有串口设备接入,将接入设备的串口号显示在下拉框,定义一个字节数组来存放串口传过来的数据,并选择以文本还是16进制显示。

#include <QSerialPort>        //提供访问串口的功能
#include <QSerialPortInfo>    //提供系统中存在的串口的信息


//打开软件后,获取串口的端口号
 foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->comboBox->addItem(info.portName());    //保存在下拉框里
    }
//连接,接收串口的数据
 QObject::connect(&serial, &QSerialPort::readyRead, this,&MainWindow::serialPort_readyRead); 

//将串口的数据存放在字符数组里面
 QByteArray buffer = serial.readAll();

 //让数据以文本还是16进制显示
    if(ui->comboBox_6->currentText()=="文本模式")
    {
         recv = ui->textEdit->toPlainText();
           recv += QString(buffer);

         //清空以前的显示
         ui->textEdit->clear();
         //重新显示
         ui->textEdit->append(recv);
    }else
    {
         // 16进制显示,并转换为大写
         // 添加空格
         QString str2;  //转换成HEX的数据
         for(int i = 0; i<str1.length (); i+=2)
         {
            str2 += str1.mid (i,2);
            str2 += " ";
         }
         //清空以前的显示
         ui->textEdit->clear();
         //重新显示
         ui->textEdit->append(str2);
    }

 下面是配置串口属性的代码,根据下拉框配置串口属性

 if(ui->pushButton_4->text()==QString("打开串口"))
    {
        //设置串口名
        serial.setPortName(ui->comboBox->currentText());
        //设置波特率

        serial.setBaudRate(ui->comboBox_2->currentText().toInt());
        //设置数据位数
        switch(ui->comboBox_3->currentIndex())
        {
        case 5:serial.setDataBits(QSerialPort::Data5);break;

        case 6:serial.setDataBits(QSerialPort::Data6);break;

        case 7:serial.setDataBits(QSerialPort::Data7);break;

        case 8: serial.setDataBits(QSerialPort::Data8); break;
        default: break;
        }
        //设置奇偶校验
        QSerialPort::Parity checkBits;
        if(ui->comboBox_5->currentText()=="无")
        {
             checkBits=QSerialPort::NoParity;
        }else if(ui->comboBox_5->currentText()== "奇校验")
        {
             checkBits=QSerialPort::OddParity;
        }else {
            checkBits=QSerialPort::EvenParity;
        }
        serial.setParity(checkBits);

        //设置停止位
        switch(ui->comboBox_4->currentIndex())
        {
        case 1: serial.setStopBits(QSerialPort::OneStop); break;

        case 2: serial.setStopBits(QSerialPort::TwoStop); break;
        default: serial.setStopBits(QSerialPort::OneAndHalfStop);break;
        }
        //设置流控制
        serial.setFlowControl(QSerialPort::NoFlowControl);
        //打开串口
        if(!serial.open(QIODevice::ReadWrite))
        {
            QMessageBox::about(NULL,"提示","无法打开串口!");
            return;
        }
        //下拉菜单控件失能
        ui->comboBox->setEnabled(true);
        ui->comboBox_2->setEnabled(false);
        ui->comboBox_3->setEnabled(false);
        ui->comboBox_4->setEnabled(false);
        ui->comboBox_5->setEnabled(false);
        ui->pushButton_4->setText(QString("关闭串口"));
        ui->pushButton_2->setEnabled(true);
        //发送按键使能
        ui->pushButton_2->setEnabled(true);
    }
    else
    {
        //关闭串口
        serial.close();
        //下拉菜单控件使能
        ui->comboBox->setEnabled(true);
        ui->comboBox_2->setEnabled(true);
        ui->comboBox_3->setEnabled(true);
        ui->comboBox_4->setEnabled(true);
        ui->comboBox_5->setEnabled(true);
        ui->pushButton_4->setText(QString("打开串口"));
        //发送按键失能
        ui->pushButton_2->setEnabled(false);
    }

 串口发送代码 (可以选择是文本数据发送还是字节数据发送)

//发送数据
void MainWindow::on_pushButton_3_clicked()
{
    QByteArray data;
    if(ui->comboBox_8->currentText()=="文本模式"){
        //array = QString2Hex(data);  //HEX 16进制
          data = ui->textEdit_2->toPlainText().toUtf8();
    }else{
        //array = data.toLatin1();    //ASCII
         data = ui->textEdit_2->toPlainText().toLocal8Bit();
    }

    //获取界面上的数据并转换成utf8格式的字节流
 //   QByteArray data = ui->textEdit_2->toPlainText().toUtf8();
  //  QByteArray data = ui->textEdit_2->toPlainText().;
 }

这样就差不多了,就串口发送数据,接收数据,串口配置,数据显示就完了。

串口配置好以后,就来配置曲线显示  有以下配置:先配置曲线对象,然后Charts绑定曲线,(我个人的理解是Charts相当于一个容器,我们要把曲线给添加进去),然后给配置容器配置,有无网格、多少个间隔,范围。

#include <QScatterSeries>              //画点状曲线头文件
#include <QtCharts/QLineSeries>        //画线曲线头文件
#include <QtCharts/QValueAxis>         //画坐标轴头文件
#include <QtCharts/QChartView>         //画绘图区域头文件
#include <QtCore/QTimer>               //时间定时器头文件
#include <QtWidgets/QGesture>          //手势头文件(鼠标动作)
#include <QtWidgets/QGraphicsScene>    //绘图屏幕参数头文件
#include <QtCharts> 

 //创建曲线对象
 QLineSeries *serices0;    //曲线一
 QLineSeries *serices1;    //曲线二
 QLineSeries *serices2;    //曲线三

 qint32  X_Rang;           //X轴的范围
 qint32  Y_Rang;           //Y轴的范围
 double fenbianlv;         //X轴的分辨率

ui->ChartView->setChart(chart);
    QMargins mgs(1,1,1,1);
    chart->setMargins(mgs);

    //创建折线序列
    serices0->setName("曲线一");
    serices1->setName("曲线二");
    serices2->setName("曲线三");
    chart->addSeries(serices0);
    chart->addSeries(serices1);
    chart->addSeries(serices2);

    //创建坐标轴
    axisX->setRange(0,5);                //设置X轴的范围
    axisX->setTitleText("time(secs)");   //X轴的标签
    axisX->setTickCount(20);             //设置20个间隔
    axisX->setMinorTickCount(5);         //设置每个间隔里有多少个网格
    axisY->setRange(-100,100);           //设置y的范围
    axisY->setTitleText("Value");        //设置标题
    axisY->setTickCount(7);             
    axisY->setMinorTickCount(4);         //设置每个间隔里有多少个网格
    
    //绑定X,Y轴的数据
    //曲线一
    chart->setAxisX(axisX,serices0);  
    chart->setAxisY(axisY,serices0);
    //曲线二
    chart->setAxisX(axisX,serices1);
    chart->setAxisY(axisY,serices1);
    //曲线三
    chart->setAxisX(axisX,serices2);
    chart->setAxisY(axisY,serices2);

设置曲线的x轴,y轴的数据。x轴我们设置成时间,y轴可以设置成串口接收的数据。代码如下

 一般我们把x轴设置成时间,y轴数据随着x轴时间变化而变化,下面这两句是时间以多少步长增长
 fenbianlv=ui->doubleSpinBox->value();
  t +=  fenbianlv;

//下面是一条曲线的配置
要想让曲线有流动的效果,x的范围随着x轴时间的增加而增加。y轴的范围增加而增加
 if(ui->quxian1->isChecked()==true)
    {
         //serices0->show();
         serices0->show();
         if(t>X_Rang)
             //  axisX->setRange(t-2,t+0.5);
            axisX->setRange(t-X_Rang,t+(0.5+X_Rang/10));
         if(listvalue.size()<=50)
            listvalue.push_front(value);
         else
         {
            listvalue.pop_back();
            listvalue.push_front(value);
         }
         qreal minvalue = *std::min_element(listvalue.begin(),listvalue.end());
         qreal maxvalue = *std::max_element(listvalue.begin(),listvalue.end());
         axisY->setRange(minvalue-Y_Rang,maxvalue+Y_Rang);
    }

下面是对串口接收的数据经行差分,因为要想实现多条曲线的显示,数据是 一帧一帧的,我们要从一帧一帧的数据里拆分,我是用@来区分数据的,只需要让串口传过来的数据是以@data1@data2@data3     分别拆分@后面的数据

   
  
   receiveBytes += receiveBuff.length();     //计算接收到的字节长度
   //曲线显示
   //前面我们已经把串口接收的数据存入Buff里,接下我们数据经行处理

   //该条语句的意思是如果遇见第一个@,就将它后面的数据存放在quxian1里面
   quxian1=QString(buffer).section("@",1,1).toDouble();     

   //该条语句的意思是如果遇见第二个@,就将它后面的数据存放在quxian2里面
   quxian2= QString(buffer).section("@",2,2).toDouble();

   //该条语句的意思是如果遇见第一个@,就将它后面的数据存放在quxian1里面
   quxian3= QString(buffer).section("@",3,3).toDouble();

   qreal value = quxian1;
   qreal value1 = quxian2;
   qreal value2 = quxian3;
   X_Rang=ui->X_Rang->value();    
   Y_Rang=ui->Y_Rang->value();
   serices0->append(t,value);       //将接收的数据追加到曲线的
   serices1->append(t,value1);      // append( , );  第一个填的是x轴的数据,第二个填y轴的数据
   serices2->append(t,value2);

本文只讲解了部分代码,需要完整工程的,可以私信我。           

算了,反正没人看表情🤡

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值