【Qt学习笔记】(三)--编写上位机软件(ui设置、样式表serialport串口接收数据、Qchart显示波形)

   声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。
   这段时间大部分都是在学Qt,前面想着跟着书一章章的学,但是发现这个效率极低,所以就改变了学习的方法,那就是:根据我需要的功能,直接用Qt去做,一边做一边学,于是这篇博客就这样写出来了…

往期回顾:

【Qt学习笔记】(一)–Qt creator软件学习
【Qt学习笔记】(二)–第一个程序“Hello World”(学习Qt中程序的运行、发布、编译过程)

一、需求描述

  首先给大家上个目前的效果图(后面还会继续针对这个上位机继续该专栏博客):
在这里插入图片描述

1.1 基础功能

   ① 串口接收数据(使用简单的通信协议);
  ② 保存数据至excel表格;
  ③ 实时显示传感器以及解算的姿态角度;
  ④ 实时显示数据波形图(可以选择要显示的数据);
  ⑤ 实时对传感器数据进行校准并可以利用3D图形显示出来;
  ⑥ 可以使用Allan方差(或者动态Allan方法)对加速度计或陀螺仪进行误差分析;
  ⑦ 可以使用某些算法(自适应扩展卡尔曼滤波、互补滤波、互相关检测等)对传感器的数据进行处理并进行姿态结算;
  目前已经实现的功能为①、③、④,其他功能会在后面逐步实现。
  下面会直接通过代码的分析对已经实现的功能进行分析。

二、Ui文件的设置

2.1 自适应显示器分辨率

  之前在做的时候,一直想着可以让窗口自适应显示器的分辨率,但是总是做不出来,最后通过这几天的摸索,终于知道如何去做了,下面整理一下方法:
  首先,一定要利用好水平布局和垂直布局,当然还有格子布局,不过我个人还是比较习惯常用水平和垂直布局,那么接下来一起看看上面上位机的布局如何:
  首先是centerwidget设置为垂直布局,它包含下面两个部分:
在这里插入图片描述
  然后再把①部分继续细分布局下去,它里面是一个垂直布局,在垂直布局里放置三个Group Box:
在这里插入图片描述
  然后呢,继续细分,把①和③再细说一下,②就是放一个垂直布局,再在垂直布局里放四个按钮即可。
  好了,说回①:它是一个垂直布局,在垂直布局里按顺序放置一个水平布局(串口号+Comb Box)+按钮(搜索串口)+水平布局(波特率、停止位等)+按钮(打开串口):
在这里插入图片描述
  再回到前面的③,它其实是一个水平布局,在水平布局里面放置两个垂直布局,再在每个垂直布局各放置12个label:
在这里插入图片描述
  这些看似麻烦,其实熟练了感觉就像剥洋葱一样,一层层的剥开就会发现这很简单…
  其实最重要的还是MainWindow的设置:
在这里插入图片描述
  同时还要右键MainWindow,选择“布局”中的一个布局方式,我个人常用水平或者垂直(两个都一样,因为它里面只有一个组件):
在这里插入图片描述

2.2 添加Chart

  这个其实就是Graphic View,把它拖进去之后,右键它,选择“提升为”QChartview:
在这里插入图片描述
  下面是代码部分:首先在.pro文件添加下面一行代码:

QT += charts

