我們本次實(shí)現(xiàn)的上位機(jī)的功能很簡單:上位機(jī)通過串口來控制開發(fā)板上的一個(gè)LED的亮滅。界面如:

二、QT環(huán)境搭建
在開始編寫上位機(jī)之前我們先來一起搭建一下QT開發(fā)環(huán)境(不然就不是手把手了,哈哈)。往期推文?QT | 詳解Qt的幾種開發(fā)方式?中有介紹到QT的兩種開發(fā)環(huán)境:
使用VS + QT
使用Qt Creator
這里我們選擇直接使用QT_Creator的方式。
Qt Creator是一個(gè)用于Qt開發(fā)的輕量級跨平臺(tái)集成開發(fā)環(huán)境。
Qt Creator可帶來兩大關(guān)鍵益處:
提供首個(gè)專為支持跨平臺(tái)開發(fā)而設(shè)計(jì)的集成開發(fā)環(huán)境 (IDE),并確保首次接觸Qt框架的開發(fā)人員能迅速上手和操作。
即使不開發(fā)Qt應(yīng)用程序,Qt Creator也是一個(gè)簡單易用且功能強(qiáng)大的IDE。
下面我們來一起安裝Qt Creator。
1、注冊qt賬號
我們需要先注冊一個(gè)QT賬號,后面安裝Qt Creator的時(shí)候會(huì)用到。
2、下載QT_Creator并安裝
我們在Windows上進(jìn)行開發(fā),安裝Windows版本的Qt Creator。

下載得到qt-opensource-windows-x86-5.11.3.exe。然后雙擊安裝,第二步需要輸入賬號密碼,把我們上面注冊好的賬號密碼填入即可。
接下來還需要選擇安裝組件,根據(jù)自己需要進(jìn)行選擇安裝,我安裝的組件如:

安裝完成之后我們桌面上并沒有Qt Creator的快捷方式,需要自己創(chuàng)建。找到Qt Creator的安裝路徑,然后把Qt Creator發(fā)送到桌面快捷方式即可。如:

3、驗(yàn)證QT_Creator是否安裝成功
我們創(chuàng)建一個(gè)簡單的C++工程來驗(yàn)證一下Qt Creator是否安裝成功。





Qt Creator搭建好之后我們接下來開始編寫我們的上位機(jī)。
三、編寫一個(gè)簡單的上位機(jī)
編寫這個(gè)簡單的上位機(jī)我們需要經(jīng)過一下幾個(gè)步驟:
上位機(jī)界面設(shè)計(jì)。
上位機(jī)邏輯代碼編寫。
添加上位機(jī)圖標(biāo)。
上位機(jī)程序的打包。
上位機(jī)測試驗(yàn)證。
1、新建一個(gè)serial_led工程





這里需要注意的一點(diǎn)是:工程名及工程路徑不要有中文字符。
另外,QT中有三種基類,這里我們選擇QWidget類。QT的三個(gè)基類如:
QMainWindow類:提供一個(gè)帶有菜單條,工具條和一個(gè)狀態(tài)條的主應(yīng)用程序窗口。
QWidget類:所有用戶界面對象的基類,窗口部件是用戶界面的一個(gè)基本單元,它從窗口系統(tǒng)接收鼠標(biāo),鍵盤和其他消息,并在屏幕上繪制自己。
QDialog類:對話框窗口的基類,對話框窗口主要用于短期任務(wù)和用戶進(jìn)行短期通訊的頂級窗口,QDialog可以是模態(tài)對話框或者是非模態(tài)對話框。
我們創(chuàng)建的工程如:

其中,項(xiàng)目文件.pro文件是用來告訴qmake關(guān)于為這個(gè)應(yīng)用程序創(chuàng)建makefile所需要的細(xì)節(jié)。例如,一個(gè)源文件和頭文件的列表、任何應(yīng)用程序特定配置。例如,一個(gè)必需鏈接的額外庫或者一個(gè)額外的包含路徑、都應(yīng)該放到項(xiàng)目文件中。
2、上位機(jī)界面設(shè)計(jì)
Qt 一個(gè)可視化的界面設(shè)計(jì)工具:Qt 設(shè)計(jì)器(Qt Designer)。我們雙擊.ui文件就可以進(jìn)入Qt Designer,在Qt Designer中我們可以通過拖動(dòng)控件的方式來設(shè)計(jì)我們的界面,整個(gè)界面如:

我們從左側(cè)的控件區(qū)把我們需要的控件拖動(dòng)到界面編輯區(qū)中,我們這個(gè)簡單地上位機(jī)用到的控件如:

這里需要注意的是波特率這個(gè)下拉框需要雙擊設(shè)置一些備選配置,如:


