stm32mp157開(kāi)發(fā)板FS-MP1A是華清遠(yuǎn)見(jiàn)自主研發(fā)的一款高品質(zhì)、高性價(jià)比的Linux+單片機(jī)二合一的嵌入式教學(xué)級(jí)開(kāi)發(fā)板。開(kāi)發(fā)板搭載ST的STM32MP157高性能微處理器,集成2個(gè)Cortex-A7核和1個(gè)Cortex-M4 核,A7核上可以跑Linux操作系統(tǒng),M4核上可以跑FreeRTOS、RT-Thread等實(shí)時(shí)操作系統(tǒng)。開(kāi)發(fā)板搭配仿真器、顯示屏、攝像頭、資源擴(kuò)展板等豐富的擴(kuò)展模塊,可拓展物聯(lián)網(wǎng)、人工智能等相關(guān)技術(shù)學(xué)習(xí),還可以拓展豐富的項(xiàng)目實(shí)戰(zhàn),非常貼合企業(yè)當(dāng)下開(kāi)發(fā)需求,是一款嵌入式Linux入門(mén)進(jìn)階必備開(kāi)發(fā)板!
可學(xué)習(xí)技術(shù):嵌入式Linux應(yīng)用/系統(tǒng)/驅(qū)動(dòng)開(kāi)發(fā)、ARM裸機(jī)開(kāi)發(fā)、Qt界面編程、STM32單片機(jī)、FreeRTOS、人工智能機(jī)器視覺(jué)等。其中ARM Cortex-A7裸機(jī)開(kāi)發(fā)課程是華清遠(yuǎn)見(jiàn)獨(dú)有特色課程,可關(guān)注:https://www.bilibili.com/video/BV1Xe4y1i7vm/,持續(xù)更新中。

14個(gè)Linux+Qt綜合項(xiàng)目案例,6個(gè)MP1A物聯(lián)網(wǎng)拓展項(xiàng)目
關(guān)注公眾號(hào)“華清遠(yuǎn)見(jiàn)在線實(shí)驗(yàn)室”,回復(fù)“mp157項(xiàng)目”,即可領(lǐng)取項(xiàng)目配套文檔及源碼。
Linux+Qt綜合項(xiàng)目案例:華清遠(yuǎn)見(jiàn)stm32mp157開(kāi)發(fā)板優(yōu)勢(shì)特色部分,包括音樂(lè)播放器、智慧家庭、智能工業(yè)電表、智能出行助手、智能貓眼、環(huán)境監(jiān)測(cè)、智能安防、智能語(yǔ)音識(shí)別等10余個(gè)項(xiàng)目案例,涉及家居、醫(yī)療、農(nóng)業(yè)多種應(yīng)用方向,在案例中使用了多種物聯(lián)網(wǎng)和嵌入式技術(shù),包括OT開(kāi)發(fā)、linux應(yīng)用開(kāi)發(fā)、linux驅(qū)動(dòng)開(kāi)發(fā)、物聯(lián)網(wǎng)云端接入、MQTT協(xié)議、json字符串等知識(shí)點(diǎn)。
基于Linux+Qt的智能語(yǔ)音識(shí)別項(xiàng)目
項(xiàng)目簡(jiǎn)介:
語(yǔ)言是人與人之間最重要的交流方式、能與機(jī)器進(jìn)行自然的人機(jī)交流,是人類一直期待的事情。隨著人工智能快速發(fā)展。語(yǔ)音識(shí)別技術(shù)作為人機(jī)交流接口的關(guān)鍵技術(shù)、發(fā)展迅速。本項(xiàng)目調(diào)用百度 AI 開(kāi)發(fā)平臺(tái) API 進(jìn)行語(yǔ)音識(shí)別,進(jìn)行語(yǔ)音控制傳感器的聯(lián)動(dòng)。
開(kāi)發(fā)平臺(tái):
華清遠(yuǎn)見(jiàn)stm32mp157開(kāi)發(fā)板豪華套餐(開(kāi)發(fā)板+仿真器+五寸屏+攝像頭+資源擴(kuò)展板+tf卡+讀卡器)
項(xiàng)目實(shí)戰(zhàn):
Qt 開(kāi)發(fā)環(huán)境搭建
主機(jī)開(kāi)發(fā)環(huán)境說(shuō)明
1) 本文檔主要介紹 linux 環(huán)境下的 Qt 程序開(kāi)發(fā);
2) 主機(jī) Qt 版本為 5.14.1;
主機(jī) Qt 環(huán)境搭建及使用
Qt Creator 安裝
將 qt-creator-opensource-linux-x86_64-4.10.1.run(Qt 實(shí)驗(yàn)源碼\工具軟件) 復(fù)制到 ubuntu 主機(jī)中,可以采用共享文件夾的方式也可以使用 tfp方式將文 件存入家目錄下的 Downloads 目錄。我們需要在終端中賦予安裝程序可執(zhí)行的權(quán)限

我們可以使用圖形化的文件管理器來(lái)查看

雙擊“qt-creator-opensource-linux-x86_64-4.10.1.run”圖標(biāo)運(yùn)行安裝程序。出現(xiàn)如下界面:
等待程序驗(yàn)證完成后點(diǎn)擊“Next”