// 下面三个新建的class要放在.h文件的public部分QChart *chart = new QChart();QValueAxis *axisX = new QValueAxis;QValueAxis *axisY = new QValueAxis;//创建图表的各个部件chart->setTitle("数据波形显示");// MainWindow::uiui->serialCurveChart->setChart(chart);ui->serialCurveChart->setRenderHint(QPainter::Antialiasing);QLineSeries *series0 = new QLineSeries ();QLineSeries *series1 = new QLineSeries ();QLineSeries *series2 = new QLineSeries ();QLineSeries *series3 = new QLineSeries ();QLineSeries *series4 = new QLineSeries ();QLineSeries *series5 = new QLineSeries ();QLineSeries *series6 = new QLineSeries ();QLineSeries *series7 = new QLineSeries ();QLineSeries *series8 = new QLineSeries ();QLineSeries *series9 = new QLineSeries ();QLineSeries *series10 = new QLineSeries ();QLineSeries *series11 = new QLineSeries ();series0->setName("加速度计X轴");series1->setName("加速度计Y轴");series2->setName("加速度计Z轴");series3->setName("陀螺仪X轴");series4->setName("陀螺仪Y轴");series5->setName("陀螺仪Z轴");series6->setName("磁力计X轴");series7->setName("磁力计Y轴");series8->setName("磁力计Z轴");series9->setName("井斜角");series10->setName("工具面角");series11->setName("磁力计方位角");curSeries = series0;QPen pen;// 加速度计pen.setStyle (Qt:: SolidLine);pen.setWidth (2);pen.setColor (PaleTurquoise1);series0->setPen (pen);pen.setStyle (Qt::SolidLine);pen.setColor(DarkSeaGreen2);series1->setPen (pen);pen.setStyle (Qt:: SolidLine);pen.setWidth (2);pen.setColor (SpringGreen1);series2->setPen (pen);// 陀螺仪pen.setStyle(Qt::DashLine);pen.setColor(MediumBlue);series3->setPen (pen);pen.setStyle (Qt:: DashLine);pen.setWidth (2);pen.setColor (PaleGreen);series4->setPen (pen);pen.setStyle (Qt::DashLine);pen.setColor(IndianRed1);series5->setPen (pen);// 磁力计pen.setStyle (Qt:: DashDotDotLine);pen.setWidth (2);pen.setColor (DeepPink);series6->setPen (pen);pen.setStyle (Qt::DashDotDotLine);pen.setColor(HotPink1);series7->setPen (pen);pen.setStyle (Qt::DashDotDotLine);pen.setColor(Violet);series8->setPen (pen);// 姿态角pen.setStyle (Qt::DotLine);pen.setWidth (2);pen.setColor (DodgerBlue1);series9->setPen (pen);pen.setStyle (Qt::DotLine);pen.setColor(SkyBlue1);series10->setPen (pen);pen.setStyle (Qt::DotLine);pen.setColor(LemonChiffon3);series11->setPen(pen);// 设置背景chart->setTheme(QChart::ChartThemeDark);chart->addSeries(series0);chart->addSeries(series1);chart->addSeries(series2);chart->addSeries(series3);chart->addSeries(series4);chart->addSeries(series5);chart->addSeries(series6);chart->addSeries(series7);chart->addSeries(series8);chart->addSeries(series9);chart->addSeries(series10);chart->addSeries(series11);curAxis = axisX;axisX->setRange (0, maxNumber);axisX->setLabelFormat("%d");axisX->setTickCount (11);axisX->setMinorTickCount(4);axisX->setTitleText("采样点");axisY->setRange(axisY_Min-100, axisY_Max+100);  //设置Y轴最大最小值axisY->setLabelFormat("%.2f");axisY->setTitleText("value");axisY->setTickCount (5);axisY->setMinorTickCount (4);chart->addAxis(axisX, Qt::AlignBottom);chart->addAxis(axisY, Qt::AlignLeft);chart->setAxisX(axisX, series0); // x****chart->setAxisX(axisX, series1); //WWxchart->setAxisX(axisX, series2); // x****chart->setAxisX(axisX, series3); //WWxchart->setAxisX(axisX, series4); // x****chart->setAxisX(axisX, series5); //WWxchart->setAxisX(axisX, series6); // x****chart->setAxisX(axisX, series7); //WWxchart->setAxisX(axisX, series8); // x****chart->setAxisX(axisX, series9); //WWxchart->setAxisX(axisX, series10); // x****chart->setAxisX(axisX, series11); //WWxchart->setAxisY(axisY, series0); //WYchart->setAxisY(axisY, series1); //WYchart->setAxisY(axisY, series2); //WYchart->setAxisY(axisY, series3); //WYchart->setAxisY(axisY, series4); //WYchart->setAxisY(axisY, series5); //WYchart->setAxisY(axisY, series6); //WYchart->setAxisY(axisY, series7); //WYchart->setAxisY(axisY, series8); //WYchart->setAxisY(axisY, series9); //WYchart->setAxisY(axisY, series10); //WYchart->setAxisY(axisY, series11); //WY

2.3 样式表

  原始的控件是很丑的,所以想要界面好看,那就得自己做一个(或者找一个样式表),下面是我目前在用的样式表:

/*
Dark Console Style Sheet for QT Applications
Author: Jaime A. Quiroga P.
Company: GTRONICK
Last updated: 24/05/2018, 17:12.
Available at: https://github.com/GTRONICK/QSS/blob/master/ConsoleStyle.qss
*/
QWidget {background-color:rgb(0, 0, 0);color: rgb(240, 240, 240);border-color: rgb(58, 58, 58);
}QPlainTextEdit {background-color:rgb(0, 0, 0);color: rgb(200, 200, 200);selection-background-color: rgb(255, 153, 0);selection-color: rgb(0, 0, 0);
}QTabWidget::pane {border-top: 1px solid #000000;
}QTabBar::tab {background-color:rgb(0, 0, 0);border-style: outset;border-width: 1px;border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-bottom-color: rgb(58, 58, 58);border-bottom-width: 1px;border-top-width: 0px;border-style: solid;color: rgb(255, 153, 0);padding: 4px;
}QTabBar::tab:selected, QTabBar::tab:hover {color: rgb(255, 255, 255);background-color:rgb(0, 0, 0);border-color:rgb(42, 42, 42);margin-left: 0px;margin-right: 0px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;
}QTabBar::tab:last:selected {background-color:rgb(0, 0, 0);border-color:rgb(42, 42, 42);margin-left: 0px;margin-right: 0px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;
}QTabBar::tab:!selected {margin-bottom: 4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;
}QPushButton{border-style: outset;border-width: 2px;border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-bottom-color: rgb(58, 58, 58);border-bottom-width: 1px;border-style: solid;color: rgb(255, 255, 255);padding: 6px;background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
}QPushButton:hover{border-style: outset;border-width: 2px;border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));border-bottom-color: rgb(115, 115, 115);border-bottom-width: 1px;border-style: solid;color: rgb(255, 255, 255);padding: 6px;background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(107, 107, 107, 255), stop:1 rgba(157, 157, 157, 255));
}QPushButton:pressed{border-style: outset;border-width: 2px;border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(62, 62, 62, 255), stop:1 rgba(22, 22, 22, 255));border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-bottom-color: rgb(58, 58, 58);border-bottom-width: 1px;border-style: solid;color: rgb(255, 255, 255);padding: 6px;background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
}QPushButton:disabled{border-style: outset;border-width: 2px;border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));border-bottom-color: rgb(58, 58, 58);border-bottom-width: 1px;border-style: solid;color: rgb(0, 0, 0);padding: 6px;background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(57, 57, 57, 255), stop:1 rgba(77, 77, 77, 255));
}QLineEdit {border-width: 1px; border-radius: 4px;border-color: rgb(58, 58, 58);border-style: inset;padding: 0 8px;color: rgb(255, 255, 255);background:rgb(101, 101, 101);selection-background-color: rgb(187, 187, 187);selection-color: rgb(60, 63, 65);
}QProgressBar {text-align: center;color: rgb(255, 255, 255);border-width: 1px; border-radius: 10px;border-color: rgb(58, 58, 58);border-style: inset;
}QProgressBar::chunk {background-color: qlineargradient(spread:pad, x1:0.5, y1:0.7, x2:0.5, y2:0.3, stop:0 rgba(0, 200, 0, 255), stop:1 rgba(30, 230, 30, 255));border-radius: 10px;
}QMenuBar {background:rgb(0, 0, 0);color: rgb(255, 153, 0);
}QMenuBar::item {spacing: 3px; padding: 1px 4px;background: transparent;
}QMenuBar::item:selected { background:rgb(115, 115, 115);
}QMenu {border-width: 2px; border-radius: 10px;border-color: rgb(255, 153, 0);border-style: outset;
}QMenu::item {spacing: 3px; padding: 3px 15px;
}QMenu::item:selected {spacing: 3px; padding: 3px 15px;background:rgb(115, 115, 115);color:rgb(255, 255, 255);border-width: 1px; border-radius: 10px;border-color: rgb(58, 58, 58);border-style: inset;
}

三、串口接收数据

  这部分咱就直接上代码了,目前很多博主大部分都在用,我的呢还是有点小bug的,不过是可以用的。
  首先一定要修改.pro文件,而且要在所需的类里包含serialport的头文件:

QT += serialport
QString lastPort="",newPort="";MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);m_serialPort = new QSerialPort;QStringList baudrateList,stopList,parityList,dataBitList;baudrateList<<"1200"<<"2400"<<"4800"<<"9600"<<"19200"<<"38400"<<"57600"<<"115200";ui->baud->addItems(baudrateList);stopList<<"1"<<"2";ui->stopBit->addItems(stopList);parityList<<"NoParity"<<"EvenParity"<<"OddParity"<<"SpaceParity"<<"MarkParity";ui->parityBit->addItems(parityList);dataBitList<<"5"<<"6"<<"7"<<"8";ui->dataBit->addItems(dataBitList);// 修改功能区标题:ui->functionSelect->setTabText(0,"数据波形显示");ui->functionSelect->setTabText(1,"传感器校准");ui->functionSelect->setTabText(2,"Allan方差分析");ui->functionSelect->setTabText(3,"姿态结算");// 获取串口号按钮与box连接connect(ui->searchPort,&QPushButton::clicked,this,&MainWindow::getPortNameList);connect(m_serialPort,&QSerialPort::readyRead,[=](){recvData();//读取数据的函数});// 设置默认参数ui->baud->setCurrentText("115200");ui->stopBit->setCurrentText("1");ui->dataBit->setCurrentText("8");ui->parityBit->setCurrentText("NoParity");// 创建图形createChart();}
MainWindow::~MainWindow()
{delete ui;
}void MainWindow::getPortNameList()
{foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {newPort = info.portName();// newPort和lastPort均为全局变量,保证一个串口只打开一次if(newPort != lastPort){if(newPort==""){ui->searchPort->setText("无串口!");}else ui->serialPort->addItem(newPort);// ui->recieveData->appendPlainText("串口号:"+newPort);}lastPort = newPort;  // 上一次搜索到的串口号}if(newPort!=""){ui->searchPort->setText("获取串口号:"+ui->serialPort->currentText()+"成功!");}
}void MainWindow::on_openPort_clicked()
{if(ui->openPort->text()=="打开串口"){  // 如果此时还未打开串口ui->openPort->setText("正在打开串口...");m_serialPort->setPortName(ui->serialPort->currentText());// 选择当前串口的名称if(!m_serialPort->open(QIODevice::ReadWrite)){  // 打开串口失败ui->openPort->setText("串口打开失败!");return;}// 根据当前选择设置串口功能// 设置波特率switch (ui->baud->currentText().toInt()) {case 1200: m_serialPort->setBaudRate(QSerialPort::Baud1200,QSerialPort::AllDirections);break;case 2400: m_serialPort->setBaudRate(QSerialPort::Baud2400,QSerialPort::AllDirections);break;case 4800: m_serialPort->setBaudRate(QSerialPort::Baud4800,QSerialPort::AllDirections);break;case 9600: m_serialPort->setBaudRate(QSerialPort::Baud9600,QSerialPort::AllDirections);break;case 19200: m_serialPort->setBaudRate(QSerialPort::Baud19200,QSerialPort::AllDirections);break;case 38400: m_serialPort->setBaudRate(QSerialPort::Baud38400,QSerialPort::AllDirections);break;case 57600: m_serialPort->setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);break;case 115200: m_serialPort->setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);break;default:break;}// 设置校验位switch (ui->parityBit->currentIndex()) {case 0: m_serialPort->setParity(QSerialPort::NoParity);  break;case 1: m_serialPort->setParity(QSerialPort::EvenParity);  break;case 2: m_serialPort->setParity(QSerialPort::OddParity);  break;case 3: m_serialPort->setParity(QSerialPort::SpaceParity);  break;case 4: m_serialPort->setParity(QSerialPort::MarkParity);  break;default:break;}// 设置停止位switch (ui->stopBit->currentText().toInt()) {case 1:m_serialPort->setStopBits(QSerialPort::OneStop);break;case 2:m_serialPort->setStopBits(QSerialPort::TwoStop);break;default:break;}//设置数据位switch(ui->dataBit->currentText().toInt()){case 5: m_serialPort->setDataBits(QSerialPort::Data5);break;case 6: m_serialPort->setDataBits(QSerialPort::Data6);break;case 7: m_serialPort->setDataBits(QSerialPort::Data7);break;case 8: m_serialPort->setDataBits(QSerialPort::Data8);break;default:break;}// 关闭所有box  使其不可选ui->baud->setDisabled(1);ui->searchPort->setDisabled(1);ui->baud->setDisabled(1);ui->dataBit->setDisabled(1);ui->parityBit->setDisabled(1);ui->stopBit->setDisabled(1);ui->serialPort->setDisabled(1);ui->openPort->setText("关闭串口");}else if(ui->openPort->text()=="关闭串口"||ui->openPort->text()=="串口打开失败!"){// 打开所有boxui->baud->setEnabled(1);ui->searchPort->setEnabled(1);ui->baud->setEnabled(1);ui->dataBit->setEnabled(1);ui->parityBit->setEnabled(1);ui->stopBit->setEnabled(1);ui->serialPort->setEnabled(1);ui->openPort->setText("打开串口");m_serialPort->close();// 记得关闭串口//qDebug()<<"1111";}
}char storeData[100];            // 保存数据
int16_t i = 0,displayFlag = 0;         // 数据索引
void MainWindow::recvData()
{bool ok;int16_t accAndGro_Data[100] = {0};QByteArray hexData,G2 ;if (m_serialPort->bytesAvailable()) {//串口收到的数据可能不是连续的,需要的话应该把数据缓存下来再进行协议解析,类似tcp数据处理const QByteArray  recv_data = m_serialPort->readAll();if(recv_data.startsWith("\xFF")||displayFlag){QString stringHex = recv_data.toHex().toUpper();QString textShow;// 解析数据:for(int j = 0;j<stringHex.length();j++){accAndGro_Data[j] = stringHex.mid(2*j,2).toInt(&ok,16);}// 加速度数据:accData[0] = (accAndGro_Data[2]<<8) + accAndGro_Data[3];accData[1] = (accAndGro_Data[4]<<8) + accAndGro_Data[5];accData[2] = (accAndGro_Data[6]<<8) + accAndGro_Data[7];// 陀螺仪数据:accData[3] = (accAndGro_Data[8]<<8) + accAndGro_Data[9];accData[4] = (accAndGro_Data[10]<<8) + accAndGro_Data[11];accData[5] = (accAndGro_Data[12]<<8) + accAndGro_Data[13];// 姿态参数:accData[6] = (accAndGro_Data[14]<<8) + accAndGro_Data[15]; // 井斜角accData[7] = (accAndGro_Data[16]<<8) + accAndGro_Data[17]; // 方位角accData[8] = (accAndGro_Data[18]<<8) + accAndGro_Data[19]; // 工具面角// 磁力计数据accData[9] = (accAndGro_Data[20]<<8) + accAndGro_Data[21];accData[10] = (accAndGro_Data[22]<<8) + accAndGro_Data[23];accData[11] = (accAndGro_Data[24]<<8) + accAndGro_Data[25];// 地磁方位角accData[12] = (accAndGro_Data[26]<<8) + accAndGro_Data[27];accX_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[0];updataAxisYMaxAndMin(accData[0]);accY_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[1];updataAxisYMaxAndMin(accData[1]);accZ_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[2];updataAxisYMaxAndMin(accData[2]);gyroX_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[3];updataAxisYMaxAndMin(accData[3]);gyroY_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[4];updataAxisYMaxAndMin(accData[4]);gyroZ_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[5];updataAxisYMaxAndMin(accData[5]);magX_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[9];updataAxisYMaxAndMin(accData[9]);magY_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[10];updataAxisYMaxAndMin(accData[10]);magZ_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[11];updataAxisYMaxAndMin(accData[11]);inclina_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[6]/100;updataAxisYMaxAndMin(accData[6]/100);toolface_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[8]/100;updataAxisYMaxAndMin(accData[8]/100);azimuth_Data[rec_Number - exceedFlag * MAXNUMBER] = accData[7]/100;updataAxisYMaxAndMin(accData[7]/100);ui->accX_Data->setNum(accData[0]);ui->accY_Data->setNum(accData[1]);ui->accZ_Data->setNum(accData[2]);ui->gyroX_Data->setNum(accData[3]);ui->gyroY_Data->setNum(accData[4]);ui->gyroZ_Data->setNum(accData[5]);ui->magX_Data->setNum(accData[9]);ui->magY_Data->setNum(accData[10]);ui->magZ_Data->setNum(accData[11]);ui->inclination_Data->setNum(accData[6]/100.0);ui->toolFace_Data->setNum(accData[8]/100.0);ui->azimuth_Data->setNum(accData[7]/100.0);// 更新数据serialDataDisplay();for(int i=0;i<stringHex.length();i+=2){textShow += stringHex.mid(i,2);textShow += " ";}displayFlag = 1;if(stringHex.length()>23){i=0;hexData = 0;QDateTime dateTime= QDateTime::currentDateTime();//获取系统当前的时间displayFlag =0;}}}
}

四、波形显示

4.1 串口接收数据在chart上以波形显示

  话不多说,直接上代码:

void MainWindow::serialDataDisplay()
{QLineSeries *series0=(QLineSeries *)ui->serialCurveChart->chart()->series().at(0);QLineSeries *series1=(QLineSeries *)ui->serialCurveChart->chart()->series().at(1);QLineSeries *series2=(QLineSeries *)ui->serialCurveChart->chart()->series().at(2);QLineSeries *series3=(QLineSeries *)ui->serialCurveChart->chart()->series().at(3);QLineSeries *series4=(QLineSeries *)ui->serialCurveChart->chart()->series().at(4);QLineSeries *series5=(QLineSeries *)ui->serialCurveChart->chart()->series().at(5);QLineSeries *series6=(QLineSeries *)ui->serialCurveChart->chart()->series().at(6);QLineSeries *series7=(QLineSeries *)ui->serialCurveChart->chart()->series().at(7);QLineSeries *series8=(QLineSeries *)ui->serialCurveChart->chart()->series().at(8);QLineSeries *series9=(QLineSeries *)ui->serialCurveChart->chart()->series().at(9);QLineSeries *series10=(QLineSeries *)ui->serialCurveChart->chart()->series().at(10);QLineSeries *series11=(QLineSeries *)ui->serialCurveChart->chart()->series().at(11);if(rec_Number>=maxNumber) {maxNumber = maxNumber + 2;curAxis = axisX;                //axisX->setRange (rec_Number-200, maxNumber); //200改为宏定义}if(rec_Number>=(MAXNUMBER*(exceedFlag+1)-1))  // 数组保存的数据已经超限{// stopRefreshFlag = 1;exceedFlag += 1;rec_Number = MAXNUMBER*(exceedFlag);}else{if(dataSelect[0]) series0->append(rec_Number,accX_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[1]) series1->append(rec_Number,accY_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[2]) series2->append(rec_Number,accZ_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[3]) series3->append(rec_Number,gyroX_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[4]) series4->append(rec_Number,gyroY_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[5]) series5->append(rec_Number,gyroZ_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[6]) series6->append(rec_Number,magX_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[7]) series7->append(rec_Number,magY_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[8]) series8->append(rec_Number,magZ_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[9]) series9->append(rec_Number,inclina_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[10])series10->append(rec_Number,toolface_Data[rec_Number - exceedFlag * MAXNUMBER]);if(dataSelect[11])series11->append(rec_Number,azimuth_Data[rec_Number - exceedFlag * MAXNUMBER]);rec_Number = rec_Number + 1;}
}

  代码这部分呢虽然麻烦,但是是在调试过程中,逐步解决而完成的,所以会麻烦一点。

4.2 按钮打开新对话框并选择显示的数据

  在这里是新建了一个设计器界面,然后和MainWindow进行了信号与槽的连接,进而实现数据选择功能,下面是新建设计器界面的步骤(因为我已经创建了,在此就不再重新添加了):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  下面是我的代码:
  .h文件:

#ifndef DIALOGSELECTDATA_H
#define DIALOGSELECTDATA_H#include <QDialog>extern int16_t dataSelect[20];namespace Ui {
class Dialogselectdata;
}class Dialogselectdata : public QDialog
{Q_OBJECTpublic:explicit Dialogselectdata(QWidget *parent = nullptr);~Dialogselectdata();private slots:void on_OK_clicked();public slots:void checkBoxState();private:Ui::Dialogselectdata *dialog_ui;
};#endif // DIALOGSELECTDATA_H

  .c文件

#include "dialogselectdata.h"
#include "ui_dialogselectdata.h"int16_t dataSelect[20]={1,1,1,0,0,0,0}; // 选择要显示的数据Dialogselectdata::Dialogselectdata(QWidget *parent) :QDialog(parent),dialog_ui(new Ui::Dialogselectdata)
{dialog_ui->setupUi(this);
}Dialogselectdata::~Dialogselectdata()
{delete dialog_ui;
}void Dialogselectdata::on_OK_clicked()
{if(dialog_ui->accX_select->isChecked())dataSelect[0] = 1;else dataSelect[0] = 0;if(dialog_ui->accY_select->isChecked())dataSelect[1] = 1;else dataSelect[1] = 0;if(dialog_ui->accZ_select->isChecked())dataSelect[2] = 1;else dataSelect[2] = 0;if(dialog_ui->gyroX_select->isChecked())dataSelect[3] = 1;else dataSelect[3] = 0;if(dialog_ui->gyroY_select->isChecked())dataSelect[4] = 1;else dataSelect[4] = 0;if(dialog_ui->gyroZ_select->isChecked())dataSelect[5] = 1;else dataSelect[5] = 0;if(dialog_ui->magX_select->isChecked())dataSelect[6] = 1;else dataSelect[6] = 0;if(dialog_ui->magY_select->isChecked())dataSelect[7] = 1;else dataSelect[7] = 0;if(dialog_ui->magZ_select->isChecked())dataSelect[8] = 1;else dataSelect[8] = 0;if(dialog_ui->inclination_select->isChecked())dataSelect[9] = 1;else dataSelect[9] = 0;if(dialog_ui->toolface_select->isChecked())dataSelect[10] = 1;else dataSelect[10] = 0;if(dialog_ui->azimuth_select->isChecked())dataSelect[11] = 1;else dataSelect[11] = 0;
}

五、总结

  虽然边做边学的学习方法做起来可能会比较费劲,但是慢慢地积累多了也就会了,这篇博客代码比较多,可能也比较乱,后面会继续完善这篇博客的,希望和大家共同学习,一起进步哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/758800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯java组 螺旋折线

题目描述 如图所示的螺旋折线经过平面上所有整点恰好一次。 对于整点(X, Y)&#xff0c;我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。 例如dis(0, 1)3, dis(-2, -1)9 给出整点坐标(X, Y)&#xff0c;你能计算出dis(X, Y)吗&#xff1f; 【输入格…

处理器方法的返回值

返回ModelAndView: 若处理器方法处理完后&#xff0c;需要跳转到其它资源&#xff0c;且又要在跳转的资源间传递数据&#xff0c;此时处理器方法返回ModelAndView 比较好。当然&#xff0c;若要返回 ModelAndView&#xff0c;则处理器方法中 需要定义ModelAndView对象。 在使用…

Python 深度学习第二版(GPT 重译)(四)

九、高级计算机视觉深度学习 本章涵盖 计算机视觉的不同分支&#xff1a;图像分类、图像分割、目标检测 现代卷积神经网络架构模式&#xff1a;残差连接、批量归一化、深度可分离卷积 可视化和解释卷积神经网络学习的技术 上一章通过简单模型&#xff08;一堆Conv2D和MaxP…

什么是高防CDN?

高防CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;在网络安全中的作用非常重要。它通过一种特别的方式来保护网站和网络应用程序免受大规模DDoS攻击。以下是它的一些主要优势&#xff1a; 01 分布式防护 高防CDN通过在全球各地设立大量的节点…

深入解析Kafka中的动态更新模式

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深入解析Kafka中的动态更新模式 前言动态更新模式的基础概念动态更新模式的概念&#xff1a;解决的问题和引入的原因&#xff1a; 原理解析与工作流程动态更新模式的工作原理和工作流程&#xff1a;示…

【联邦学习贡献评估——联邦学习优化】

1. 模型复用 贡献评估往往需要计算不同参与方组合的数据价值, 然而模型相关的价值度量指标, 比如测试准确率, 需要基于数据重新训练并评测模型, 这导致了高昂的数据价值度量代价. 为了避免重复训练联邦模型的代价, 考虑复用全体参与方组合下训练联邦模型时各参与方的梯度更新,…

【NTN 卫星通信】 车辆物联网设备通过NTN和TN切换的应用场景

1 场景描述 对于有两个3GPP无线接入网服务的大面积农田和农场&#xff0c;物联网设备可以通过NTN和TN接入网同时受益于5G系统的双转向数据连接能力。   在这个用例中&#xff0c;我们有一个广域的农业自动化应用系统来控制农业车辆&#xff0c;例如&#xff0c;一个装有数百个…

大模型提示学习样本量有玄机,自适应调节方法好

引言&#xff1a;探索文本分类中的个性化示例数量 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;预测模型已经从零开始训练演变为使用标记数据对预训练模型进行微调。这种微调的极端形式涉及到上下文学习&#xff08;In-Context Learning, ICL&#xff09;&…

leetcode代码记录(删除字符串中的所有相邻重复项

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给出由小写字母组成的字符串 S&#xff0c;重复项删除操作会选择两个相邻且相同的字母&#xff0c;并删除它们。 在 S 上反复执行重复项删除操作&#xff0c;直到无法继续删除。 在完成…

数据结构:9、二叉树

在上堆中已经介绍了什么是二叉树&#xff0c;所以这里直接写二叉树实现。 1、二叉树的构建 二叉树的构建第一步肯定是初始化&#xff0c;也就是构建这棵树&#xff0c;这里是利用前序遍历构建的&#xff0c;因为这里是利用链表形式创建的二叉树&#xff0c;所以这里就是和之前…

redis常用五大数据类型

目录 Key 字符串String 常用命令 列表List 常用命令 集合Set 常用命令 Hash哈希 键值对集合 有序集合Zset Redis新数据类型 Key set key value...添加keykeys *查看当前库中所有的keyexist key该key是否存在type keykey的类型del key删除keyunlink key根据value选择非阻塞…

C++ UML类图

参考文章&#xff1a; &#xff08;1&#xff09;C UML类图详解 &#xff08;2&#xff09;C基础——用C实例理解UML类图 &#xff08;3&#xff09;C设计模式——UML类图 &#xff08;4&#xff09;[UML] 类图介绍 —— 程序员&#xff08;灵魂画手&#xff09;必备画图技能之…

2 使用GPU理解并行计算

2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验&#xff0c;但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…

手撕算法-二叉树的最大深度

描述&#xff1a;分析&#xff1a;求以节点root为根节点的树的最大深度。可以进行拆分&#xff1a;root为根节点的树的最大深度 max(左子树的最大深度, 右子树最大深度&#xff09;1 截止条件是节点为空&#xff0c;深度为0&#xff1b; 代码&#xff1a; public int maxDep…

HarmonyOS如何创建及调用三方库

介绍 本篇主要向开发者展示了在Stage模型中&#xff0c;如何调用已经上架到三方库中心的社区库和项目内创建的本地库。效果图如下&#xff1a; 相关概念 Navigation&#xff1a;一般作为Page页面的根容器&#xff0c;通过属性设置来展示页面的标题、工具栏、菜单。Tabs&#…

Java + sa-token统一身份认证开发笔记

官网地址&#xff1a;Sa-Token 统一认证服务端 直接用的官网的demo&#xff0c;稍加改动&#xff0c;因为要前后端分离&#xff0c;加了一个H5Controller&#xff0c;官网也有详细介绍&#xff0c;这一部分不难&#xff0c;照着做就行了 配置文件&#xff1a; # Sa-Token 配…

vo、po、dto、bo、pojo、entity

VO&#xff1a;Value Object&#xff0c;值对象。 通常用于业务层之间的数据传递&#xff0c;由new创建&#xff0c;由GC回收&#xff1b;例如&#xff1a;将商品信息和用户信息重新用一个对象封装起来。和PO一样也是仅仅包含数据而已&#xff0c;但应是抽象出的业务对象&…

全网良心开源知识库:AI学习者的宝藏之地

导语&#xff1a;在这个信息爆炸的时代&#xff0c;想要入门AI&#xff0c;找到最一流的学习资源并非易事。然而&#xff0c;有一个地方&#xff0c;能让你免费学习AI&#xff0c;获取最顶尖的知识&#xff0c;还能加入最优秀的AI学习圈。今天&#xff0c;我要向大家推荐的&…

Jumpserver 堡垒机用户启用双因子登录

前言&#xff1a; 堡垒机双因子登录 堡垒机往往是内部权限的集合体&#xff0c;拿到了堡垒机的用户账号密码&#xff0c;很容易就顺藤摸瓜攻破各种应用系统&#xff0c;除了常规的用户名复杂密码的要求外&#xff0c;我们常常都要求采用双因子的登录方式。双因子最常见的就是账…

【Qt学习笔记】(六)界面优化

界面优化 1 QSS1.1 背景介绍1.2 基本语法1.3 QSS设置方式1.3.1 指定控件样式设计1.3.2 全局样式设置1.3.3 使用 Qt Designer 编辑样式 1.4 选择器1.4.1选择器概况1.4.2 子控件选择器&#xff08;Sub-Controls&#xff09;1.4.3伪类选择器(Pseudo-States) 1.5 样式属性1.5.1 盒模…