天天看點

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

一.簡介

最近粗略地學習了一下上位機的程式設計,大緻了解了底層硬體與上位機之間的序列槽通信邏輯,TCP通信和UDP通信暫時還未學習。
本次把學習思路分享一下,主要學習視訊是b站上北京迅為的QT教學視訊,我的筆記也是在此基礎上總結出來。很多細節在視訊中已經介紹,篇幅有限,僅分享大緻流程。
源碼附在文章最後,希望和各位多多交流。

視訊連結:【北京迅為】嵌入式學習之QT學習篇

同時分享一篇很好的相關部落格:開源一款基于Qt的序列槽波形顯示上位機 & 以“筆”會友

二.界面展示

界面制作較為簡陋,代碼也較為粗糙,多多包涵。

1.基礎界面:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

2.波形顯示界面

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

三.QT軟體下載下傳

下載下傳位址:清華鏡像網

★按以下步驟依次點開:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

選擇需要下載下傳的版本,以v5.12.1為例:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

下載下傳windows版本:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

安裝教程視訊中有詳細介紹。唯一需要改變的是:

在選擇安裝元件時多勾選一個,用于後面的波形顯示:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

四.建立工程

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

五.工程檔案結構

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

六.序列槽基本收發編寫

注意:對于新手,請務必看完視訊的基礎教程再繼續浏覽,後續不包含基礎教學,隻提及一些學習過程中的難點和關鍵點。

序列槽的打開和普通的資料收發在迅飛的視訊中均有介紹,在此不做過多講解。

1.十六進制與字元之間的轉換發送/接收

/************************發送資料按鈕槽函數************************/
void Widget::on_sendBt_clicked()
{
    //将發送欄的資料輸出
    long long a=0;
    //字元串形式
    if(ui->is16SendQch->checkState() == false)
    {
        a=serialPort->write(ui->lineEdit->text().toLocal8Bit().data());
    }
    else    //16進制發送(将16進制轉換成Ascll碼對應的字元發送)
    {
        a=serialPort->write(QByteArray::fromHex(ui->lineEdit->text().toUtf8()).data()); //16進制資料解碼後發送
    }
    //如果發送成功,a擷取發送的位元組長度,發送失敗則傳回-1;

    if(a > 0)
    {
        sendNum += a;
        set_num_on_label(ui->sendLbl,"S:", sendNum);	//顯示發送的資料量
    }
}
           
connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot()));
//把接收資料信号與接收槽函數關聯,加在構造函數中。
/************************接收資料槽函數,需要手動關聯************************/
void Widget::serialPortReadyRead_Slot()
{
    QString buf;
    QByteArray recBuf;
    int bufNum;
    uint8_t checkNum=0;   //計算校驗碼

    //讀取所有位元組
    recBuf=serialPort->readAll();
    //接收位元組計數
    recvNum += recBuf.size();

    if(ui->is16RecvQch->checkState() == false)  //不使用16進制接收
    {
        buf = QString(recBuf);
    }
    else
    {
        buf = QString(recBuf).toUtf8().toHex();     //轉成16進制

        //每個16進制資料之間用空格分隔
        bufNum = buf.length();
        while(bufNum-2 > 0)
        {
            bufNum = bufNum - 2;
            buf.insert(bufNum," ");
        }
    }
    ui->plainTextEdit->insertPlainText(buf);         //把接收到的資料顯示到接收欄上
    ui->plainTextEdit->moveCursor(QTextCursor::End); //光标設定,確定滾輪滾動

    //狀态欄顯示接收資料量
    set_num_on_label(ui->recvLbl, "R:", recvNum);
}
           

2.以16進制/字元發送切換(接收暫未程式設計)

/************************字元串/16進制發送切換槽函數************************/
void Widget::on_is16SendQch_stateChanged()
{
    QString str;
    int strNum;

    if(ui->is16SendQch->checkState() == false)  //轉成字元串
    {
        ui->lineEdit->setText(QByteArray::fromHex(ui->lineEdit->text().toUtf8()).data());   //解碼16進制
    }
    else    //轉成16進制
    {
        str=ui->lineEdit->text().toUtf8().toHex().data();

        //每個16進制資料之間用空格分隔
        strNum = str.length();
        while(strNum-2 > 0)
        {
            strNum = strNum - 2;
            str.insert(strNum," ");
        }

        ui->lineEdit->setText(str);
    }
}
           

該代碼實作當切換16進制/字元發送時,發送框内的資料會自動轉換:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享
【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

3.定時發送

connect(&timer,SIGNAL(timeout()),this,SLOT(on_sendBt_clicked())); 
//把定時器溢出信号與序列槽發送槽函數關聯,加在構造函數中。
/************************定時發送開始/關閉槽函數************************/
void Widget::on_timeSendQch_stateChanged()
{
    long counter;
    if(ui->timeSendQch->checkState() == false)  //定時發送關閉
    {
        timer.stop();       //關閉定時器
    }
    else    //定時發送打開
    {
        counter = (ui->timeSendQl->text()).toLong();    //轉換成長整型
        if(counter>0 && ui->lineEdit->text() != "" && isSerialConnect == true)     //定時時間需大于0ms且發送欄須有字元,否則關閉
        {
            timer.start(counter);   //打開定時器,機關ms
        }
        else
        {
            timer.stop();   //關閉定時器
        }
    }
}
           

使用展示:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

七.波形顯示

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

上圖是由測試資料直接顯示,基本沒有問題。但是根據接收資料進行實時繪制會出現問題。

