基於Qt5-將串口助手打造成“示波器”

有段時間,做電賽題的時候,在那看波形調PID參數,因爲要同時觀察電壓和兩路電流,無奈只有一臺示波器,遂有一想法,將單片機採集的電流數據通過串口發送給上位機,然後在上位機上以波形的形式顯示出來,方便觀察。因爲時間問題,都是現學現用,整體做的很簡陋,只是實現了要用到的功能,還請選擇性瀏覽。

1.上位機是基於Qt5編寫的,還用到了用於繪圖第三方庫--qcustomplot,具體使用可以百度,我這裏用的比較簡單,沒花時間去琢磨。首先用Qt創建一個項目,然後在項目的.pro文件裏添加,其中serialport是串口的,printsupport是繪圖庫qcustomplot的。

QT       += serialport printsupport

2.相應的頭文件,第一個是對串口的設置,第二個是得到串口的信息,第三個自然就是用於繪圖的qcustomplot的頭文件了。

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include "qcustomplot.h"

3.定義相關變量,

private:
    QSerialPort SerialPort;        //用於設置串口
    QSerialPortInfo SerialPortInfo;//用於得到串口信息
    int Clk ;    //x軸的時間數
    QCustomPlot *Plot;    //定義一個窗口繪圖的句柄
    QVector <double>    XData;//x軸數據
    QVector <double>    YData;//線1的y軸數據
    QVector <double>    Y1Data;//線2的y軸數據
    QCustomPlot *PlotV;    //定義另一個窗口繪圖的句柄
    QVector <double>    Y2Data;
    QVector <double>    Y3Data;

初始化相關變量

    XData.resize(50);    //分配空間
    XData.value(0,1);
    YData.resize(50);
    Y1Data.resize(50);
    Y2Data.resize(50);
    Y3Data.resize(50);
    ui->horizontalAMax->setRange(600,3000);
    ui->horizontalAMax->setValue(600);
    ui->horizontalAMin->setRange(0,600);
    ui->horizontalAMin->setValue(0);
    ui->horizontalVMax->setRange(500,800);
    ui->horizontalVMax->setValue(600);
    ui->horizontalVMin->setRange(0,500);
    ui->horizontalVMin->setValue(400);

    Plot = ui->widget;        //指定窗口用於顯示波形
    Plot->addGraph();        //添加一條線
    Plot->addGraph();        //再添加一條線
    Plot->graph(0)->setPen(QPen(Qt::red));    //設置第一根線的顏色爲紅色
    Plot->graph(1)->setPen(QPen(Qt::blue));   //設置第二根線的顏色爲藍色 
    Plot->xAxis->setLabel("mS");        //設置x軸的標籤
    Plot->yAxis->setLabel("mA");        //設置y軸的標籤
//    Plot->rescaleAxes(true);
    Plot->yAxis->setRange(0,700);        //初始化y軸的範圍
    Plot->xAxis->rescale(true);          //讓x軸自動隨着數變化

    PlotV = ui->widget_C;
    PlotV->addGraph();
    PlotV->addGraph();
    PlotV->graph(0)->setPen(QPen(Qt::red));
    PlotV->graph(1)->setPen(QPen(Qt::blue));
    PlotV->xAxis->setLabel("mS");
    PlotV->yAxis->setLabel("Count");
    PlotV->yAxis->setRange(400,600);
    PlotV->xAxis->rescale(true);

    GraphShow();    //給圖形賦值
    InitPort();    //初始化串口
    QTimer::singleShot(80,this,&Widget::ReadPort);//定一定時器,方便接收數據
    Clk = 0;    //x軸的時間數,初試爲0

3.串口的初始化和出口數據的讀取

void Widget::InitPort()    //判斷當前是否有效的串口,並得到相關得數據
{
    //遍歷所有有效的串口,得到每個有效串口得數據
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        qDebug() << "Name :"<<info.portName();
        qDebug() << "Description: "<<info.description();
        qDebug() << "Manufacturer: "<<info.manufacturer();
        QSerialPort serial;
        serial.setPort(info);
        if(serial.open(QIODevice::ReadWrite))
        {//判斷是否能夠打開該串口,如果能,則將相應的串口名加到串口的下拉欄裏
            ui->comboBoxCom->addItem(info.portName());
            serial.close();//這裏只是起判定效果,不用以打開,還得關閉當前串口,方便查詢其他串口
        }
    }
}
//這個是開啓按鍵的槽函數,如果有有效的串口,然後進行打開操作,也可以充當關閉串口的作用
void Widget::on_pushButtonS_clicked()
{
    //判斷當前程序處於什麼狀態中,如果沒有串口使用,則進入“開啓串口”
    if(ui->pushButtonS->text() == "開啓串口")
    {    //得到當前串口欄得數據
        SerialPort.setPortName(ui->comboBoxCom->currentText());
        if(SerialPort.open(QIODevice::ReadOnly))
        {
            SerialPort.setBaudRate(ui->comboBoxBaut->currentText().toInt());//設置波特率
            SerialPort.setDataBits(QSerialPort::Data8);//設置數據位爲8位
            SerialPort.setParity(QSerialPort::NoParity);//沒有奇偶校驗位
            SerialPort.setFlowControl(QSerialPort::NoFlowControl);//沒有流控制
            SerialPort.setStopBits(QSerialPort::OneStop);//設置一個停止位

            ui->pushButtonS->setText("關閉串口");    //更改按鍵狀態
        }
        else{
            qDebug() << "串口沒有打開";
            return;
        }
    }else if(ui->pushButtonS->text() == "關閉串口")
        {
        SerialPort.close();
        ui->pushButtonS->setText("開啓串口");
    }
    else{
        qDebug() <<"無效操作";
    }
}
//獲取串口數據,我這裏是採用每隔40ms來獲取一次數據
void Widget::ReadPort()
{
    QTimer::singleShot(40,this,&Widget::ReadPort);
    if(SerialPort.isOpen() == false)
        return;
    //得到串口數據
    QByteArray temp = SerialPort.readAll();
    if(temp.isEmpty())
        return;
    //將數據進行文本化顯示
    ui->textEditR->append(QString(temp));
    GetData(QString(temp));//處理當前數據,得出有效數據,這個函數實現是按要求來的,就不貼出來了
    GraphShow();
}

4.波形的繪製--GraphShow函數的實現

void Widget::GraphShow()
{
    Plot->graph(0)->setData(XData,YData);
    Plot->graph(1)->setData(XData,Y1Data);
    Plot->yAxis->setRange(Slither_aMin,Slither_aMax);
    Plot->xAxis->rescale(true);
    Plot->replot();//重新繪製

    PlotV->graph(0)->setData(XData,Y2Data);
    PlotV->graph(1)->setData(XData,Y3Data);
    PlotV->yAxis->setRange(Slither_vMin,Slither_vMax);
    PlotV->xAxis->rescale(true);
    PlotV->replot();
}

5.另外就是一些按鍵和滑動欄的槽函數,視具體要求實現,就不貼出來了。其中刷新按鍵,是獲取當前有效串口,清除按鍵是清除text窗口的文本信息,四個滑行分別是調整相應窗口的y軸的上限和下限,方便觀察波形。

6.總結,其實qcustomplot和串口相關的函數使用還是挺簡單的,其中qcustomplot我只是用到了點皮毛,看官方提供的demo,可是非常好看和實用的。

最後用來觀察波形的時候,還是挺不錯的。因爲時間有點遠,沒有相應的圖貼出來了,還請見諒。學習,共勉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章