【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::ui
    ui->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); //WWx
    chart->setAxisX(axisX, series2); // x****
    chart->setAxisX(axisX, series3); //WWx
    chart->setAxisX(axisX, series4); // x****
    chart->setAxisX(axisX, series5); //WWx
    chart->setAxisX(axisX, series6); // x****
    chart->setAxisX(axisX, series7); //WWx
    chart->setAxisX(axisX, series8); // x****
    chart->setAxisX(axisX, series9); //WWx
    chart->setAxisX(axisX, series10); // x****
    chart->setAxisX(axisX, series11); //WWx

    chart->setAxisY(axisY, series0); //WY
    chart->setAxisY(axisY, series1); //WY
    chart->setAxisY(axisY, series2); //WY
    chart->setAxisY(axisY, series3); //WY
    chart->setAxisY(axisY, series4); //WY
    chart->setAxisY(axisY, series5); //WY
    chart->setAxisY(axisY, series6); //WY
    chart->setAxisY(axisY, series7); //WY
    chart->setAxisY(axisY, series8); //WY
    chart->setAxisY(axisY, series9); //WY
    chart->setAxisY(axisY, series10); //WY
    chart->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()=="串口打开失败!"){

       // 打开所有box
       ui->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_OBJECT

public:
    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;
}

五、总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT6实现创建与操作sqlite数据库及读取实例(一)

一.Qt为SQL数据库提供支持的基本模块&#xff08;Qt SQL&#xff09; Qt SQL的API分为不同层&#xff1a; 驱动层 SQL API层 用户接口层 1.驱动层 对于Qt 是基于C来实现的框架&#xff0c;该层主要包括QSqlDriver&#xff0c;QSqlDriverCreator,QSqlDriverCreatorBase,QSqlPlug…

初识GO语言

是由google公司推出的一门编程语言&#xff0c;12年推出的第一个版本 Go的特点 Go为什么能在最近的IT领域炙手可热 集python简洁&C语言的性能于一身 21世纪的C语言 顺应容器化时代的到来 区块链的崛起 学习一门编程语言可以划分为下面这三个步骤 安装 编译器 or 解…

C语言种sizeof()和strlen的区别

sizeof 是 C 语言内置的操作符关键字&#xff0c;而 strlen 是 C 语言库函数&#xff1b; sizeof 仅用于计算数据类型的大小或者变量的大小&#xff0c;而 strlen 只能以结尾为 \0 的字符串作为参数&#xff1b; 编译器在编译时就计算出了 sizeof 的结果&#xff0c;而 strlen …

【内核内存管理、动态分配及IO访问、LED驱动】

一、内核内存管理框架 内核将物理内存等分成N块4KB&#xff0c;称之为一页&#xff0c;每页都用一个struct page来表示&#xff0c;采用伙伴关系算法维护 内核地址空间划分图&#xff1a; 3G~3G896M&#xff1a;低端内存&#xff0c;直接映射 虚拟地址 3G 物理地址 ​ 细…

YOLOv8独家改进:block改进 | RepViTBlock和C2f进行结合实现二次创新 | CVPR2024清华RepViT

💡💡💡本文独家改进:CVPR2024 清华提出RepViT:轻量级新主干!从ViT角度重新审视移动CNN,RepViTBlock和C2f进行结合实现二次创新 改进结构图如下: 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm=1001.2014.3001.5482 💡…

UML学习体会

1. 水在前面 本来写作的水平就很一般&#xff0c;平时写的也少。最近看到一些文章说学习最好的方式是输出&#xff0c;刚好又重温了一遍UML方面的基础&#xff0c;所以想记录点学习心得。而且说实话这玩意平时基本不怎么用&#xff08;偶尔倒是看看别人的成果&#xff09;&…

mabatis 下

mybatis 原生的API&注解的方式MyBatis-原生的API调用快速入门需求快速入门代码实现 MyBatis-注解的方式操作快速入门需求快速入门代码实现注意事项和说明 mybatis-config.xml配置文件详解说明properties属性settings全局参数定义typeAliases别名处理器typeHandlers类型处理…

麒麟 V10 一键安装 Oracle 11GR2(231017)单机版

Oracle 一键安装脚本&#xff0c;演示 麒麟 V10 一键安装 Oracle 11GR2 单机版过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 ORALCE PSU/OJVM 等补丁自动安装&#xff09; ⭐️ 脚本下载地址&#xff1a;Shell脚本安装Oracle数据库 脚本第…

