linux開(kāi)發(fā)板物聯(lián)網(wǎng)項(xiàng)目實(shí)戰(zhàn)之環(huán)境檢測(cè)學(xué)生畢業(yè)設(shè)計(jì)首選
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入門進(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的環(huán)境檢測(cè)項(xiàng)目
項(xiàng)目功能介紹:
(1)設(shè)計(jì)有環(huán)境監(jiān)測(cè)功能,通過(guò)溫濕度、光照傳感器實(shí)時(shí)采集環(huán)境溫度、濕度、光照顯示到 LCD 屏上。
(2)設(shè)計(jì)有設(shè)備控制功能,通過(guò)控制觸摸屏來(lái)進(jìn)行控制 3 個(gè) LED 燈、風(fēng)扇、蜂鳴器。
(3)設(shè)計(jì)智能檢測(cè)功能,用戶可以根據(jù)自己的需求修改智能檢測(cè)的閾值,開(kāi)啟智能檢測(cè)后,當(dāng)環(huán)境達(dá)到閾值后會(huì)啟動(dòng)設(shè)備。比如設(shè)置溫度閾值為 28 攝氏度,當(dāng)環(huán)境溫度達(dá)到 28 攝氏度時(shí),會(huì)自動(dòng)開(kāi)啟風(fēng)扇。設(shè)置一級(jí)照明為 50lux,二級(jí)照明為 30lux,三級(jí)照明為 1lux,當(dāng)光照強(qiáng)度小于 50lux 會(huì)開(kāi)啟一個(gè) led 燈,小于 30lux 會(huì)開(kāi)啟 2 個(gè) led 燈,當(dāng)光照強(qiáng)度小于 1lux 時(shí),3 個(gè) led 燈會(huì)全部開(kāi)啟。
開(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"

填寫信息如下,"Name"為"Auto-GCC","Compiler path"點(diǎn)擊旁邊的"Browse.."按鈕選擇編譯器的路徑,例子中的路徑是 “/usr/bin/gcc”

2)配置 G++
點(diǎn)擊右側(cè)"Add"按鈕,彈出下拉列表后,選擇"GCC"的"C++",下面的文本框填寫"Name" 為"Auto-G++","Compiler path"點(diǎn)擊旁邊的"Browse.."按鈕選擇編譯器的路徑,例子中的路徑是" /usr/bin/g++"。


填寫完成后,點(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 Widgets
Application”,然后點(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),鍵盤和其他消息,并在屏幕上繪制自己。一個(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)建了一些文件,寫好了一些前置代碼等等。
我們可以點(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)了。

Qt Creator 文件說(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 模塊。
“TARGET = 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 Creator 幫助文檔
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ù)如何編寫)。
部件常用事件主要在 “QWidget”中聲明,選擇“Events”即可查看相關(guān)說(shuō)明。
每個(gè)事件都對(duì)應(yīng)著事件函數(shù)。

點(diǎn)擊事件函數(shù)可查看詳情

項(xiàng)目總體設(shè)計(jì)介紹
(1)設(shè)計(jì)有環(huán)境監(jiān)測(cè)功能,通過(guò)溫濕度、光照傳感器實(shí)時(shí)采集環(huán)境溫度、濕度、光照顯示到 LCD 屏上。
(2)設(shè)計(jì)有設(shè)備控制功能,通過(guò)控制觸摸屏來(lái)進(jìn)行控制 3 個(gè) LED 燈、風(fēng)扇、蜂鳴器。
(3)設(shè)計(jì)智能檢測(cè)功能,用戶可以根據(jù)自己的需求修改智能檢測(cè)的閾值,開(kāi)啟智能檢測(cè)后,當(dāng)環(huán)境達(dá)到閾值后會(huì)啟動(dòng)設(shè)備。比如設(shè)置溫度閾值為 28 攝氏度,當(dāng)環(huán)境溫度達(dá)到 28 攝氏度時(shí),會(huì)自動(dòng)開(kāi)啟風(fēng)扇。設(shè)置一級(jí)照明為 50lux,二級(jí)照明為 30lux,三級(jí)照明為 1lux,當(dāng)光照強(qiáng)度小于 50lux 會(huì)開(kāi)啟一個(gè) led 燈,小于 30lux 會(huì)開(kāi)啟 2 個(gè) led 燈,當(dāng)光照強(qiáng)度小于 1lux 時(shí),3 個(gè) led 燈會(huì)全部開(kāi)啟
M4 部分實(shí)驗(yàn)原理
M4 部分功能概述
M4 核部分主要實(shí)現(xiàn)兩個(gè)功能,首先可以接收 A7 核發(fā)送的指令,根據(jù)指令控制風(fēng)扇、蜂鳴器以及 LED 燈工作,同時(shí) M4 部分可以采集環(huán)境光、溫濕度傳感器數(shù)據(jù),將采集數(shù)值打包成 JSON 字符串然后發(fā)送給 A7。另外,通過(guò)按鍵可以控制數(shù)碼管顯示采集的溫濕度、環(huán)境光數(shù)據(jù)。
cubeIDE 功能配置
首先打開(kāi) cubeIDE,創(chuàng)建一個(gè)新工程,進(jìn)入 cubeMX 配置界面,因?yàn)樾枰獙?shí)現(xiàn) A7 與 M4 通信,需要配置 IPCC 與 OPENAMP 部分,如下圖所示


