作者:楊紅超
本章主要闡述多功能氣壓計(jì)的應(yīng)用背景,包括根據(jù)大氣壓強(qiáng)判斷和確定建筑工人的樓層位置、幫助建筑工人感知周圍環(huán)境溫度變化等,同時(shí)也可根據(jù)大氣壓強(qiáng)判斷無(wú)人機(jī)的GPS定位。其次著重介紹氣壓計(jì)的具體功能,如可以通過(guò)對(duì)工人周圍的氣壓和溫度的采集計(jì)算出當(dāng)前所在的樓層位置,并將數(shù)據(jù)信息通過(guò)ONENET上傳到云服務(wù)器上,通過(guò)語(yǔ)音識(shí)別實(shí)現(xiàn)設(shè)備在線升級(jí)功能。最后對(duì)本次設(shè)計(jì)的組織結(jié)構(gòu)進(jìn)行介紹,以表明每章節(jié)的主要內(nèi)容和作用。
1.1應(yīng)用背景
為確保建筑工人在工地施工時(shí)的人身安全,故此設(shè)計(jì)一款工人們的“運(yùn)行手環(huán)”——多功能氣壓計(jì)。它內(nèi)置氣體壓強(qiáng)檢測(cè)裝置可實(shí)時(shí)檢測(cè)建筑工人身處的大氣壓強(qiáng)和周圍的環(huán)境溫度,進(jìn)而根據(jù)采集的數(shù)據(jù)推算出工人所在的樓層高度,并將數(shù)據(jù)實(shí)時(shí)上傳到云服務(wù)器上通過(guò)管理者對(duì)數(shù)據(jù)的檢測(cè)給建筑工人提供一份雙保險(xiǎn)。
此外,該多功能氣壓計(jì)還具有無(wú)人機(jī)GPS定位和判斷吸塵器吸力大小等應(yīng)用于多對(duì)象、多環(huán)境的特點(diǎn)。
1.2實(shí)現(xiàn)功能
本次多功能氣壓計(jì)的設(shè)計(jì)硬件采用ART-Pi開(kāi)發(fā)板、LPS22HH氣壓傳感器和LD3320語(yǔ)音識(shí)別模塊,操作系統(tǒng)使用RT-Thread 4.0.3,軟件使用RT-Thread Studio 1.1.5開(kāi)發(fā)平臺(tái)和使用C語(yǔ)言實(shí)現(xiàn)軟件編程,具有如下功能:
(1)利用LPS22HH氣壓傳感器實(shí)時(shí)對(duì)大氣壓的壓強(qiáng)進(jìn)行采集,并通過(guò)SPI4接口將采集的數(shù)據(jù)傳給單片機(jī)。
(2)利用AP6212 WIFI模塊實(shí)時(shí)將經(jīng)過(guò)處理后的數(shù)據(jù),如溫度值和樓層信息等上傳到云服務(wù)器;同時(shí)通過(guò)WIFI模塊實(shí)現(xiàn)在線升級(jí)用戶程序。
(3)語(yǔ)音識(shí)別模塊通過(guò)SPI2實(shí)現(xiàn)與開(kāi)發(fā)板的數(shù)據(jù)交互,完成語(yǔ)音重啟設(shè)備和語(yǔ)音在線升級(jí)功能。
1.3設(shè)計(jì)組織結(jié)構(gòu)
本次基于ART-Pi開(kāi)發(fā)板的多功能氣壓計(jì)設(shè)計(jì),主要分為五個(gè)章節(jié)其具體設(shè)計(jì)組織結(jié)構(gòu)如下:
第一章 緒論,主要介紹多功能氣壓計(jì)的實(shí)際應(yīng)用背景和具有的具體功能,以及設(shè)計(jì)組織結(jié)構(gòu)的規(guī)劃。
第二章 RT-Thread概述,主要對(duì)在本設(shè)計(jì)中涉及的RT-Thread內(nèi)核、及其組件和軟件包進(jìn)行闡述,欲以說(shuō)明對(duì)RT-Thread操作系統(tǒng)的使用情況和了解程度,同時(shí)對(duì)其內(nèi)容作些簡(jiǎn)單的介紹。
第三章 硬件設(shè)計(jì),主要闡述硬件模塊的電氣連接和本次設(shè)計(jì)使用的硬件電路,如LPS22HH氣壓傳感器、ART-Pi開(kāi)發(fā)板和語(yǔ)音識(shí)別模塊等。
第四章 軟件設(shè)計(jì),主要闡述軟件實(shí)現(xiàn)的設(shè)計(jì)流程和各個(gè)軟件模塊設(shè)計(jì)的框架,以及模塊之間的通訊方式。
第五章 總結(jié)與展望,主要闡述對(duì)本次設(shè)計(jì)的評(píng)估,即軟件設(shè)計(jì)存在的不足和功能與性能存在的不足,以及針對(duì)不足之處提出的具體改進(jìn)措施和方案、參加比賽的感悟和心得。
1.4本章小節(jié)
本章主要介紹多功能氣壓計(jì)的應(yīng)用背景和具體的應(yīng)用功能,以及對(duì)軟硬件開(kāi)發(fā)環(huán)境和該設(shè)計(jì)文檔的組織結(jié)構(gòu)進(jìn)行闡述。
本章主要闡述在軟件設(shè)計(jì)中關(guān)于RT-Thread操作系統(tǒng)的應(yīng)用情況,如與線程運(yùn)行有關(guān)的采用動(dòng)態(tài)方式創(chuàng)建線程,與線程同步有關(guān)的信號(hào)量的動(dòng)態(tài)創(chuàng)建、釋放和獲取,以及與網(wǎng)絡(luò)有關(guān)的SAL組件、OneNET軟件包等。
2.1內(nèi)核
為了提高軟件運(yùn)行的并發(fā)性和數(shù)據(jù)采集的實(shí)時(shí)性,故使用內(nèi)核中的核心部分——線程,使其維護(hù)和管理每個(gè)任務(wù)的運(yùn)行,同時(shí)以使用信號(hào)量和事件集等的同步方式,以及使用郵箱和消息隊(duì)列等的通信方式來(lái)確保每個(gè)任務(wù)在運(yùn)行過(guò)程中能“自由飛翔”。
不僅如此,為增加任務(wù)在運(yùn)行狀態(tài)中的時(shí)間和提高每個(gè)任務(wù)響應(yīng)的快慢速度,故使用線程中重要的兩個(gè)屬性即線程優(yōu)先級(jí)和時(shí)間片,并根據(jù)應(yīng)用的具體環(huán)境和軟實(shí)時(shí)性的要求將每個(gè)任務(wù)賦予各自該具有的任務(wù)優(yōu)先級(jí)和時(shí)間片。同時(shí),使用rt_thread_mdelay延遲函數(shù)來(lái)定時(shí)釋放線程(任務(wù))確保在其處于非運(yùn)行態(tài)時(shí)可以退出時(shí)間片以讓其它任務(wù)能及時(shí)運(yùn)行。
2.2驅(qū)動(dòng)
在bootloader程序中主要初始化SPI和SFUD驅(qū)動(dòng)實(shí)現(xiàn)對(duì)外部SPI FLASH的讀寫操作,同時(shí)結(jié)合使用FAL軟件包將操作FLASH的函數(shù)進(jìn)行分層,進(jìn)而實(shí)現(xiàn)在bootloader程序中讀取“download”分區(qū)的升級(jí)固件,以及使用ota_downloader軟件包完成升級(jí)固件的下載,最后使用出廠W25QXX函數(shù)實(shí)現(xiàn)固件搬運(yùn)工作進(jìn)而完成在線升級(jí)應(yīng)用。
2.3組件
SAL組件完成并提供了基于RT-Thread操作系統(tǒng)的對(duì)不同網(wǎng)絡(luò)協(xié)議?;蚓W(wǎng)絡(luò)實(shí)現(xiàn)接口的抽象和與上層應(yīng)用有關(guān)的一組標(biāo)準(zhǔn)BSD Socket API,在網(wǎng)絡(luò)開(kāi)發(fā)設(shè)計(jì)時(shí)可只需關(guān)心和使用網(wǎng)絡(luò)應(yīng)用層提供的網(wǎng)絡(luò)接口,而無(wú)需關(guān)心底層具體網(wǎng)絡(luò)協(xié)議棧類型和具體實(shí)現(xiàn),如TCP/IP協(xié)議棧、LWIP和AT Socket網(wǎng)絡(luò)。SAL組件不僅提高了軟件系統(tǒng)對(duì)底層驅(qū)動(dòng)的兼容性,而且縮短了網(wǎng)絡(luò)開(kāi)發(fā)周期。此外,SAL組件還具有一下功能特點(diǎn)[1]:
- 抽象、統(tǒng)一多種網(wǎng)絡(luò)協(xié)議棧接口;
- 提供Socket層面的TLS加密傳輸特性;
- 支持標(biāo)準(zhǔn)BSP Socket API;
- 統(tǒng)一的FD管理,便于使用read/write,poll/select來(lái)操作網(wǎng)絡(luò)功能。
在本次AP6212 WIFI模塊設(shè)計(jì)中主要使用SAL組件來(lái)實(shí)現(xiàn)多功能氣壓計(jì)自動(dòng)檢測(cè)熱點(diǎn)、連接熱點(diǎn)和斷線重連的功能,并結(jié)合OneNET軟件包提供的API接口以實(shí)現(xiàn)訪問(wèn)OneNET云服務(wù)器的功能。
2.4軟件包
OneNET軟件包是 RT-Thread 系統(tǒng)針對(duì) OneNET 平臺(tái)連接的適配,通過(guò)這個(gè)組件包可以讓設(shè)備在 RT-Thread 上非常方便的連接 OneNet 平臺(tái),完成數(shù)據(jù)的發(fā)送、接收、設(shè)備的注冊(cè)和控制等功能。具有如下功能特點(diǎn)[2]:
- 斷線重連。在斷網(wǎng)或網(wǎng)絡(luò)不穩(wěn)定導(dǎo)致連接斷開(kāi)時(shí),會(huì)維護(hù)登陸狀態(tài),重新連接,并自動(dòng)登陸 OneNET 平臺(tái)。提高連接的可靠性,增加了軟件包的易用性。
- 自動(dòng)注冊(cè)。不需要在 web 頁(yè)面上手動(dòng)的一個(gè)一個(gè)創(chuàng)建設(shè)備,輸入設(shè)備名字和鑒權(quán)信息。當(dāng)開(kāi)啟設(shè)備注冊(cè)功能后,設(shè)備第一次登陸 OneNET 平臺(tái)時(shí),會(huì)自動(dòng)調(diào)用注冊(cè)函數(shù)向 OneNET 平臺(tái)注冊(cè)設(shè)備,并將返回的設(shè)備信息保存下來(lái),用于下次登陸。
- 自動(dòng)響應(yīng)函數(shù)。OneNET 軟件包提供了一個(gè)命令響應(yīng)回調(diào)函數(shù),當(dāng) OneNET 平臺(tái)下發(fā)命令后,RT-Thread 會(huì)自動(dòng)調(diào)用命令響應(yīng)回調(diào)函數(shù),用戶處理完命令后,返回要發(fā)送的響應(yīng)內(nèi)容,RT-Thread 會(huì)自動(dòng)將響應(yīng)發(fā)回 OneNET 平臺(tái)。
- 自定義topic和回調(diào)函數(shù)。OneNET 軟件包除了可以響應(yīng) OneNET 官方 topic 下發(fā)的命令外,還可以訂閱用戶自定義的 topic,并為每個(gè) topic 單獨(dú)設(shè)置一個(gè)命令處理回調(diào)函數(shù)。方便用戶開(kāi)發(fā)自定義功能。
- 上傳二進(jìn)制數(shù)據(jù)。OneNET 軟件包除了上傳數(shù)字和字符串外,還支持二進(jìn)制文件上傳。當(dāng)啟用了 RT-Thread 的文件系統(tǒng)后,可以直接將文件系統(tǒng)內(nèi)的文件以二進(jìn)制的方式上傳至云端。
2.5本章小節(jié)
本章主要介紹了內(nèi)核線程在本次任務(wù)實(shí)現(xiàn)過(guò)程中的應(yīng)用情況,如采集任務(wù)和網(wǎng)絡(luò)發(fā)送任務(wù)的同步和通信等;以及闡述了SAL組件和OneNET軟件包的概念和具有的功能特點(diǎn)等。
本章主要描述多功能氣壓計(jì)的硬件設(shè)計(jì)框架和模塊之間的電氣連接,如氣壓傳感器通過(guò)SPI4接口與ART-Pi開(kāi)發(fā)板的PE2(SPI4_CK)、PE5(SPI4_MISO)和PE6(SPI4_MOSI)引腳等相連,AP6212 WIFI模塊通過(guò)SDIO2接口與主單片機(jī)(STM32H750XB)相連,語(yǔ)音識(shí)別模塊通過(guò)SPI2接口與主單片機(jī)相連;以及介紹項(xiàng)目涉及的主要芯片或模塊的應(yīng)用特點(diǎn)和通訊協(xié)議。
3.1硬件框架
本設(shè)計(jì)采用ART-Pi開(kāi)發(fā)板及板載WIFI模塊,并使用LPS22HH氣壓傳感器和語(yǔ)音識(shí)別模塊完成硬件模塊電路搭建,如下圖3.1硬件設(shè)計(jì)框圖所示。
圖3.1 硬件設(shè)計(jì)框圖
由硬件設(shè)計(jì)框架圖可知:WIFI模塊通過(guò)SMMC2(SDIO2)接口與單片機(jī)STM32H750相連;氣壓傳感器通過(guò)SPI4接口與單片機(jī)相連;語(yǔ)音識(shí)別模塊與單片機(jī)的SPI2接口連接。
3.2硬件模塊介紹
(1)LPS22H氣壓傳感器
LPS22HH是一款高精度氣壓傳感器,可用作數(shù)字輸出氣壓計(jì),具有數(shù)字I2C / MIPI I3CSM / SPI 串行接口標(biāo)準(zhǔn)輸出。工作壓力范圍為260 hPa 至1260 hPa,器件能夠以最高200 Hz 的輸出數(shù)據(jù)率測(cè)量壓力值。絕對(duì)精度是0.5hPa.LPM下功耗只有4uA??梢杂糜跍y(cè)量海拔高度,樓層定位,無(wú)人機(jī)定高,吸塵器吸力大小判斷等應(yīng)用。在本次設(shè)計(jì)中使用模塊中的SPI4接口與單片機(jī)通訊,以獲取傳感器采集和轉(zhuǎn)換的氣壓值和溫度值。
(2)AP6212 WIFI模塊
AMPAK技術(shù)公司想宣布一個(gè)低成本和低功耗的模塊它具有所有WiFi、藍(lán)牙和FM功能。高度集成的模塊使網(wǎng)絡(luò)瀏覽、VoIP、藍(lán)牙耳機(jī)、調(diào)頻收音機(jī)功能成為可能應(yīng)用程序和其他應(yīng)用程序。具有無(wú)縫漫游功能和高級(jí)安全性,也可以與不同廠商的802.11b/g/n無(wú)線接入點(diǎn)進(jìn)行交互局域網(wǎng)。該無(wú)線模塊符合ieee802.11b/g/n標(biāo)準(zhǔn),可以達(dá)到802.11n草案中的單流傳輸速度為72.2Mbps,IEEE規(guī)定為54Mbps,802.11g或11Mbps,用于連接到無(wú)線LAN的IEEE 802.11b。綜合模塊為WiFi提供SDIO接口,為藍(lán)牙和用于FM的UART/I2S/PCM接口。這個(gè)緊湊的模塊是一個(gè)結(jié)合WiFi+BT+FM技術(shù)的整體解決方案。該模塊是專門為智能手機(jī)和便攜式設(shè)備開(kāi)發(fā)的。
(3)LD3320語(yǔ)音識(shí)別模塊
LD3320 是一顆基于非特定人語(yǔ)音識(shí)別(SI-ASR:Speaker-IndependentAutomatic Speech Recognition)技術(shù)的語(yǔ)音識(shí)別/聲控芯片。提供了真正的單芯片語(yǔ)音識(shí)別解決方案。LD3320 芯片上集成了高精度的 A/D 和 D/A 接口,不再需要外接輔助的Flash 和 RAM,即可以實(shí)現(xiàn)語(yǔ)音識(shí)別/聲控/人機(jī)對(duì)話功能。并且,識(shí)別的關(guān)鍵詞語(yǔ)列表是可以動(dòng)態(tài)編輯的。在本次設(shè)計(jì)中通過(guò)SPI2接口與主單片機(jī)相連,實(shí)現(xiàn)語(yǔ)音命令的初始化和語(yǔ)音數(shù)據(jù)的傳輸。
3.3本章小節(jié)
本章著重介紹了硬件電路的設(shè)計(jì)框架,和主要的芯片或模塊如LPS22HH氣壓傳感器模塊、AP6212 WIFI模塊和LD3320語(yǔ)音識(shí)別模塊等。
本章主要闡述在瀑布式開(kāi)發(fā)模型下首先將軟件系統(tǒng)分為各個(gè)模塊并在邏輯控制單元模塊下實(shí)現(xiàn)模塊之間數(shù)據(jù)的交互,即軟件系統(tǒng)框架。其次闡述各個(gè)模塊的軟件設(shè)計(jì)流程,以及模塊的具體功能和接口。
4.1軟件框架
本設(shè)計(jì)根據(jù)多功能氣壓計(jì)的功能將軟件系統(tǒng)劃分各個(gè)模塊,如采集模塊、網(wǎng)絡(luò)通訊模塊、語(yǔ)音識(shí)別模塊和升級(jí)模塊,并將其作為單獨(dú)任務(wù)進(jìn)行初始化和執(zhí)行讀寫操作等。最后通過(guò)邏輯控制單元實(shí)現(xiàn)各模塊之間的通信和同步,如圖4.1(a)軟件系統(tǒng)框架圖所示:
圖4.1(a) 軟件系統(tǒng)設(shè)計(jì)框圖
由圖4.1(a)可知:邏輯控制單元主要負(fù)責(zé)接收采集模塊輸出的數(shù)據(jù)消息;升級(jí)模塊主要從云端獲取升級(jí)固件并將其輸出給邏輯控制單元,再由邏輯控制單元將升級(jí)固件寫入到downloader分區(qū)并通過(guò)bootloader程序引導(dǎo)完成升級(jí)操作;網(wǎng)絡(luò)通訊模塊主要將由邏輯控制單元處理后的數(shù)據(jù)如氣壓值和溫度值傳輸?shù)?/span>OneNET云服務(wù)器上;語(yǔ)音識(shí)別模塊主要接收和解析用戶輸入的語(yǔ)音指令,進(jìn)而實(shí)現(xiàn)設(shè)備在線升級(jí)等功能。
在硬件通電后軟件首先初始化底層設(shè)備驅(qū)動(dòng),然后對(duì)各個(gè)系統(tǒng)軟件模塊進(jìn)行初始化,初始化方式采用命令INIT_APP_EXPORT導(dǎo)入方式。最后使用for循環(huán)語(yǔ)句使其依次以線程(任務(wù))的形式創(chuàng)建監(jiān)測(cè)(采集)任務(wù)、用戶任務(wù)和(網(wǎng)絡(luò))終端任務(wù),若任務(wù)創(chuàng)建成功則開(kāi)始運(yùn)行,如下圖4.1(b) 軟件系統(tǒng)設(shè)計(jì)流程圖所示:
圖4.1(b) 軟件設(shè)計(jì)流程圖
4.2采集模塊
(1)實(shí)現(xiàn)方式
首先使用STM32CubeMX工具配置底層SPI驅(qū)動(dòng),需要注意CPOL值為SPI_POLARITY_HIGH和CPHA值為SPI_PHASE_2EDGE;其次根據(jù)芯片手冊(cè)配置SPI波特率為SPI_BAUDRATEPRESCALER_8,同時(shí)LPS22HH氣壓傳感器模塊初始化時(shí)CTRL_REG1設(shè)置為LPS22HH_50_Hz_LOW_NOISE;最后通過(guò)讀取寄存器0x0FU的值判斷SPI通訊是否正常,進(jìn)而讀取溫度值和壓強(qiáng)值。
(2)實(shí)時(shí)采集任務(wù)
對(duì)于實(shí)時(shí)采集任務(wù)是通過(guò)while循環(huán)方式每秒讀取0x28U等寄存器值實(shí)現(xiàn)的,此函數(shù)在task_init函數(shù)中被調(diào)用,使用線程方式創(chuàng)建和運(yùn)行。如下所示為實(shí)時(shí)采集任務(wù)函數(shù)的實(shí)現(xiàn)。
/** * @brief A thread entry, used to capture temperature[degC] and pressure[hPa]. * Call at task_init function in task module. * @param void* RT_NULL. * @retval int32_t */ int sensor_monitor_entry(void *parameter) { axis1bit32_t data_raw_pressure ={0}; axis1bit16_t data_raw_temperature ={0}; uint32_t pressure =0; uint16_t temperature =0; uint8_t floor =0; while (1) { /* read pressure from lps22hh */ rt_memset(data_raw_pressure.u8bit, 0x00, sizeof(int32_t)); lps22hh_pressure_raw_get(&dev_ctx, data_raw_pressure.u8bit); pressure =data_raw_pressure.i32bit *1.0 / 4096.0; DBG_SENSOR_PRINTF("pressure:%dn", pressure);
/* write pressure into mailbox, offset: PRESSURE_OFFSET */ if (ld3320_assert(pressure, temperature) == 1) { mailbox_write(pressure, PRESSURE_OFFSET); } rt_thread_mdelay(10);
/* read temperature from lps22hh */ rt_memset(data_raw_temperature.u8bit, 0x00, sizeof(int16_t)); lps22hh_temperature_raw_get(&dev_ctx, data_raw_temperature.u8bit); temperature =data_raw_temperature.i16bit *1.0 / 100.0; DBG_SENSOR_PRINTF("temperature:%dn", temperature);
/* write temperature into mailbox, offset: TEMPERATURE_OFFSET */ if (ld3320_assert(pressure, temperature) == 1) { mailbox_write(temperature, TEMPERATURE_OFFSET); }
rt_thread_mdelay(10); /* calculate floor by location algorithm */ floor =location_algorithm(pressure, temperature); DBG_SENSOR_PRINTF("floor:%dn", floor);
/* write floor into mailbox, offset: TEMPERATURE_OFFSET */ if (floor !=255) { mailbox_write(floor, FLOOR_OFFSET); }
rt_thread_mdelay(500); }
return RT_EOK; }
|
4.3升級(jí)模塊
(1)實(shí)現(xiàn)方式
首先將升級(jí)固件(rtthread.bin)上傳到服務(wù)器;其次通過(guò)語(yǔ)音識(shí)別模塊識(shí)別到“升級(jí)”語(yǔ)音命令時(shí)調(diào)用http_ota_fw_download(PKG_HTTP_OTA_URL)升級(jí)函數(shù),實(shí)現(xiàn)將服務(wù)器固件文件下載到download分區(qū),下載完成后通過(guò)bootloader程序?qū)⒐碳?/span>download分區(qū)搬運(yùn)到app分區(qū),從而實(shí)現(xiàn)應(yīng)用程序升級(jí)。注:download分區(qū)最后4個(gè)字節(jié)存儲(chǔ)的值為固件大小并將其作為升級(jí)標(biāo)志,即若為0xFFFFFFFF則直接跳轉(zhuǎn)到app;若值不為0xFFFFFFFF則表示存在升級(jí)固件并且固件大小為該值,從而先擦除app分區(qū)、讀取download分區(qū)固件寫入到app分區(qū)、擦除download分區(qū)、最后進(jìn)行跳轉(zhuǎn)完成升級(jí)工作。
(2)讀取download分區(qū)寫入app分區(qū)的過(guò)程如下
/** * @brief IAP move update-firmware from download part to app part. * Call at main.c. * @param None. * @retval Not used. */ rt_uint8_t iap_move(void) { int ret = 0; int file_size = 0, length = 0, total_length = 0;
const struct fal_partition * dl_part = RT_NULL;
/* find download part */ if ((dl_part = fal_partition_find("download")) == RT_NULL) { rt_kprintf("Firmware download find error!"); ret = -RT_ERROR; goto __exit; }
/* get filesize of firmware */ fal_partition_read(dl_part, dl_part->len-4, (rt_uint8_t*)&file_size, 4); if (file_size ==0xFFFFFFFF) { ret = -RT_ERROR; goto __exit; }
/* erase app partition */ rt_kprintf("start erase appn"); W25QXX_ChipErase(); rt_kprintf("erase app finishedn");
/*moved download to app */ rt_kprintf("start moven"); do { /*read data from download part */ length = fal_partition_read(dl_part, total_length, buffer_read, file_size - total_length > 4096 ? 4096 : file_size - total_length); if (length > 0) { /* write data into app part */ W25QXX_Write_NoCheck(buffer_read, total_length, length); total_length += length; rt_kprintf("process: %dn", total_length); } else { rt_kprintf("Exit: server return err (%d)!", length); ret = -RT_ERROR; goto __exit; } } while(total_length != file_size); rt_kprintf("move finished n");
/* check data between download and app part */ total_length = 0; do{ length = fal_partition_read(dl_part, total_length, buffer_read, file_size - total_length > 4096 ? 4096 : file_size - total_length); if (length > 0) { W25QXX_Read(buffer_temp, total_length, length); if (rt_strncmp(buffer_read, buffer_temp, length) ==0) { total_length += length; rt_kprintf("check: %dn", total_length); } else { for(int i = 0; i < length; i++) { rt_kprintf("-%x-%x-n", buffer_temp[i], buffer_read[i]); } rt_kprintf("process: %d check errorn", total_length); } } else { rt_kprintf("Exit: return err (%d)!", length); ret = -RT_ERROR; goto __exit; } } while(total_length != file_size);
/* clear update flag */ if (total_length == file_size) { rt_kprintf("Start erase flash (%s) partition!", dl_part->name);
if (fal_partition_erase(dl_part, 0, dl_part->len) < 0) { LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name); ret = -RT_ERROR; goto __exit; } rt_kprintf("Erase flash (%s) partition success!", dl_part->name); } rt_kprintf("start jumpn"); __exit: return ret; }
|
4.4網(wǎng)絡(luò)通訊模塊
(1)實(shí)現(xiàn)方式
首先,通過(guò)rt_wlan_connect函數(shù)成功WIFI網(wǎng)絡(luò)后,添加Onenet軟件包配置參數(shù)并添加onenet_mqtt_init函數(shù)實(shí)現(xiàn)與云服務(wù)器的連接;其次,通過(guò)郵箱方式獲取采集的數(shù)據(jù),如溫度值和氣壓值;最后調(diào)用onenet_mqtt_upload_digit函數(shù)實(shí)現(xiàn)數(shù)據(jù)上傳。
(2)數(shù)據(jù)上傳
在WIFI網(wǎng)絡(luò)連接成功后每隔5秒實(shí)現(xiàn)數(shù)據(jù)獲取和數(shù)據(jù)上傳,具體的數(shù)據(jù)上傳如下所示。
/** * @brief A thread entry, used to upload temperature and pressure. * Call at task_init function in task module. * @param void* RT_NULL. * @retval int32_t */ int net_terminal_entry(void *parameter) { uint32_t value =0; while (1) {
/* get pressure in a mailbox from sensor */ value =mailbox_read(PRESSURE_OFFSET);
/* upload pressure to onenet cloud */ if (onenet_mqtt_upload_digit("pressure", value) < 0) { DBG_TERMINAL_PRINTF("upload has an error, stop uploadingn"); } else { DBG_TERMINAL_PRINTF("buffer : {"pressure":%d}n", value); }
/* get temperature in a mailbox from sensor */ value =mailbox_read(TEMPERATURE_OFFSET);
/* upload temperature to onenet cloud */ if (onenet_mqtt_upload_digit("temperature", value) < 0) { DBG_TERMINAL_PRINTF("upload has an error, stop uploadingn"); } else { DBG_TERMINAL_PRINTF("buffer : {"temperature":%d}n", value); }
/* get floor in a mailbox from sensor */ value =mailbox_read(FLOOR_OFFSET);
/* upload floor to onenet cloud */ if (onenet_mqtt_upload_digit("floor", value) < 0) { DBG_TERMINAL_PRINTF("upload has an error, stop uploadingn"); } else { DBG_TERMINAL_PRINTF("buffer : {"floor":%d}n", value); } rt_thread_mdelay(5000); } return RT_EOK; }
|
4.5語(yǔ)音識(shí)別模塊
(1)實(shí)現(xiàn)方式
首先通過(guò)STM32CubeMX工具初始化SPI2配置,通過(guò)調(diào)用HAL庫(kù)函數(shù)實(shí)現(xiàn)開(kāi)發(fā)板與語(yǔ)音模塊通訊;其次初始化語(yǔ)音命令,通過(guò)使用PIN設(shè)備完成IRQ中斷方式監(jiān)聽(tīng)語(yǔ)音;最后,根據(jù)語(yǔ)音命令實(shí)現(xiàn)相對(duì)應(yīng)的功能:重啟設(shè)備和遠(yuǎn)程升級(jí)。
(2)語(yǔ)音識(shí)別
int audio_telling_entry(void *parameter) { uint8_t nAsrRes = 0; LD_init(); while(1) { switch(nAsrStatus) { case LD_ASR_RUNING: case LD_ASR_ERROR: break; case LD_ASR_NONE: nAsrStatus=LD_ASR_RUNING; if (LD_ASR()==0) nAsrStatus = LD_ASR_ERROR; break; case LD_ASR_FOUNDOK: nAsrRes = LD_GetResult(); switch(nAsrRes) { case CODE_CALLED: rt_kprintf("CODE_CALLEDn"); break; case CODE_REBOOT: /* reset cpu */ rt_kprintf("CODE_REBOOTn"); rt_hw_cpu_reset(); break; case CODE_UPDATE: /* update app */ rt_kprintf("CODE_UPDATEn"); extern int http_ota_fw_download(const char* uri); http_ota_fw_download(PKG_HTTP_OTA_URL); rt_kprintf("CODE_UPDATE ENDn"); break; case CODE_PLAY: rt_kprintf("CODE_PLAYn"); break; default: break; } nAsrStatus = LD_ASR_NONE; nAsrRes = 0; break; case LD_ASR_FOUNDZERO: default: nAsrStatus = LD_ASR_NONE; break; }
rt_thread_mdelay(1000); }
return RT_EOK; }
|
4.6本章小節(jié)
本章主要介紹了軟件模塊的設(shè)計(jì)思路和設(shè)計(jì)方法,以及包括在設(shè)計(jì)時(shí)需要注意的地方。
5.1作品展示
如圖5.1所示為app程序運(yùn)行的部分打印信息,圖5.2為升級(jí)過(guò)程信息,圖5.3氣壓、溫度和樓層數(shù)據(jù)上傳到onenet平臺(tái)。
圖5.1
圖5.2
圖5.3
視頻演示
5.2不足和改進(jìn)措施
本次創(chuàng)客創(chuàng)意大賽多功能氣壓計(jì)的設(shè)計(jì),由于個(gè)人能力和時(shí)間原因?qū)е履壳暗某绦蛉匀淮嬖谛⌒〉娜毕荩喝鐨鈮簜鞲衅鞑杉瘻囟群痛髿鈮簳r(shí)精度不夠高,有時(shí)會(huì)出現(xiàn)采集數(shù)值錯(cuò)誤的地方;其次語(yǔ)音識(shí)別功能靈敏度太高導(dǎo)致和初始化的命令碼相似時(shí)也會(huì)執(zhí)行重啟和升級(jí)功能。
針對(duì)上述問(wèn)題,可以通過(guò)增加多個(gè)雜亂的語(yǔ)音碼以減少命令的匹配度,同時(shí)增加氣壓傳感器的識(shí)別速度,以實(shí)現(xiàn)高精度采集。最后要著重定位算法,以達(dá)到根據(jù)溫度和大氣壓實(shí)現(xiàn)高精度定位問(wèn)題。
5.3心得和感悟
經(jīng)過(guò)這次短短一個(gè)多月的比賽,感覺(jué)自己的能力有了明顯的提升、對(duì)RT-Thread操作系統(tǒng)的認(rèn)識(shí)有漸漸地前進(jìn)了一個(gè)臺(tái)階。
如在剛開(kāi)始使用SPI驅(qū)動(dòng)時(shí)一直猶豫不決不知道是使用HAL庫(kù)還是使用SPI設(shè)備,剛開(kāi)始驅(qū)動(dòng)傳感器模塊時(shí)單純使用HAL庫(kù)函數(shù)還能解決問(wèn)題,但是到bootloader程序時(shí)要使用FAL軟件包就必須使用SPI設(shè)備和SFUD驅(qū)動(dòng),這才使我花了好幾天時(shí)間配置SPI設(shè)備和SFUD驅(qū)動(dòng),最后終于明白了要使用SPI設(shè)備需要這幾個(gè)步驟:首先要在RT-Thread Settings使能SPI和SFUD Drivers,其次在board.c文件中初始化HAL_SPI_MspInit函數(shù)和HAL_SPI_MspDeInit函數(shù),接著在rtconfig.h中定義宏BSP_USING_SPI和BSP_USING_SPI1,最后在stm32h7xx_hal_config.h文件中定義HAL_SPI_MODULE_ENABLED。若沒(méi)有定義HAL_SPI_MODULE_ENABLED這個(gè)宏編譯程序后會(huì)出現(xiàn)找不到與SPI HAL庫(kù)有關(guān)的函數(shù),這個(gè)地方比較容易忘記。
比如在調(diào)試語(yǔ)音命令升級(jí)程序時(shí)由于線程棧太小(512K)導(dǎo)致audio任務(wù)線程崩潰,最后通過(guò)增加其大?。?/span>10240K)順利的完成升級(jí)。
5.4本章小節(jié)
本章主要介紹了此次應(yīng)用開(kāi)發(fā)設(shè)計(jì)存在的不足和后期改進(jìn)的方法,以及比賽過(guò)程中的心得和感悟。