【C语言】结构体的内存对齐问题

1.结构体内存对齐 我们已经基本掌握了结构体的使用了。那我们现在必须得知道结构体在内存中是如何存储的&#xff1f;内存是如何分配的&#xff1f;所以我们得知道如何计算结构体的大小&#xff1f;这就引出了我们今天所要探讨的内容&#xff1a;结构体内存对齐。 1.1 对齐规…

深入浅出Go性能监控:使用expvar库的实战指南

深入浅出Go性能监控&#xff1a;使用expvar库的实战指南 引言expvar库概览主要组件介绍如何帮助开发者监控应用性能 实战开始&#xff1a;配置和初始化导入expvar库初始化expvar创建和注册自定义Var实例 监控关键数据使用expvar监控内存使用监控Goroutines数量自定义业务指标监…

软件测评中心:进行科技成果鉴定测试的注意事项和好处简析

软件产品科技成果鉴定是有效评价科技成果质量和水平的方法之一&#xff0c;也是鼓励科技成果通过市场竞争等方式得到有效的评价和认可&#xff0c;可以推动科技成果的进步和转化。 一、进行科技成果鉴定测试时的注意事项&#xff1a;   1、应由具备一定资质和能力的专业机构…

综合实验---Web---进阶版

目录 实验配置&#xff1a; 1.PHP调整主配置文件时&#xff0c;修改文件内容 1.原内容调整(在编译安装的情况下) 2.调整如下 3.没有调整的&#xff0c;根据之前配置就行 2.配置Nginx支持PHP解析 1.原内容如下 2.调整如下 3.验证PHP测试页 1.原内容如下 2.调整如下 4…

Ethsign银河活动开启,简单参与领6个NFT

简介&#xff1a;EthSign是一个基于区块链技术的去中心化电子签名平台&#xff0c;目的是解决传统中心化电子签名服务的各种问题。用户可以使用钱包或社交媒体帐户生成的私钥签署文件和协议&#xff0c;数字签名记录在链上&#xff0c;文件经过加密存储在去中心化存储网络中&am…

51-31 CVPR’24 | VastGaussian,3D高斯大型场景重建

2024 年 2 月&#xff0c;清华大学、华为和中科院联合发布的 VastGaussian 模型&#xff0c;实现了基于 3D Gaussian Splatting 进行大型场景高保真重建和实时渲染。 Abstract 现有基于NeRF大型场景重建方法&#xff0c;往往在视觉质量和渲染速度方面存在局限性。虽然最近 3D…

OSPF特殊区域(stub\nssa)

stub区域——只有1类、2类、3类&#xff1b;完全stub区域——只有1类、2类 NSSA区域&#xff1a;本区域将自己引入的外部路由发布给其他区域&#xff0c;但不需要接收其他区域的路由 在NSSA区域的路由器上&#xff0c;引入外部路由时&#xff0c;不会转换成5类LSA&#xff0c…

【保姆级教程】如何拥有GPT?(Proton邮箱版)

OnlyFans 订阅教程移步&#xff1a;【保姆级】2024年最新Onlyfans订阅教程 Midjourney 订阅教程移步&#xff1a; 【一看就会】五分钟完成MidJourney订阅 GPT-4.0 升级教程移步&#xff1a;五分钟开通GPT4.0 如果你需要使用Wildcard开通GPT4、Midjourney或是Onlyfans的话&am…

故障诊断 | 一文解决,RBF径向基神经网络的故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述

【暑期实习记录】腾讯oc

部门&#xff1a;实习基地 - 无意向 - csig腾讯云捞 TimeLine 3.3 压线投递实习基地 3.6 一面 主要深问项目&#xff0c;包括设计、困难点、亮点、迭代过程、对比、测试和部署等&#xff0c;然后问了一些相关的八股&#xff0c;一道简单sql和简单算法 之后反问面试官他对应…

操作系统知识-操作系统作用+进程管理-嵌入式系统设计师备考笔记

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 本章的主要内容见下图&#xff1a; 1、操作系统的作用…

【ACL 2023获奖论文】再现奖:Do CoNLL-2003 Named Entity Taggers Still Work Well in 2023?

【ACL 2023获奖论文】再现奖&#xff1a;Do CoNLL-2003 Named Entity Taggers Still Work Well in 2023? 写在最前面动机主要发现和观点总结 正文1引言6 相关工作解读 2 注释一个新的测试集以度量泛化CoNLL数据集的创建数据集统计注释质量与评估者间协议目标与意义 3 实验装置…