配置 I2C1 用于采集溫濕度、環(huán)境光傳感器數(shù)據(jù),這里分別選擇 PF14、PF15 引腳用作 I2C1_SDA 和 I2C1_SCL 功能

因?yàn)樾枰玫綌?shù)碼管顯示采集的傳感器數(shù)值,這里通過(guò) SPI 進(jìn)行控制,使用 SPI 默認(rèn)引腳,分別對(duì) PE11、PE12、PE13 和 PE14 配置為 SPI4_NSS、SPI4_SCK、SPI4_MISO 和 SPI4_MOSI。切換到 SPI4 標(biāo)簽,勾選給“M4”,Mode”選擇“Full-Duplex-Master”,使用硬件片選,選擇“Hardware NSS
Output Signal”,其配置如下圖所示

擴(kuò)展板 LED 燈對(duì)應(yīng)的 GPIO 引腳分別為 PE8、PE10、PF10,這里左鍵點(diǎn)擊設(shè)置為 GPIO_Output

可以通過(guò)按鍵中斷控制數(shù)碼管顯示的數(shù)值,這里配置擴(kuò)展板的按鍵為PF9,如下所示

另外,這里還需要對(duì)剛才配置的 I/O 引腳設(shè)置“ Pin Reservation”給
“ Cortex-M4”,否則 STM32CubeMX 不會(huì)生生成 GPIO 初始化相關(guān)代碼。具體操作:在剛才選擇的引腳上,鼠標(biāo)右鍵選擇“ Pin Reservation”->“ CortexM4”。

打開(kāi) GPIO 標(biāo)簽,對(duì) PF9 引腳進(jìn)行配置

實(shí)驗(yàn)中還用到了蜂鳴器與風(fēng)扇,查看原理圖得,對(duì)應(yīng)管腳分別為 PB6 與
PE9,分別配置為 TIM4 與 TIM1 功能,在本次實(shí)驗(yàn)中,系統(tǒng)默認(rèn)時(shí)鐘頻率為
64MHz,TIM 配置如下所示


如果實(shí)現(xiàn)開(kāi)發(fā)板與電腦串口通信,這里可以通過(guò) 485 總線實(shí)現(xiàn),即配置UART5,如下所示