這里我們需要登錄或者注冊(cè)一個(gè)賬號(hào),如果我們之前已經(jīng)注冊(cè)過(guò)直接登錄就可以。如果沒(méi)有注冊(cè)過(guò)則需要新注冊(cè)有一個(gè)賬號(hào)后登錄。這里筆者已經(jīng)注冊(cè)過(guò)賬號(hào),所以直接登錄。 登錄成功后出現(xiàn)如下界面,點(diǎn)擊 Next

這里選擇安裝路徑

可以直接默認(rèn),Next

這路選擇安裝的組件,直接默認(rèn)即可

這里我們需要同意用戶協(xié)議

這個(gè)界面告訴我們安裝完成后需要占用的空間。點(diǎn)擊”Install”按鈕后開(kāi)始安裝。

安裝完成后出現(xiàn)如下界面
點(diǎn)擊“Finish”按鈕后將彈出 Qt Creator 主界面
點(diǎn)擊“Cancel”按鈕后即可正常使用
Qt5.14.1 安裝
復(fù)制到 qt-opensource-linux-x64-5.14.1.run(Qt 實(shí)驗(yàn)源碼\工具軟件)到 ubuntu 主機(jī)中,可以采用共享文件夾的方式也可以使用 tfp 方式將文件存入家目錄下的 Downloads 目錄。進(jìn)入所在文件夾,先給執(zhí)行權(quán)限
輸入命令
chmod +x ./qt-opensource-linux-x64-5.14.1.run
安裝在命令行輸入
./qt-opensource-linux-x64-5.14.1.run
會(huì)有可視化引導(dǎo)安裝,一直 next 就行了
在選擇安裝組件的時(shí)候要是不知道選擇那些就全選了 大概有 4 個(gè) G 左右
下載 gcc 和 g++
sudo apt-get install gcc g++
下載 cmake
sudo apt-get install cmake
下載鏈接庫(kù)
sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev
Qt Creator 配置
1)配置 GCC
運(yùn)行 QtCreator 后,依次點(diǎn)擊"Tool"->"Options",出現(xiàn)選項(xiàng)對(duì)話框,在左側(cè)點(diǎn)擊"Kits",右 邊選擇"Compilers"標(biāo)簽。 檢查有沒(méi)有下圖標(biāo)注的 C++和 C ,般按上面步驟執(zhí)行后都會(huì)有

點(diǎn)擊右側(cè)"Add"按鈕,彈出下拉列表后,選擇"GCC"的"C"

填寫(xiě)信息如下,"Name"為"Auto-GCC","Compiler path"點(diǎn)擊旁邊的"Browse.."按鈕選擇編譯器的路徑,例子中的路徑是 “/usr/bin/gcc”
2)配置 G++
點(diǎn)擊右側(cè)"Add"按鈕,彈出下拉列表后,選擇"GCC"的"C++",下面的文本框填寫(xiě)"Name" 為"Auto-G++","Compiler path"點(diǎn)擊旁邊的"Browse.."按鈕選擇編譯器的路徑,例子中的路徑是" /usr/bin/g++"。
填寫(xiě)完成后,點(diǎn)擊"Apply"。
3)配置 qmake
選擇"Qt Versions"標(biāo)簽,如果有下面紅框中的文本,可以跳過(guò)下面步驟

如果沒(méi)有,在右側(cè)點(diǎn)擊"Add..."

會(huì)彈出 qmake 路徑選擇對(duì)話框,這里以"/home/linux/Qt5.14.1/5.14.1/gcc_64/bin/qmake"為例子。 選擇”qmake”文件后,點(diǎn)擊"Open"按鈕

"Version name"改為" Qt %{Qt:Version} GCC"。然后點(diǎn)擊"Apply"按鈕。
4)配置 Kits
點(diǎn)擊左側(cè)"Kits",右側(cè)選擇"Kits"標(biāo)簽。檢查有沒(méi)有下圖紅框選中的文本,如果有可以跳過(guò)下面步驟

然后沒(méi)有,點(diǎn)擊 Add:
在彈出的對(duì)話框中"Name"為"Desktop","Device Type"選擇"Desktop"選項(xiàng), "Sysroot"選擇目標(biāo)設(shè)備的系統(tǒng)目錄,"Compiler"選擇之前配置的名稱"Auto-GCC"和"Auto-G++","Qt version"選擇之前配 置的名稱"Qt 5.14.1GCC",其它默認(rèn)即可,最后點(diǎn)擊"Apply"和"OK"按鈕。
Qt Creator 新建工程
注意:工程路徑最好不要包含中文、特殊字符、空格等。
我們可以新建一個(gè)“qt”文件夾,該文件夾用作我們以后存放源代碼。
打開(kāi) Qt Creator,在歡迎頁(yè)面點(diǎn)擊 “New”按鈕,來(lái)新建一個(gè)工程。
在出現(xiàn)的新建項(xiàng)目窗口中,我們選則“Application”->“Qt WidgetsApplication”,然后點(diǎn)擊右下方“Choose…”按鈕,來(lái)創(chuàng)建一個(gè)桌面 Qt 應(yīng)用。