1.示波器顯示可以最多兩個通道;

2.可以控制波形顯示的更新與暫停,以及波形1/波形2是否顯示。

3.與匿名上位機等類似,需要使用特定的幀格式。

4.顯示主題可以切換。

5.仍存在一些未解決的BUG(文章最後會提到)。

6.代碼中包含測試波形的程式。

★波形顯示基礎界面借鑒了下面這篇部落格,部落格中部落客也分享了源碼:

QtChart——簡單的動态波形圖

1.波形資料接收并判斷

在之前的就收槽函數中,加入了後面一部分波形資料的接收判斷。

/************************接收資料槽函數,需要手動關聯************************/
void Widget::serialPortReadyRead_Slot()
{
    QString buf;
    QByteArray recBuf;
    int bufNum;
    uint8_t checkNum=0;   //計算校驗碼

    //讀取所有位元組
    recBuf=serialPort->readAll();
    //接收位元組計數
    recvNum += recBuf.size();

    if(ui->is16RecvQch->checkState() == false)  //不使用16進制接收
    {
        buf = QString(recBuf);
    }
    else
    {
        buf = QString(recBuf).toUtf8().toHex();     //轉成16進制

        //每個16進制資料之間用空格分隔
        bufNum = buf.length();
        while(bufNum-2 > 0)
        {
            bufNum = bufNum - 2;
            buf.insert(bufNum," ");
        }
    }
    ui->plainTextEdit->insertPlainText(buf);         //把接收到的資料顯示到接收欄上
    ui->plainTextEdit->moveCursor(QTextCursor::End); //光标設定,確定滾輪滾動

    //狀态欄顯示計數值
    set_num_on_label(ui->recvLbl, "R:", recvNum);

    if(wa->isHidden() == false &&                   //界面打開後才進行波形顯示
       static_cast<uint8_t>(recBuf[0]) == 0xAA &&   //同時要保證幀頭和位址正确
       static_cast<uint8_t>(recBuf[1]) == 0xCC)
    {
        //計算校驗位
        for(uint8_t i=3;i<7;i++)
            checkNum += recBuf[i];

        if(checkNum == static_cast<uint8_t>(recBuf[7])) //校驗位正确
        {
            //資料類型轉換并轉移到Ware的屬性中
            wa->head    = static_cast<uint8_t>(recBuf[0]);
            wa->address = static_cast<uint8_t>(recBuf[1]);
            wa->length  = static_cast<uint8_t>(recBuf[2]);
            wa->ware1   = static_cast<uint8_t>(recBuf[3])*256+static_cast<uint8_t>(recBuf[4]);
            wa->ware2   = static_cast<uint8_t>(recBuf[5])*256+static_cast<uint8_t>(recBuf[6]);
            wa->check   = static_cast<uint8_t>(recBuf[7]);
            wa->isValid = true;
        }
        else
        {
            wa->isValid = false;
        }
        wa->serial_updata_data(wa->isValid);   //波形繪制
    }
}
           

2.使用波形測試資料時需要如下調整

1.去除下列注釋符号:
Ware::Ware(QWidget *parent)
{
	//timer->setInterval(50); //定時50ms
	//timer->start();
}

void Ware::init_slot()
{
	//connect(timer, SIGNAL(timeout()), this, SLOT(timerSlot())); //定時器溢出信号
}

2.把下述代碼用注釋代碼替換
void Ware::update_data()
{
	//double dataY1,dataY2;
	int16_t dataY1,dataY2;
	
	//擷取波形資料
	//dataY1 = 10 * sin(M_PI * count * 4 / 180);   //擷取新資料
	//dataY2 = 10 * cos(M_PI * count * 4 / 180);
	dataY1 = ware1;
	dataY2 = ware2;
}
           

其餘代碼直接下載下傳源碼檢視。

八.打包與部署(生成.exe檔案)

1.把工程切換到release模式,然後編譯。

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

2.找到release模式建構的檔案夾

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

3.把圖示檔案添加到工程檔案夾下,進而更換.exe檔案的圖示。(圖示格式必須為.ico這個格式的)

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

然後在.pro檔案中添加如下代碼:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

★USB.ico為圖檔檔案名稱。

4.使用QT的工作台進行封包的操作

(1).直接通過windows的搜尋功能找到QT工作台:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

(2).然後在電腦桌面上建立新的檔案夾(注意:檔案夾名稱不能出現中文)

再把工程檔案中的.exe檔案複制到新檔案夾中。

(3).接着在QT工作台中輸入:cd /d C:\Users\pc\Desktop\serial tools(後面為建立的檔案夾路徑)進入檔案夾。

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

(4).然後輸入:windeployqt serial.exe進行封包:

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

(5).封包結束後即可在檔案夾中看到應用檔案,輕按兩下即可使用。

【QT上位機設計——序列槽收發和波形顯示】一.簡介二.界面展示三.QT軟體下載下傳四.建立工程五.工程檔案結構六.序列槽基本收發編寫七.波形顯示八.打包與部署(生成.exe檔案)九.待解決的問題十.源碼分享

九.待解決的問題

1.接收資料的波形資料高8位/低8位不能為0,否則無法正常顯示波形;

2.使用測試資料進行波形繪制時不會卡頓;但是,當使用接收的資料進行波形繪制時,接收的資料量變大後容易卡頓,隻有清除序列槽接收界面的資料才可以緩解;

3.滑鼠移動可能會引起波形繪制錯誤。

十.源碼分享

基于QT的序列槽收發和波形繪制上位機程式

繼續閱讀