另外,在本次實(shí)驗(yàn)中,A7 與 M4 數(shù)據(jù)通信和數(shù)碼管顯示相當(dāng)于同時(shí)運(yùn)行,可以通過(guò)配置 FreeRTOS 實(shí)現(xiàn)多任務(wù)運(yùn)行。切換到中間件“Middleware”的
“FREERTOS”,默認(rèn)自動(dòng)勾選給 M4 了,然后接口“Interface”選擇
“CMSIS_V2”。為了運(yùn)行其他任務(wù),這里需要切換到“Tasks and Queues”標(biāo)簽,可以看到看到默認(rèn)有個(gè)“defaultTask”任務(wù),我們點(diǎn)擊“Add”再新增一個(gè)任務(wù),如圖所示

上述配置完成以后,還要注意一點(diǎn),因?yàn)橛玫?FreeRTOS,這里我們不能為每一種外設(shè)生成頭文件,如下所示

配置完成以后保存,然后生成初始化代碼,其間會(huì)出現(xiàn)如下提示框,選擇“Yes”
?

代碼實(shí)現(xiàn)
生成初始代碼以后,在 usart.c 文件 USER CODE BEGIN 1 與 USER CODE
END 1 之間添加 printf 的重定向函數(shù),實(shí)現(xiàn) UART5 與 printf 綁定。
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
PUTCHAR_PROTOTYPE
{
?HAL_UART_Transmit(&huart5,(uint8_t*)&ch,1,HAL_MAX_DELAY);
return ch;
}
#endif?
這里創(chuàng)建了一個(gè) RPMSG tty 通道,用于實(shí)現(xiàn) A7 與 M4 之間的數(shù)據(jù)傳輸
1、初始化 RPMSG tty 虛擬串口
printf("Virtual UART0 OpenAMP-rpmsg channel creation\r\n");
?if (VIRT_UART_Init(&huart0) != VIRT_UART_OK) {
?printf("VIRT_UART_Init UART0 failed.\r\n");
?Error_Handler();
}?
2、注冊(cè)回調(diào)函數(shù)以按通道接收消息?
if(VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID,
VIRT_UART0_RxCpltCallback) != VIRT_UART_OK)
?{
?Error_Handler();
?}
3、虛擬串口回調(diào)函數(shù)
M4 接收到數(shù)據(jù)以后,將會(huì)調(diào)用該回調(diào)函數(shù),需要將接收的數(shù)據(jù)復(fù)制到用戶
內(nèi)存,修改接收標(biāo)志位,通知用戶完成數(shù)據(jù)接收。
void VIRT_UART0_RxCpltCallback(VIRT_UART_HandleTypeDef *huart)
{
printf("Msg received on VIRTUAL UART0 channel: %s \n\r", (char *)
huart->pRxBuffPtr);
?/* copy received msg in a variable to sent it back to master processor
in main infinite loop*/
?VirtUart0ChannelRxSize = huart->RxXferSize < MAX_BUFFER_SIZE?
huart->RxXferSize : MAX_BUFFER_SIZE-1;
?memcpy(VirtUart0ChannelBuffRx, huart->pRxBuffPtr,
VirtUart0ChannelRxSize);
VirtUart0RxMsg = SET;
}
添加driver_si7006.c文件,編寫溫濕度數(shù)據(jù)采集函數(shù)
uint8_t SI7006_Init(void)
{
HAL_I2C_Init(&hi2c1);
SI7006_WriteByte(SI7006CMD_RESET);
return 0;
}
uint8_t SI7006_WriteByte(uint8_t reg)
{
uint8_t write_data = reg;
if(HAL_I2C_Master_Transmit(&hi2c1, SI7006_ADDR | SI7006_W ,
(uint8_t*)&write_data, 1, 300) != HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
return 0;
}
uint16_t SI7006_ReadWord(uint8_t reg)
{
uint16_t read_data = 0;
if(HAL_I2C_Master_Transmit(&hi2c1, SI7006_ADDR | SI7006_W ,
(uint8_t*)®, 1, 300) != HAL_OK) //發(fā)送命令
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
if(HAL_I2C_Master_Receive(&hi2c1, SI7006_ADDR | SI7006_R ,
(uint8_t*)&read_data, 2, 300) != HAL_OK) //接收 word 數(shù)據(jù)
{
Error_Handler();
}
?return read_data;
}
uint16_t SI7006_Read_Data(uint16_t cmd)
{
uint16_t data = 0,data_low = 0,data_high = 0;
data = SI7006_ReadWord(cmd); //采集溫濕度
data_low = (data & 0xff); //進(jìn)行高低字節(jié)轉(zhuǎn)換
data_high = (data >> 8) & 0xff;
?data = (data_low << 8) + data_high;
return data;
}
uint16_t SI7006_Readhum(void)
{
uint16_t hum = 0;
hum = SI7006_Read_Data(SI7006CMD_RH_HOLD);
hum = (125*hum/65536 - 6);
return hum;
}
uint16_t SI7006_Readtem(void)
{
uint16_t tem = 0;
tem = SI7006_Read_Data(SI7006CMD_TEMP_HOLD);
tem = ((17572*tem)/65536 - 4685);
return tem;
}
添加 driver_ap3216.c 文件,編寫環(huán)境光數(shù)據(jù)采集函數(shù)
uint8_t AP3216_Init(void)
{
uint8_t ret_value = 0;
AP3216_WriteOneByte(SYS_CONFIG_ADDR, SYS_SW_RESET);
HAL_Delay(50);
AP3216_WriteOneByte(SYS_CONFIG_ADDR, SYS_ALS_ACT);
HAL_Delay(50);
ret_value = AP3216_ReadOneByte(SYS_CONFIG_ADDR);
if(ret_value != SYS_ALS_ACT)
{
printf("read error \n");
}
printf("\r I2C Configuration register: 0x%x \n", SYS_CONFIG_ADDR);
printf("\r I2C Configuration value: 0x%x \n", SYS_ALS_ACT);
printf("\r I2C Read configuration value: 0x%x \n", ret_value);
return 0;
}
uint8_t AP3216_WriteOneByte(uint8_t reg, uint8_t data)
{
uint16_t write_data = reg | (data<<8)
if(HAL_I2C_Master_Transmit(&hi2c1, AP3216_ADDR | AP3216_W ,
(uint8_t*)&write_data, 2, 300) != HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
return 0;
}
uint8_t AP3216_ReadOneByte(uint8_t reg)
{
uint8_t read_data = 0;
if(HAL_I2C_Master_Transmit(&hi2c1, AP3216_ADDR | AP3216_W ,
(uint8_t*)®, 1, 300) != HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
if(HAL_I2C_Master_Receive(&hi2c1, AP3216_ADDR | AP3216_R ,
(uint8_t*)&read_data, 1, 300) != HAL_OK)
{
Error_Handler();
}
?return read_data;
}
uint16_t AP3216_Read_ALS_Data()
{
uint8_t als_l = 0, als_h = 0;
uint16_t data;
als_l = AP3216_ReadOneByte(ALS_DATA_LOW);
als_h = AP3216_ReadOneByte(ALS_DATA_HIGH);
data = (als_h<<8) | (als_l);
return data;
}
添加 driver_m74hc.c 文件,編寫數(shù)碼管顯示函數(shù)
uint8_t num[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uint8_t rw_595_Register(uint8_t reg,uint8_t data)
{
?uint8_t txdata[2] = {reg, data};
?if(HAL_SPI_Transmit(&hspi4, txdata ,2,300) != HAL_OK) //發(fā)送數(shù)據(jù)
?{
?Error_Handler();
?}
?return 0;
}
void M74HC595_ReadDataTest(uint16_t data,uint8_t sign)
{
uint8_t data1,data2, data3,data4;
data1 = data/1000;
data2 = data%1000/100;
data3 = data%100/10;
data4 = data%10;
num[data1] = (num[data1] & 0x7f);
?rw_595_Register(0X01,num[data1]);
?HAL_Delay(1);
?if(sign == 0) //sign = 1 為整數(shù), = 0 為小數(shù)
?num[data2] = (num[data2] | 0x80);
?else
?num[data2] = (num[data2] & 0x7f);
?rw_595_Register(0X02,num[data2]);
HAL_Delay(1);
num[data3] = (num[data3] & 0x7f);
?rw_595_Register(0X04,num[data3]);
?HAL_Delay(1);
?num[data4] = (num[data4] & 0x7f);
?rw_595_Register(0X08,num[data4]);
?HAL_Delay(1);
}
添加 driver_pwm.c 文件,編寫風(fēng)扇與蜂鳴器控制函數(shù)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
?if(htim->Instance==TIM4) //beep
?{
?__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,9999);
}
?if(htim->Instance==TIM1) //fan
?{
?__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,level *
3000);
?}
}
void TIM4_PWM_START(void)
{
?if(HAL_TIM_Base_Start_IT(&htim4) != HAL_OK)
?{
?Error_Handler();
?}
?HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
}
void TIM4_PWM_STOP(void)
{
?if(HAL_TIM_Base_Start_IT(&htim4) != HAL_OK)
?{
?Error_Handler();
?}
?HAL_TIM_PWM_Stop(&htim4,TIM_CHANNEL_1);
}
void TIM1_PWM_START(void)
{
?if(HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
?{
?Error_Handler();
?}
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
}
void TIM1_PWM_STOP(void)
{
?if(HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
?{
?Error_Handler();
?}
?HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
}
在 StartDefaultTask() 任務(wù)中實(shí)現(xiàn) A7 與 M4 的數(shù)據(jù)傳輸,在 StartTask02
() 任務(wù)中實(shí)現(xiàn)控制數(shù)碼管顯示采集的傳感器數(shù)值,相關(guān)代碼如下?
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
printf("Virtual UART0 OpenAMP-rpmsg channel creation\r\n");
if (VIRT_UART_Init(&huart0) != VIRT_UART_OK) {
printf("VIRT_UART_Init UART0 failed.\r\n");
Error_Handler();
}
if(VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID,
VIRT_UART0_RxCpltCallback) != VIRT_UART_OK)
{
printf("callback 0 error \n");
Error_Handler();
}
AP3216_Init();
SI7006_Init();
/* Infinite loop */
for(;;)
{
OPENAMP_check_for_message();
if (VirtUart0RxMsg)
{
VirtUart0RxMsg = RESET;
usr = cJSON_CreateObject();
#if 1
json = cJSON_Parse((char *)VirtUart0ChannelBuffRx);
json_led1 = cJSON_GetObjectItem(json,"led1");
json_led2 = cJSON_GetObjectItem(json,"led2");
json_led3 = cJSON_GetObjectItem(json,"led3");
json_beep = cJSON_GetObjectItem(json,"beep");
json_fan = cJSON_GetObjectItem(json,"fan");
if( strcmp((char*)json_led3->string,"led3") == 0)
{
printf("led1 light \n");
if(json_led3->valueint == 1)
HAL_GPIO_WritePin(GPIOE,
GPIO_PIN_8,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOE,
GPIO_PIN_8,GPIO_PIN_RESET);
}
else if( strcmp((char*)json_led2->string,"led2") == 0)
{
printf("led2 light \n");
if(json_led2->valueint == 1)
HAL_GPIO_WritePin(GPIOF,
GPIO_PIN_10,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOF,
GPIO_PIN_10,GPIO_PIN_RESET);
}
else if( strcmp((char*)json_led1->string,"led1") == 0)
{
printf("led1 light \n");
if(json_led1->valueint == 1)
HAL_GPIO_WritePin(GPIOE,
GPIO_PIN_10,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOE,
GPIO_PIN_10,GPIO_PIN_RESET);
}
else if( strcmp((char*)json_beep->string,"beep") == 0)
{
printf("beep work \n");
if(json_beep->valueint == 1)
TIM4_PWM_START();
else
TIM4_PWM_STOP();
}
else if( strcmp((char*)json_fan->string,"fan") == 0)
{
printf("fan work \n");
switch(json_fan->valueint)
{
case 1 :
case 2 :
case 3:
level = json_fan->valueint;
TIM1_PWM_START();
break;
case 0:
TIM1_PWM_STOP();
break;
}
}
#endif
value_als = AP3216_Read_ALS_Data();
value_tem = SI7006_Readtem();
value_hum = SI7006_Readhum();
cJSON_AddNumberToObject(usr,"als",value_als);
cJSON_AddNumberToObject(usr,"tem",value_tem);
cJSON_AddNumberToObject(usr,"hum",value_hum);
out = cJSON_Print(usr);
printf("the out: %s \n",out);
strcpy((char *)BuffTx,out);
if( VIRT_UART_Transmit(&huart0, BuffTx, strlen((const char
*)BuffTx)) != VIRT_UART_OK)
{
printf("transmit error \n");
}
memset(BuffTx, 0 ,strlen((const char *)BuffTx));
cJSON_Delete(usr);
memset(VirtUart0ChannelBuffRx, 0 ,VirtUart0ChannelRxSize);
cJSON_Delete(json);
cJSON_Delete(json_led1);
cJSON_Delete(json_led2);
cJSON_Delete(json_led3);
cJSON_Delete(json_beep);
cJSON_Delete(json_fan);
}
}
/* USER CODE END 5 */
}
void StartTask02(void *argument)
{
?/* USER CODE BEGIN StartTask02 */
?/* Infinite loop */
?for(;;)
?{
?switch(vol_cur)
?{
?case 1:
?M74HC595_ReadDataTest(value_als,1);
?break;
?case 2:
?M74HC595_ReadDataTest(value_tem,0);
?break;
?case 3:
?M74HC595_ReadDataTest(value_hum,0);
?break;
?}
?}
?/* USER CODE END StartTask02 */
}?
M4 部分調(diào)試、執(zhí)行
程序編譯沒(méi)問(wèn)題以后,點(diǎn)擊“debug”下載調(diào)試,會(huì)將生成的 elf 文件下載到開(kāi)發(fā)板/lib/fireware/目錄下

進(jìn)入內(nèi)核終端下,查看對(duì)應(yīng)目錄下文件,如下所示

在/usr/local/projects/ 目錄下,可以看到含有所創(chuàng)工程名的目錄

進(jìn)入目錄下,其包含文件如圖所示

此時(shí)執(zhí)行 ./fw_cortex_m4.sh start便可以啟動(dòng) M4 程序。
源碼分析
環(huán)境監(jiān)測(cè)模塊和智能檢測(cè)模塊
啟動(dòng) m4 程序后會(huì)生成一個(gè)串口設(shè)備,m4 程序采集溫濕度、環(huán)境光照信息。將采集到的數(shù)據(jù)寫入到串口,a7 通過(guò)實(shí)時(shí)讀取串口的數(shù)據(jù),對(duì)數(shù)據(jù)進(jìn)行解析、計(jì)算獲得溫濕度和光照的數(shù)值,再使用信號(hào)的方式傳給主線程,實(shí)時(shí)顯示到 UI 界面上,實(shí)現(xiàn)環(huán)境的溫濕度和光照的監(jiān)測(cè)。
使用 sqlite3 數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)用戶設(shè)置的溫度開(kāi)啟風(fēng)扇的閾值、照明等級(jí)。用戶每次改變閾值后都會(huì)存儲(chǔ)到數(shù)據(jù)庫(kù)里,當(dāng)關(guān)閉程序后,下次啟動(dòng)會(huì)從數(shù)據(jù)庫(kù)讀取上次保存的數(shù)值,不用每次都重新設(shè)置閾值,更加人性化。
如果開(kāi)啟了智能檢測(cè),每次采集到數(shù)據(jù)后會(huì)跟用戶設(shè)置的閾值進(jìn)行比較,如果采集的溫度大于設(shè)置的溫度閾值,就會(huì)自動(dòng)開(kāi)啟風(fēng)扇;如果設(shè)置一級(jí)照明為 50lux,二級(jí)照明為 30lux,三級(jí)照明為 1lux,當(dāng)光照強(qiáng)度小于 50lux 會(huì)開(kāi)啟一個(gè) led 燈,小于 30lux 會(huì)開(kāi)啟 2 個(gè) led 燈,當(dāng)光照強(qiáng)度小于 1lux 時(shí),3 個(gè)led 燈會(huì)全部開(kāi)啟。從而實(shí)現(xiàn)智能檢測(cè)的功能
設(shè)備控制模塊
只需要向相應(yīng)的設(shè)備文件寫入數(shù)據(jù)就能實(shí)現(xiàn)對(duì) LED 燈、風(fēng)扇、蜂鳴器的控制。在 QT 程序中,只需點(diǎn)擊按鍵后觸發(fā) clicked 信號(hào),進(jìn)入相應(yīng)的槽函數(shù),向串口設(shè)備文件寫入數(shù)據(jù),M4 程序?qū)?shù)據(jù)進(jìn)行采集,根據(jù)數(shù)據(jù)的不同,通過(guò)實(shí)現(xiàn)對(duì)設(shè)備的控制,核心代碼如下
void MainWindow::led1_on_btnSlot()
{
?QString ctrl ="{\"led1\":1}";
?thread_collentdata.ctrlEnv = false;
?write(fd, ctrl.toUtf8(), ctrl.length());
?qDebug()<<"write fd:"<<fd<<" success"<<" data = "<<ctrl;
?ui->pushButton->setEnabled(true);
}
設(shè)備樹(shù)編譯
使用 M4 程序進(jìn)行數(shù)據(jù)采集的時(shí)候,因?yàn)?A7 和 M4 有沖突,所以需要重新編譯設(shè)備樹(shù)文件。詳細(xì)參考【FS-MP1A 開(kāi)發(fā)教程】中 50.5 linux 源碼編譯章節(jié)
1. 進(jìn)入在鏡像中拿到的 linux 源碼下的 dts 路徑下:
linux@ubuntu:~cd linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts
2. 新建設(shè)備樹(shù)文件
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$ cp stm32mp157a-fsmp1aextended-rgb070.dts stm32mp157a-fsmp1a-extended-noi2c1-rgb070.dts
3. 修改復(fù)制的文件,將 i2c1 節(jié)點(diǎn)關(guān)閉

4. 修改 Makefile
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$ vi Makefile
加入以下內(nèi)容。

5.進(jìn)入內(nèi)核頂層目錄編譯
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$ make dtbs
6. 拷貝編譯好的設(shè)備樹(shù)文件到開(kāi)發(fā)板
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$scparch/arm/boot/dts/stm32mp157a-fsmp1a
extended-noi2c1-rgb070.dtb root@192.168.10.130:/boot
7. 修改默認(rèn)啟動(dòng)選項(xiàng)
root@fsmp1a:~# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf

8. 重啟開(kāi)發(fā)板
選擇后,即可載入設(shè)備樹(shù)文件。

源碼路徑【8_環(huán)境檢測(cè)\實(shí)驗(yàn)源碼\8_EnvironmentalTest】
注意事項(xiàng)
1.在開(kāi)發(fā)板運(yùn)行時(shí),需要導(dǎo)入中文字庫(kù),否則會(huì)因?yàn)樽R(shí)別不了中文。將【8_環(huán)境檢測(cè)\工具軟件\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
QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0:rotate=90