我們?cè)谶@里設(shè)置項(xiàng)目介紹和源碼位置,我們這里創(chuàng)建一個(gè)名為“HelloWorld”的示例項(xiàng)目,設(shè)置完成之后點(diǎn)擊 next

直接點(diǎn)擊 next

隨后進(jìn)行細(xì)節(jié)設(shè)置,主要設(shè)置要?jiǎng)?chuàng)建的源碼文件的基本類信息,包括類名等。這里我們可以根據(jù)自己的項(xiàng)目特點(diǎn)進(jìn)行設(shè)置。需要說(shuō)明的一點(diǎn)就是基類的選擇,這里基類有 QMainWindow、QWidget、QDialog 三種,它們的不同之處如下:
QMainWindow 類提供一個(gè)帶有菜單條,工具條和一個(gè)狀態(tài)條的主應(yīng)用程序窗口。主窗口通常提供一個(gè)大的中央窗口部件,以及周圍菜單,工具條,和一個(gè)狀態(tài)欄。QMainWindow 窗口經(jīng)常被繼承,使得封裝中央部件,菜單,工具條,狀態(tài)欄等都變得很容易,當(dāng)用戶點(diǎn)擊它的時(shí)候,相應(yīng)的槽就會(huì)被調(diào)用;
QWidget 類是所有用戶界面對(duì)象的基類,窗口部件是用戶界面的一個(gè)基本單元,它從窗口系統(tǒng)接收鼠標(biāo),鍵盤(pán)和其他消息,并在屏幕上繪制自己。一個(gè)窗口部件可以被他的父窗口或者是其他窗口擋住一部分;
QDialog 類是對(duì)話框窗口的基類,對(duì)話框窗口主要用于短期任務(wù)和用戶進(jìn)行短期通訊的頂級(jí)窗口,QDialog 可以是模態(tài)對(duì)話框或者是非模態(tài)對(duì)話框。QDialog 支持?jǐn)U展并帶有返回值,他們可以帶有默認(rèn)值;我們?cè)谶@里選擇 QDialog 類即可,點(diǎn)擊 next 完成類信息設(shè)置。
直接點(diǎn)擊 next 按鈕即可。
然后進(jìn)行工具選擇,該頁(yè)面可以選擇我們創(chuàng)建的工程可以使用的工具,選擇想要使用的編譯器模塊,例如下圖 。點(diǎn)擊 next

最后我們?cè)O(shè)置匯總信息,如果不需要版本控制等功能,直接點(diǎn)擊完成finish 即可。

隨后我們就進(jìn)入到了主界面,這時(shí)候 Qt 已經(jīng)幫我們做好了一些準(zhǔn)備工作,包括創(chuàng)建了一些文件,寫(xiě)好了一些前置代碼等等。
我們可以點(diǎn)擊左邊 protect 欄,來(lái)查看我們的編譯選項(xiàng)。

我們可以在左下角選擇編譯 Debug 版或者 Release 版,即調(diào)試版或發(fā)行版。
左下角綠色剪頭是編譯并運(yùn)行,錘子是僅編譯,我們可以直接點(diǎn)擊綠色小箭頭將我們導(dǎo)入的工程編譯并運(yùn)行起來(lái)。
點(diǎn)擊運(yùn)行按鈕后,我們可以看到 HelloWorld 窗口運(yùn)行起來(lái)了。
Qt Creator導(dǎo)入工程
我們可以將已存在的 Qt 程序項(xiàng)目直接打開(kāi),這里以上一章節(jié)的HelloWorld 程序?yàn)槔?。首先我們確定源碼存在的位置,如 HelloWorld 程序源碼在 /home/linux/qt/helloworld 路徑下
點(diǎn)擊歡迎頁(yè)面的“Open” 按鈕可以打開(kāi)已有的工程
找到我們剛才解壓好的源碼,選擇“helloworld.pro”文件并點(diǎn)擊打開(kāi)

接下來(lái)我們就可以進(jìn)入到代碼編輯界面了。

左上角是項(xiàng)目欄,點(diǎn)擊項(xiàng)目名稱左邊的小箭頭可以展開(kāi)項(xiàng)目目錄

我們可以點(diǎn)擊左邊項(xiàng)目欄,來(lái)查看我們的編譯選項(xiàng)。需注意的是構(gòu)建設(shè)置中的路徑應(yīng)與工程路徑處于同級(jí)目錄下。

我們可以在左下角選擇編譯 Debug 版或者 Release 版,即調(diào)試版或發(fā)行版。
左下角綠色剪頭是編譯并運(yùn)行,錘子是僅編譯,我們可以直接點(diǎn)擊綠色小箭頭將我們導(dǎo)入的工程編譯并運(yùn)行起來(lái)
點(diǎn)擊運(yùn)行按鈕后,我們可以看到 HelloWorld 窗口運(yùn)行起來(lái)了。
文件說(shuō)明
通過(guò)上面兩個(gè)章節(jié),我們學(xué)習(xí)到了 Qt 程序的新建與導(dǎo)入的方法,也知道了Qt 會(huì)幫我們做一些基礎(chǔ)工作,比如幫我們建立了一些文件,那么這些文件都是干什么用的呢?我們以 HelloWorld 程序來(lái)說(shuō)明一下。