大家可以在左邊地控件區(qū)找到這三種控件拖動(dòng)到界面編輯器進(jìn)行修改、布局即可。
其中,布局可通過如下組件調(diào)整:

這幾個(gè)組件的功能如:

具體地用法大家可以自己去實(shí)操一下。
另外,我們需要給我們使用的控件重新命名,在右側(cè)的對象管理區(qū)進(jìn)行操作。命名為有意義的名字,因?yàn)楹竺婢帉懘a會(huì)用到。有意義的名字利于編寫易懂的代碼。比如我們修改的名字如:

最后,控件的屬性可根據(jù)需要在屬性區(qū)進(jìn)行調(diào)整。
3、上位機(jī)邏輯代碼編寫
(1)添加串口庫、包含串口相關(guān)頭文件
在serial_led.pro文件添加串口庫:
?
?
QT?+=?core?gui?serialport
?
?

在widget.h文件包含串口頭文件:
?
?
#include?#include?
?
?

QSerialPort 類提供了操作串口的各種接口。
QSerialPortInfo 是一個(gè)輔助類,可以提供計(jì)算機(jī)中可用串口的各種信息。
(2)添加QSerialPort成員
在widget.h的Widget類中添加一個(gè)QSerialPort成員:

(3)創(chuàng)建串口對象、搜索所有可用串口
在Widget構(gòu)造函數(shù)中創(chuàng)建一個(gè)串口對象并搜索所有可用串口:
Widget::Widget(QWidget?*parent)?:
????QWidget(parent),
????ui(new?Ui::Widget)
{
????QStringList?serialNamePort;
????ui->setupUi(this);
????this->setWindowTitle("serial_led");
????/*?創(chuàng)建一個(gè)串口對象?*/
????serialPort?=?new?QSerialPort(this);
????/*?搜索所有可用串口?*/
????foreach?(const?QSerialPortInfo?&inf0,?QSerialPortInfo::availablePorts())?{
????????serialNamePort<serialBox->addItems(serialNamePort);
}
?
?

(4)編寫“打開串口”槽函數(shù)



當(dāng)某個(gè)事件發(fā)生之后,比如,按鈕檢測到自己被點(diǎn)擊了一下,它就會(huì)發(fā)出一個(gè)信號(signal)。如果有對象對這個(gè)信號感興趣,想要處理的信號和自己的一個(gè)函數(shù)(稱為槽(slot))綁定來處理這個(gè)信號。也就是說,當(dāng)信號發(fā)出時(shí),被連接的槽函數(shù)會(huì)自動(dòng)被回調(diào)。
這里,我們點(diǎn)擊打開串口按鈕會(huì)發(fā)出clicked信號,此時(shí)對應(yīng)槽函數(shù)on_openButton_clicked會(huì)被調(diào)用。下面我們來實(shí)現(xiàn)這個(gè)槽函數(shù):
void?Widget::on_openButton_clicked()
{
????/*?串口設(shè)置?*/
????serialPort->setPortName(ui->serialBox->currentText());
????serialPort->setBaudRate(ui->baudrateBox->currentText().toInt());
????serialPort->setDataBits(QSerialPort::Data8);
????serialPort->setStopBits(QSerialPort::OneStop);
????serialPort->setParity(QSerialPort::NoParity);
????/*?打開串口提示框?*/
????if?(true?==?serialPort->open(QIODevice::ReadWrite))
????{
????????QMessageBox::information(this,?"提示",?"串口打開成功");
????}
????else
????{
????????QMessageBox::critical(this,?"提示",?"串口打開失敗");
????}
}
這里我們寫死數(shù)據(jù)位、停止位、求校驗(yàn)位;增加提示框。其中使用QMessageBox需要包含如下頭文件:
#include?
(5)編寫“關(guān)閉串口”、“點(diǎn)燈”、“滅燈”槽函數(shù)
按照上面打開串口槽函數(shù)的方法編寫關(guān)閉串口、點(diǎn)燈、滅燈槽函數(shù):
void?Widget::on_closeButton_clicked()
{
????serialPort->close();
}
void?Widget::on_onButton_clicked()
{
????serialPort->write("ON
");
????qDebug("ON
");
}
void?Widget::on_offButton_clicked()
{
????serialPort->write("OFF
");
????qDebug("OFF
");
}
以上就是上位機(jī)邏輯代碼的編寫。
4、添加上位機(jī)圖標(biāo)
在網(wǎng)上找一個(gè)相關(guān)的.ico后綴的圖標(biāo)下載放到我們的工程路徑下,如:

圖標(biāo)下載網(wǎng)址如:
https://www.iconfont.cn/
https://www.iconfont.cn/
然后在我們的serial_led.pro文件中添加如下一行代碼:
RC_ICONS?=?led.ico
?
?

5、上位機(jī)程序打包
我們上面運(yùn)行的上位機(jī)都是在Qt Creator中編譯運(yùn)行的,如果我們需要把編寫好的可執(zhí)行文件發(fā)送給別人使用的話還需要進(jìn)行打包。
上面我們的工程是Debug版本的:

打包之前,我們先把工程修改為Release版本:

然后在我們工程目錄下得到:

此時(shí),雙擊release文件夾下的serial_led.exe文件是會(huì)報(bào)錯(cuò)的,報(bào)錯(cuò)原因是找不到一些相關(guān)的動(dòng)態(tài)庫:

我們新建一個(gè)文件夾保存我們的打包文件,如:

把build-serial_led-Desktop_Qt_5_11_1_MinGW_32bit-Release elease路徑下的serial_led.exe文件拷貝至serial_led_packet文件夾中:

打開QT for Disktop工具:


執(zhí)行如下命令進(jìn)入打包目錄:
cd /d D:Qtqt_prjserial_ledserial_led_packet
然后執(zhí)行如下命令進(jìn)行打包:
windeployqt serial_led.exe

此時(shí),serial_led_packet文件夾中的serial_led.exe文件就可以雙擊運(yùn)行了:

此時(shí)就完成了程序的打包。此時(shí)我們把這一整個(gè)文件夾壓縮發(fā)送給別人使用了。另外,我們也可以借助一些工具把這些文件打包成一個(gè)整體的.exe文件,這里不再介紹。
6、上位機(jī)測試驗(yàn)證
上位機(jī)我們寫好了,接下來編寫下位機(jī)代碼來測試一下。
我們點(diǎn)擊上位機(jī)的點(diǎn)燈、滅燈按鈕,則會(huì)通過串口分別發(fā)送ON 、OFF ,我們編寫下位機(jī)代碼進(jìn)行接收,然后操控LED燈即可。
int?main(void)
{
??/*?USER?CODE?BEGIN?1?*/
?
??/*?USER?CODE?END?1?*/
??/*?MCU?Configuration----------------------------------------------------------*/
??/*?Reset?of?all?peripherals,?Initializes?the?Flash?interface?and?the?Systick.?*/
??HAL_Init();
??/*?USER?CODE?BEGIN?Init?*/
??/*?USER?CODE?END?Init?*/
??/*?Configure?the?system?clock?*/
??SystemClock_Config();
??/*?USER?CODE?BEGIN?SysInit?*/
??/*?USER?CODE?END?SysInit?*/
??/*?Initialize?all?configured?peripherals?*/
??MX_GPIO_Init();
??MX_DMA_Init();
??MX_USART1_UART_Init();
??/*?USER?CODE?BEGIN?2?*/
??printf("Welcome?to?UART1?test!
");
??/*?USER?CODE?END?2?*/
??/*?Infinite?loop?*/
??/*?USER?CODE?BEGIN?WHILE?*/
??while?(1)
??{
??/*?USER?CODE?END?WHILE?*/
??/*?USER?CODE?BEGIN?3?*/?
??if(HAL_UART_Receive(&huart1,?&Rdata,?1,?0)==HAL_OK)
??{
??????if?(usart_rx_buf_index?>?USART1_RX_BUF_LEN?-?1)
??????{
????????usart_rx_buf_index?=?0;
??????}
??????
??????if?(Rdata?==?0x0A)
??????{
????????if?(strcmp((char*)USART1_RX_BUF,?"ON")?==?0)
????????{
??????????HAL_GPIO_WritePin(LED_GPIO_Port,?LED_Pin,?GPIO_PIN_SET);
????????}
????????else?if?(strcmp((char*)USART1_RX_BUF,?"OFF")?==?0)
????????{
??????????HAL_GPIO_WritePin(LED_GPIO_Port,?LED_Pin,?GPIO_PIN_RESET);
????????}
????????usart_rx_buf_index?=?0;
????????memset(USART1_RX_BUF,?0,?USART1_RX_BUF_LEN);
??????}
??????else
??????{
????????USART1_RX_BUF[usart_rx_buf_index++]?=?Rdata;
??????}
??}
??}
??/*?USER?CODE?END?3?*/
}
演示如文章開頭所見。
四、總結(jié)
以上就是手把手教你編寫一個(gè)簡單的點(diǎn)燈上位機(jī)的內(nèi)容,雖然實(shí)現(xiàn)的功能很簡單,但是QT上位機(jī)開發(fā)的步驟基本就是這些步驟,通過這個(gè)基礎(chǔ)實(shí)例把這些套路摸透我們就可以接著進(jìn)行后續(xù)更多QT程序地開發(fā)學(xué)習(xí)了。
編輯:黃飛
?
電子發(fā)燒友App














評論