以“.pro”為后綴名的文件,為 Qt 的項(xiàng)目管理文件,存儲(chǔ)項(xiàng)目設(shè)置的文件;

“Qt += core gui”表示項(xiàng)目中加入 core gui 模塊。core gui 是 Qt 用于GUI 設(shè)計(jì)的類庫(kù)模塊,如果創(chuàng)建的是控制臺(tái)(console)應(yīng)用程序,就不需要添加 core gui。
Qt 類庫(kù)以模塊的形式組織各種功能的類,根據(jù)項(xiàng)目涉及的功能需求,在項(xiàng)目中添加適當(dāng)?shù)念悗?kù)模塊支持。例如,如果項(xiàng)目中使用到了涉及數(shù)據(jù)庫(kù)操作的類就需要用到 sql(數(shù)據(jù)庫(kù))模塊,在 pro 文件中需要在后面加上 sql:
1 Qt += core gui sql
“greaterThan(QT_MAJOR_VERSION, 4): QT += widgets”,這是個(gè)條件執(zhí)行語(yǔ)句,表示當(dāng) Qt 主版本大于 4 時(shí),才加入 widgets 模塊?!癟ARGET = HelloWorld”表示生成的目標(biāo)可執(zhí)行文件的名稱,即編譯后生成的可執(zhí)行文件是 HelloWorld.exe。
“TEMPLATE = app”表示項(xiàng)目使用的模板是 app,是一般的應(yīng)用程序。
后面的 SOURCES、HEADERS、FORMS 記錄了項(xiàng)目中包含的源程序文件、頭文件和窗體文件(.ui 文件)的名稱。這些文件列表是 Qt Creator 自動(dòng)添加到項(xiàng)目管理文件里面的,用戶不需要手動(dòng)修改。當(dāng)添加一個(gè)文件到項(xiàng)目,或從項(xiàng)目里刪除一個(gè)文件時(shí),項(xiàng)目管理文件里的條目會(huì)自動(dòng)修改。
文件夾“Header”中,存放的是所設(shè)計(jì)的窗體類的頭文件;
文件夾“Sources”中,存放著源碼文件。main.cpp 是實(shí)現(xiàn) main()函數(shù)的程序文件,HelloWorld.cpp 是 widget.h 里定義類的實(shí)現(xiàn)文件。C++中,任何窗體或界面組件都是用類封裝的,一個(gè)類一般有一個(gè)頭文件(.h 文件)和一個(gè)源程序文件(.cpp 文件);
文件夾“Forms”中,存放著界面設(shè)計(jì)文件,“.ui”文件是一個(gè) XML 格式存儲(chǔ)的窗體上的元件及其布局的文件,雙擊項(xiàng)目文件目錄樹(shù)中的文件 ui,會(huì)打開(kāi)一個(gè)集成在 Qt Creator 中的 Qt Designer 對(duì)窗體進(jìn)行可視化設(shè)計(jì);
UI 設(shè)計(jì)器有以下一些功能區(qū)域:
組件面板:窗口左側(cè)是界面設(shè)計(jì)組件面板,分為多個(gè)組,如 Layouts、Buttons、Display Widgets 等,界面設(shè)計(jì)的常見(jiàn)組件都可以在組件面板里找到。
中間主要區(qū)域是待設(shè)計(jì)的窗體。如果要將某個(gè)組件放置到窗體上時(shí),從組件面板上拖放一個(gè)組件到窗體上即可。
Signals 和 Slots 編輯器與 Action 編輯器是位于待設(shè)計(jì)窗體下方的兩個(gè)編輯器。Signals 和 Slots 編輯器用于可視化地進(jìn)行信號(hào)與槽的關(guān)聯(lián),Action 編輯器用于可視化設(shè)計(jì) Action。
布局和界面設(shè)計(jì)工具欄:窗口上方的一個(gè)工具欄,工具欄上的按鈕主要實(shí)現(xiàn)布局和界面設(shè)計(jì)。
對(duì)象瀏覽器(Object Inspector):窗口右上方是 Object Inspector,用樹(shù)狀視圖顯示窗體上各組件之間的布局包含關(guān)系,視圖有兩列,顯示每個(gè)組件的對(duì)象名稱(ObjectName)和類名稱。
屬性編輯器(Property Editor):窗口右下方是屬性編輯器,是界面設(shè)計(jì)時(shí)最常用到的編輯器。屬性編輯器顯示某個(gè)選中的組件或窗體的各種屬性及其取值,可以在屬性編輯器里修改這些屬性的值。屬性編輯器的內(nèi)容分為兩列,左側(cè)為屬性的名稱,右側(cè)為屬性的值。屬性又分為多個(gè)組,實(shí)際上表示了類的繼承關(guān)系,位于下方的類屬性組繼承自位于上方的類屬性組;
如果我們需要新建資源文件、源碼文件等,可以在項(xiàng)目文件夾出點(diǎn)擊鼠標(biāo)右鍵,選擇 Add New;如果我們有新的文件需要添加,可以在項(xiàng)目文件夾出點(diǎn)擊鼠標(biāo)右鍵,選擇 Add Existing Files。

幫助文檔
Qt 的幫助文檔是伴隨我們學(xué)習(xí) Qt 開(kāi)發(fā)的好伙伴。在 Qt 開(kāi)發(fā)過(guò)程中,我們會(huì)面臨圖形接口使用的問(wèn)題,它不像 C 語(yǔ)言那樣就那么幾個(gè)函數(shù)接口,圖形接口的接口數(shù)量可以用海量來(lái)形容,常用的我們可能能記住,其它的就沒(méi)有必要去記了,用到什么就去幫助文檔查看用法是比較方便的。我們可以按 F1 按鍵,或通過(guò)上方導(dǎo)航欄的“help->contects”來(lái)進(jìn)入幫助文檔。

上方的前進(jìn)后退按鈕方便我們查看文檔,如返回到上一步,返回到下一步。
我們可以通過(guò)幫助文檔來(lái)查看以下幾個(gè)部分:
類使用的相關(guān)介紹;
查看相關(guān)類的使用介紹,我們可以先進(jìn)入到幫助文檔,然后在左上角選擇“Search”。筆者這里以 QWidget 類為例,輸入我們想要查找的類的名字,然后雙擊查找結(jié)果來(lái)查看說(shuō)明。

也可以先將鼠標(biāo)移動(dòng)到想要查詢的類的位置,如圖所示,將鼠標(biāo)移動(dòng)至“QWidget”處,然后按“F1”鍵,即可跳轉(zhuǎn)到相應(yīng)的幫助文檔。
我們可以通過(guò)再按一次“F1”鍵來(lái)全窗口查看幫助文檔,按“Esc”鍵可以退出。

部分常用的成員元素包括以下幾項(xiàng):
公有成員函數(shù):操作部件屬性的相關(guān)函數(shù);
公有槽函數(shù):Qt 類中已經(jīng)定義好的槽函數(shù),直接可與信號(hào)相連接;
信號(hào):軟中斷,如按下按鈕觸發(fā) pressed() 信號(hào)等;
保護(hù)成員函數(shù):通常事件所對(duì)應(yīng)的虛函數(shù)放在此處;
事件:常用事件,如操作鼠標(biāo)觸發(fā)的鼠標(biāo)事件;
滾動(dòng)鼠標(biāo)滾輪,向下即可看到“Qwdget Class”類的相關(guān)說(shuō)明了。
部分常用的成員元素包括以下幾項(xiàng):
公有成員函數(shù):操作部件屬性的相關(guān)函數(shù);
公有槽函數(shù):Qt 類中已經(jīng)定義好的槽函數(shù),直接可與信號(hào)相連接;
信號(hào):軟中斷,如按下按鈕觸發(fā) pressed() 信號(hào)等;
保護(hù)成員函數(shù):通常事件所對(duì)應(yīng)的虛函數(shù)放在此處;
事件:常用事件,如操作鼠標(biāo)觸發(fā)的鼠標(biāo)事件;
滾動(dòng)鼠標(biāo)滾輪,向下即可看到“Qwdget Class”類的相關(guān)說(shuō)明了。

1) 查看所用的部件的相應(yīng)成員函數(shù)。
我們可以查找到該類所用部件的相應(yīng)成員函數(shù)的使用方法、功能、參數(shù)、返回值等等,我們以“按鈕”控件,即“QPushButton Class”類為例,我們通過(guò)索引搜索的方式,來(lái)找到這個(gè)類
我們可以通過(guò)點(diǎn)擊“Public Functions” 來(lái)查看“QPushButton”這個(gè)類中的成員函數(shù)。
這里以“QPushButton(const QString &text, QWidget *parent =Q_NULLPTR)”為例,我們點(diǎn)擊函數(shù)名字可以進(jìn)入到函數(shù)詳情中。我們可以看到相應(yīng)的描述為:以“text”為顯示內(nèi)容,以“parent”為父對(duì)象,構(gòu)造一個(gè)push 按鈕?!皌ext”“parent”為函數(shù)參數(shù),由于是構(gòu)造函數(shù),所以此函數(shù)沒(méi)有返回值。
還有一些函數(shù)是繼承自其它類的,例如“Public Functions”中有 21 個(gè)繼承自“QAbstractButton”類的函數(shù),我們點(diǎn)擊“QAbstractButton”即可查看。擊“QAbstractButton”即可查看

同樣我們可以點(diǎn)擊相應(yīng)的函數(shù)進(jìn)入查看詳情。如查看“voidsetText(const QString &text)”。

2) 查看所用的部件的信號(hào)。
我們這里還是以“PushButton”為例,我們點(diǎn)擊“Public Slots”。

可以看到“PushButton”本身有一個(gè)“void showMenu()”的信號(hào),并且有很多繼承自其他類的信號(hào)。
一般來(lái)說(shuō)我們用的“PushButton”的信號(hào),最多的是用到其繼承自基類“QAbstractButton”中的幾個(gè)信號(hào),分別是點(diǎn)擊(按下后抬起)、按壓(單按下)、釋放(單抬起)等
我們可以點(diǎn)擊相應(yīng)信號(hào)查看詳情
3) 查看所用的部件的事件(所對(duì)應(yīng)的虛函數(shù)如何編寫(xiě))。部件常用事件主要在 “QWidget”中聲明,選擇“Events”即可查看相關(guān)說(shuō)明。
每個(gè)事件都對(duì)應(yīng)著事件函數(shù)。
點(diǎn)擊事件函數(shù)可查看詳情
UI 界面設(shè)計(jì)
Ui 界面設(shè)計(jì)如下:
由于我們配置的七寸屏幕是 1024*768 分辨率的,所以我們的 MainWindow主界面的尺寸設(shè)置為 1024*768。共使用如下幾個(gè)控件,使用 QTextEdit 控件textEdit 來(lái)顯示語(yǔ)音識(shí)別后返回的最佳匹配語(yǔ)音。使用 QPushButton 控件pushButton_video 點(diǎn)擊錄音和釋放識(shí)別,使用 pushButton_clear 來(lái)清空 QtextEdit的內(nèi)容,使用 textEdit_2 來(lái)顯示傳感器的反饋。


錄音
在 pro 文件添加
QT += network
QT += multimedia
在 mainwindow.h 頭文件添加下面定義
void RecorderStart(QString fileName);//開(kāi)始錄音
void RecorderEnd();//結(jié)束錄音并轉(zhuǎn)換格式
QFile *outFile;//錄音時(shí)的變量
QAudioInput *my_audio;//錄音時(shí)的變量
QAudioFormat audioFormat;//錄音時(shí)的變量
Mainwindow.cpp 錄音函數(shù)實(shí)現(xiàn):
void MainWindow::RecorderStart(QString fileName)
{
QAudioDeviceInfo device = QAudioDeviceInfo::defaultInputDevice();
if(device.isNull())
{
QMessageBox::warning(NULL,"QAudioDeviceInfo","錄音設(shè)備不存
在");
return;
}
// 設(shè)置通道數(shù)
audioFormat.setChannelCount(1);
// 設(shè)置編碼
audioFormat.setCodec("audio/pcm");
// 設(shè)置采樣頻率
audioFormat.setSampleRate(16000);
// 設(shè)置位深
audioFormat.setSampleSize(16);
// 判斷設(shè)備是否支持該格式
if(!device.isFormatSupported(audioFormat)){ //當(dāng)前使用設(shè)備是否支持
audioFormat = device.nearestFormat(audioFormat); //轉(zhuǎn)換為最接近格
式
}
// 創(chuàng)建錄音對(duì)象
my_audio = new QAudioInput(audioFormat,this);
outFile = new QFile;
outFile->setFileName(fileName); //語(yǔ)音原始文件
outFile->open(QIODevice::WriteOnly);
// 開(kāi)始錄音
my_audio->start(outFile);
}
結(jié)束錄音函數(shù)實(shí)現(xiàn)
/**********************
* 結(jié)束錄音并轉(zhuǎn)換格式
**********************/
void MainWindow::RecorderEnd()
{
// 結(jié)束錄音
my_audio->stop();
outFile->close();
delete outFile;
outFile =NULL;
delete my_audio;
my_audio = NULL;
}
點(diǎn)擊釋放按鈕槽函數(shù)
右鍵按鈕,轉(zhuǎn)到槽,選擇 pressed 和 released 點(diǎn)擊 ok。會(huì)在 mainwindow.cpp
生成 on_pushButton_video_pressed()和 on_pushButton_video_released()槽函數(shù)。
在兩個(gè)槽函數(shù)分別實(shí)現(xiàn)如上圖所示
申請(qǐng)百度 AI 開(kāi)發(fā)平臺(tái)語(yǔ)音識(shí)別應(yīng)用
語(yǔ)音識(shí)別是利用百度的 API 在線識(shí)別。所以需要申請(qǐng)項(xiàng)目 ID。
進(jìn)入百度的 API 平臺(tái):https://ai.baidu.com/
在產(chǎn)品服務(wù)下選擇語(yǔ)音識(shí)別:

點(diǎn)擊立即使用:

申請(qǐng)賬號(hào)點(diǎn)擊登錄:

點(diǎn)擊創(chuàng)建應(yīng)用:

輸入應(yīng)用名稱、應(yīng)用描述,點(diǎn)擊立即創(chuàng)建:

點(diǎn)擊返回應(yīng)用列表:

獲取 AppID、API Key 和 Secret Key:

我們記住其中的 API Key 和 Secret Key,下面會(huì)用到。
HTTP 請(qǐng)求類實(shí)現(xiàn)
我們錄好的音頻文件需要通過(guò) HTTPS 協(xié)議上傳到百度 AI 開(kāi)發(fā)平臺(tái)進(jìn)行語(yǔ)音識(shí)別,之后 AI 平臺(tái)會(huì)返回給我們識(shí)別的結(jié)果。
http 類只需要封裝一個(gè)方法
bool post_sync(QString url,QMap<QString,QString>header,QByteArray
requestData,QByteArray &replyData);
使用這個(gè)方法去 URL 發(fā)送請(qǐng)求會(huì)收到 URL 的返回值。
http.h
#ifndef HTTP_H
#define HTTP_H
#include <QObject>
#include <QMap>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>
class Http : public QObject
{
Q_OBJECT
public:
explicit Http(QObject *parent = nullptr);
bool post_sync(QString url,QMap<QString,QString>header,QByteArray
requestData,QByteArray &replyData);
};
#endif // HTTP_H
http.cpp
這個(gè)方法的第一個(gè)參數(shù)是 post 方法發(fā)送請(qǐng)求的 URL,第二個(gè)參數(shù)是請(qǐng)求的方法頭,第三個(gè)參數(shù)是請(qǐng)求的數(shù)據(jù),第四個(gè)參數(shù)是返回的數(shù)據(jù)。
這里要說(shuō)的是必須要設(shè)置 openssl 簽名配置,否則在 ARM 上會(huì)報(bào)錯(cuò)。
bool Http::post_sync(QString url,QMap<QString,QString>header,QByteArray
requestData,QByteArray &replyData)
{
// 發(fā)送請(qǐng)求的對(duì)象
QNetworkAccessManager manager;
// 請(qǐng)求 對(duì)象
QNetworkRequest request;
request.setUrl(url);
QMapIterator<QString,QString> it(header);
while (it.hasNext()) {
it.next();
request.setRawHeader(it.key().toLatin1() ,it.value().toLatin1());
}
//設(shè)置 openssl 簽名配置,否則在 ARM 上會(huì)報(bào)錯(cuò)
QSslConfiguration conf = request.sslConfiguration();
conf.setPeerVerifyMode(QSslSocket::VerifyNone);
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
conf.setProtocol(QSsl::TlsV1_0);
#else
conf.setProtocol(QSsl::TlsV1);
#endif
request.setSslConfiguration(conf);
QNetworkReply *reply = manager.post(request,requestData);
QEventLoop l;
//一旦服務(wù)器返回,reply 會(huì)發(fā)出信號(hào)
connect(reply,&QNetworkReply::finished,&l,&QEventLoop::quit);
l.exec();
if(reply != nullptr && reply->error() == QNetworkReply::NoError)
{
replyData = reply->readAll();
return true;
}
else
{
qDebug()<<"request error!";
return false;
}
}
發(fā)送請(qǐng)求
這里需要向兩個(gè) URL 發(fā)送兩個(gè)請(qǐng)求,第一個(gè)請(qǐng)求是把我們 4.2.3 創(chuàng)建應(yīng)用得到的 API Key 和 Secret Key 組合成一個(gè) URL 獲取 access_token,第二個(gè)請(qǐng)求是把音頻文件發(fā)送請(qǐng)求到語(yǔ)音識(shí)別的 URL 才能返回語(yǔ)音識(shí)別的結(jié)果。
我們新建一個(gè)類 Speech
Speech.h
這里我們把 API Key 和 Secret Key 作為參數(shù)傳到 const QString
baiduTokenUrl 里面去。把主機(jī)名和獲取的 access_token 做為參數(shù)傳入 const
QString baiduSpeechUrl。
#include <QObject>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QFile>
#include "http.h"
#include <QHostInfo>
// 獲取 Access Token
const QString baiduTokenUrl =
"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=
%1&client_secret=%2&";
const QString client_id = "我們創(chuàng)建應(yīng)用的 API Key";
const QString client_secret = "我們創(chuàng)建應(yīng)用的 Secret Key";
// 語(yǔ)音識(shí)別 url
const QString baiduSpeechUrl =
"https://vop.baidu.com/server_api?dev_pid=1537&cuid=%1&token=%2";
class Speech:public QObject
{
Q_OBJECT
public:
Speech();
QString speechIdentify(QString fileName);
private:
QString getJsonValue(QByteArray ba,QString key);
};
#endif // SPEECH_H
Speech.cpp
QString Speech::speechIdentify(QString fileName)
{
// 獲取 Access Token
QString tokenUrl =QString(baiduTokenUrl).arg(client_id).arg(client_secret);
Http my_http;
QMap<QString,QString>header;
header.insert(QString("Content-Type"),QString("audio/pcm;rate=16000"));
QByteArray requestData;//請(qǐng)求內(nèi)容
QByteArray replyData;//url 返回內(nèi)容
qDebug()<<tokenUrl;
bool result = my_http.post_sync(tokenUrl,header,requestData,replyData);
if(result) {
QString key = "access_token";
QString accessToken =getJsonValue(replyData,key);
qDebug()<<accessToken;
// 語(yǔ)音識(shí)別
QString speechUrl =
QString(baiduSpeechUrl).arg(QHostInfo::localHostName()).arg(accessToken);
QFile file;
file.setFileName(fileName);
file.open(QIODevice::ReadOnly);
requestData = file.readAll();
file.close();
replyData.clear();
// 再次發(fā)起請(qǐng)求
result = my_http.post_sync(speechUrl,header,requestData,replyData);
if(result) {
QString key = "result";
QString retText =getJsonValue(replyData,key);
qDebug()<<retText;
return retText;
}
else{
return NULL;
}
}
else {
return "error";
}
}
解析返回的數(shù)據(jù)
返回的數(shù)據(jù)是這種 Json 類型的,我們只需要獲取里邊 result 的值就能得到我們想要的結(jié)果了。
{"err_no":0,"err_msg":"success.","corpus_no":"15984125203285346378","sn":"
481D633F-73BA-726F-49EF-8659ACCC2F3D","result":["北京天氣"]}
QString Speech::getJsonValue(QByteArray ba,QString key)
{
QJsonParseError parseError;
QJsonDocument jsondocument =
QJsonDocument::fromJson(ba,&parseError);
if(parseError.error ==QJsonParseError::NoError)
{
if(jsondocument.isObject())
{
QJsonObject jsonObject = jsondocument.object();
if(jsonObject.contains(key)){
QJsonValue jsonvalue = jsonObject.value(key);
if(jsonvalue.isString())
return jsonvalue.toString();
else if(jsonvalue.isArray()){
QJsonArray arr = jsonvalue.toArray();
QJsonValue val =arr.at(0);
return val.toString();
}
}
}
}
return "";
}
MainWindow 類調(diào)用函數(shù)
我們?cè)卺尫虐粹o的槽函數(shù)里添加以下代碼。
void MainWindow::on_pushButton_video_released()
{
ui->pushButton_video->setText("按住說(shuō)話");
RecorderEnd();
Speech my_speech;
QString text =my_speech.speechIdentify("./1.pcm");
ui->textEdit->append(text);
audioCtrl(text);
}
語(yǔ)音控制設(shè)備聯(lián)動(dòng)
代碼如下
void MainWindow::audioCtrl(QString text)
{
if(text == "開(kāi)燈。")
{
system("echo 1 >/sys/class/leds/user1/brightness");
system("echo 1 >/sys/class/leds/user2/brightness");
system("echo 1 >/sys/class/leds/user3/brightness");
ui->textEdit_2->setText("燈已打開(kāi)");
}
else if(text == "關(guān)燈。")
{
system("echo 0 >/sys/class/leds/user1/brightness");
system("echo 0 >/sys/class/leds/user2/brightness");
system("echo 0 >/sys/class/leds/user3/brightness");
ui->textEdit_2->setText("燈已關(guān)閉");
}
else if(text == "報(bào)警。")
{
int fd;
struct input_event event;
struct timeval time;
fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);
event.type = EV_SND;
event.code = SND_TONE;
event.value = 1000;
time.tv_sec = 1;
time.tv_usec = 0;
event.time = time;
write(fd, &event, sizeof(struct input_event));
ui->textEdit_2->setText("蜂鳴器已報(bào)警");
}
else if(text == "關(guān)閉。")
{
int fd;
struct input_event event;
struct timeval time;
fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);
event.type = EV_SND;
event.code = SND_TONE;
event.value = 0;
time.tv_sec = 0;
time.tv_usec = 0;
event.time = time;
write(fd, &event, sizeof(struct input_event));
ui->textEdit_2->setText("蜂鳴器報(bào)警已關(guān)閉");
}
else if(text == "關(guān)風(fēng)扇。")
{
unsigned char arg;
Ioctl(EXIT_FAN,&arg);
ui->textEdit_2->setText("風(fēng)扇已關(guān)閉");
}
else if(text == "開(kāi)風(fēng)扇。")
{
unsigned char arg;
Ioctl(EXIT_FAN,&arg);
Ioctl(INIT_FAN,&arg);
Ioctl(FAN_UP,&arg);
ui->textEdit_2->setText("風(fēng)扇已打開(kāi)");
}
else if(text == "溫度。")
{
QString tem = temCollect();
ui->textEdit_2->setText(QString(" 此 時(shí) 溫 度
為:").append(tem).append("'C"));
}
else if(text == "濕度。")
{
QString hum = humCollect();
ui->textEdit_2->setText(QString(" 此時(shí)濕度
為:").append(hum).append("%"));
}
}
實(shí)驗(yàn)源碼
源碼路徑【10_智能語(yǔ)音識(shí)別\實(shí)驗(yàn)源碼\04-Aivideo】
注意事項(xiàng)
1.在開(kāi)發(fā)板運(yùn)行時(shí),需要導(dǎo)入中文字庫(kù),否則會(huì)因?yàn)樽R(shí)別不了中文。
將【10_智能語(yǔ)音識(shí)別\工具軟件\wqy-zenhei-0.9.47-
nightlybuild.tar.gz 或 wqy-zenhei-0.8.38-1.tar.gz】復(fù)制到 ubuntu 下。并使用 scp 命令將文件拷貝到開(kāi)發(fā)板的 usr/share/fonts 目錄下,使用 tar 命令解壓后即可。
linux@ubuntu:~$ scp wqy-zenhei-0.8.38-1.tar.gz
root@192.168.10.128:/usr/share/fonts/

2.如果使用 mipi 五寸屏運(yùn)行此項(xiàng)目,需要進(jìn)行屏幕旋轉(zhuǎn)以適應(yīng)屏幕,具體步驟如下:
在/etc/profile.d/qt-eglfs.sh 添加環(huán)境變量如下


下面變量的 event0 設(shè)備需要填實(shí)際的觸摸屏設(shè)備

這里即填 event0
export QT_QPA_EGLFS_ROTATION=90
export QT_QPA_EGLFS_NO_LIBINPUT=1
export文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-780979.html
QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0:rotate=90文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-780979.html
到了這里,關(guān)于嵌入式linux物聯(lián)網(wǎng)畢業(yè)設(shè)計(jì)項(xiàng)目智能語(yǔ)音識(shí)別基于stm32mp157開(kāi)發(fā)板的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!