• 方案介紹
    • 一、項(xiàng)目背景
    • 二、系統(tǒng)設(shè)計(jì)
    • 三、部署華為云物聯(lián)網(wǎng)平臺(tái)
    • 四、上位機(jī)開(kāi)發(fā)
    • 五、代碼實(shí)現(xiàn)
  • 附件下載
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

基于STM32+華為云IOT設(shè)計(jì)的智能窗簾控制系統(tǒng)

5小時(shí)前
171
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

更多詳細(xì)資料請(qǐng)聯(lián)系.docx

共1個(gè)文件

一、項(xiàng)目背景

隨著智能家居技術(shù)的不斷發(fā)展,人們對(duì)于家居生活的需求也越來(lái)越高。智能窗簾作為智能家居領(lǐng)域的重要組成部分,為用戶提供了更便捷、舒適的生活體驗(yàn)。本項(xiàng)目基于STM32主控芯片華為云物聯(lián)網(wǎng)平臺(tái),設(shè)計(jì)一款智能窗簾控制系統(tǒng),以滿足家庭和商業(yè)場(chǎng)所的需求。

在本項(xiàng)目中,選擇了STM32F103ZET6作為主控芯片具有強(qiáng)大的處理能力和豐富的外設(shè)接口,適合用于物聯(lián)網(wǎng)設(shè)備的控制和通信。通過(guò)與ESP8266-WIFI模塊的連接,可以實(shí)現(xiàn)智能窗簾與華為云物聯(lián)網(wǎng)平臺(tái)的互聯(lián)互通,實(shí)現(xiàn)遠(yuǎn)程控制和監(jiān)測(cè)。

為了方便用戶的操作和控制,使用Qt開(kāi)發(fā)了Android手機(jī)APP和Windows上位機(jī)軟件,用戶可以通過(guò)這些應(yīng)用程序進(jìn)行窗簾的遠(yuǎn)程控制。同時(shí),本地窗簾也支持手動(dòng)控制,用戶可以通過(guò)物理按鈕或開(kāi)關(guān)來(lái)操作窗簾的開(kāi)關(guān)、升降等功能。

智能化方面,引入了語(yǔ)音識(shí)別技術(shù)(LD3320模塊),用戶可以通過(guò)語(yǔ)音指令來(lái)控制窗簾的運(yùn)行。這為用戶提供了更加便捷、智能的控制方式,使得窗簾的操作更加自然和智能化。

除了遠(yuǎn)程控制和智能化功能,還引入了自動(dòng)模式。在自動(dòng)模式下,系統(tǒng)會(huì)根據(jù)環(huán)境條件進(jìn)行智能判斷和控制。例如,當(dāng)檢測(cè)到陽(yáng)光強(qiáng)度超過(guò)設(shè)定閾值時(shí),系統(tǒng)會(huì)自動(dòng)關(guān)閉窗簾,以避免陽(yáng)光直射室內(nèi);在晚上時(shí),系統(tǒng)也會(huì)自動(dòng)拉上窗簾,提供更好的隱私和安全性。

本智能窗簾控制系統(tǒng)基于STM32主控芯片和華為云物聯(lián)網(wǎng)平臺(tái),結(jié)合語(yǔ)音識(shí)別、智能家居控制等功能,旨在為家庭和1商業(yè)場(chǎng)所提供便捷、舒適的智能化服務(wù)。通過(guò)遠(yuǎn)程控制、自動(dòng)模式和智能化功能,用戶可以實(shí)現(xiàn)對(duì)窗簾的靈活、智能的控制,提升生活質(zhì)量和用戶體驗(yàn)。

image-20230728112154869

image-20230728112455576

二、系統(tǒng)設(shè)計(jì)

2.1 硬件選型

在設(shè)計(jì)智能窗簾控制系統(tǒng)的硬件方案時(shí),需要考慮主控芯片、通信模塊和傳感器等關(guān)鍵組件的選型。

以下是當(dāng)前系統(tǒng)的具體硬件選型:

【1】主控芯片:采用STM32F103ZET6作為主控芯片。具備強(qiáng)大的處理能力和豐富的外設(shè)接口,適合用于物聯(lián)網(wǎng)設(shè)備的控制和通信??梢则?qū)動(dòng)各種傳感器和執(zhí)行器,并與ESP8266-WIFI模塊和LD3320語(yǔ)音識(shí)別模塊進(jìn)行通信。

【2】通信模塊:選擇了ESP8266-WIFI模塊作為通信模塊,用于連接華為云物聯(lián)網(wǎng)平臺(tái)。ESP8266-WIFI模塊具有低功耗、高集成度和穩(wěn)定的無(wú)線連接能力,能夠?qū)崿F(xiàn)智能窗簾與互聯(lián)網(wǎng)的互聯(lián)互通。

【3】光照傳感器:采用BH1750光照傳感器來(lái)檢測(cè)光照強(qiáng)度。BH1750是一種數(shù)字式光強(qiáng)度傳感器,能夠準(zhǔn)確測(cè)量環(huán)境光的強(qiáng)度。通過(guò)獲取光照強(qiáng)度數(shù)據(jù),系統(tǒng)可以根據(jù)設(shè)定的閾值來(lái)判斷是否需要自動(dòng)拉窗簾。

【4】語(yǔ)音識(shí)別模塊:選擇了LD3320語(yǔ)音識(shí)別模塊,用于實(shí)現(xiàn)語(yǔ)音控制功能。LD3320是一種高性能語(yǔ)音識(shí)別芯片,能夠?qū)崿F(xiàn)對(duì)語(yǔ)音指令的識(shí)別和解析。通過(guò)語(yǔ)音識(shí)別模塊,用戶可以通過(guò)語(yǔ)音指令來(lái)控制窗簾的開(kāi)合和模式切換。

【5】電機(jī)和驅(qū)動(dòng)模塊:選擇了28BYJ40步進(jìn)電機(jī)作為窗簾控制的電機(jī),并使用ULN2003驅(qū)動(dòng)模塊來(lái)驅(qū)動(dòng)電機(jī)。28BYJ40步進(jìn)電機(jī)具有較高的精度和穩(wěn)定性,適合用于窗簾的控制。ULN2003是一種高電壓、高電流驅(qū)動(dòng)芯片,能夠提供足夠的電流和電壓來(lái)驅(qū)動(dòng)步進(jìn)電機(jī)。

【6】用戶界面設(shè)備:采用Qt開(kāi)發(fā)Android手機(jī)APP和Windows上位機(jī)來(lái)實(shí)現(xiàn)用戶界面。通過(guò)這兩個(gè)界面,用戶可以進(jìn)行遠(yuǎn)程控制窗簾的操作,包括開(kāi)關(guān)窗簾、調(diào)整窗簾的開(kāi)合程度和切換窗簾的工作模式。

2.2 設(shè)計(jì)思路

智能窗簾控制系統(tǒng)的軟件設(shè)計(jì)主要包括主控程序、通信模塊驅(qū)動(dòng)、傳感器驅(qū)動(dòng)和用戶界面等部分。

以下是系統(tǒng)軟件設(shè)計(jì)的思路:

【1】主控程序:主控程序是系統(tǒng)的核心,負(fù)責(zé)控制窗簾的運(yùn)行、處理傳感器數(shù)據(jù)、與通信模塊進(jìn)行通信等。主控程序需要實(shí)現(xiàn)以下功能:

  • 初始化各個(gè)硬件模塊,包括通信模塊、傳感器和電機(jī)驅(qū)動(dòng)等。
  • 循環(huán)讀取傳感器數(shù)據(jù),根據(jù)數(shù)據(jù)進(jìn)行窗簾的控制和判斷。
  • 處理用戶的控制指令,包括遠(yuǎn)程控制指令和本地控制指令。
  • 與通信模塊進(jìn)行通信,實(shí)現(xiàn)與華為云物聯(lián)網(wǎng)平臺(tái)的互聯(lián)互通。
  • 實(shí)現(xiàn)自動(dòng)模式下的智能判斷和控制邏輯。

【2】通信模塊驅(qū)動(dòng):通信模塊驅(qū)動(dòng)負(fù)責(zé)與華為云物聯(lián)網(wǎng)平臺(tái)進(jìn)行通信,實(shí)現(xiàn)遠(yuǎn)程控制和數(shù)據(jù)傳輸。通信模塊驅(qū)動(dòng)需要實(shí)現(xiàn)以下功能:

  • 初始化通信模塊,建立與華為云物聯(lián)網(wǎng)平臺(tái)的連接。
  • 接收來(lái)自云平臺(tái)的控制指令,解析指令內(nèi)容。
  • 將傳感器數(shù)據(jù)和窗簾狀態(tài)等信息上傳到云平臺(tái),實(shí)現(xiàn)實(shí)時(shí)監(jiān)測(cè)和數(shù)據(jù)傳輸。

【3】傳感器驅(qū)動(dòng):傳感器驅(qū)動(dòng)負(fù)責(zé)與光敏傳感器、時(shí)間傳感器等傳感器進(jìn)行交互,獲取環(huán)境數(shù)據(jù)。傳感器驅(qū)動(dòng)需要實(shí)現(xiàn)以下功能:

  • 初始化傳感器,配置傳感器的工作模式和參數(shù)。
  • 定期讀取傳感器數(shù)據(jù),包括光敏傳感器的光強(qiáng)度和時(shí)間傳感器的時(shí)間信息。
  • 將傳感器數(shù)據(jù)傳遞給主控程序,供其進(jìn)行判斷和控制。

【4】用戶界面:用戶界面是用戶與系統(tǒng)進(jìn)行交互的界面,可以通過(guò)Android手機(jī)APP或Windows上位機(jī)軟件實(shí)現(xiàn)。用戶界面需要實(shí)現(xiàn)以下功能:

  • 顯示窗簾的狀態(tài)和實(shí)時(shí)數(shù)據(jù),如光強(qiáng)度、時(shí)間。
  • 提供遠(yuǎn)程控制窗簾的功能,包括開(kāi)關(guān)、升降和自動(dòng)模式的切換。
  • 接收用戶的控制指令,將指令傳遞給主控程序進(jìn)行處理。

三、部署華為云物聯(lián)網(wǎng)平臺(tái)

華為云官網(wǎng): https://www.huaweicloud.com/

打開(kāi)官網(wǎng),搜索物聯(lián)網(wǎng),就能快速找到 設(shè)備接入IoTDA。

image-20221204193824815

3.1 物聯(lián)網(wǎng)平臺(tái)介紹

華為云物聯(lián)網(wǎng)平臺(tái)(IoT 設(shè)備接入云服務(wù))提供海量設(shè)備的接入和管理能力,將物理設(shè)備聯(lián)接到云,支撐設(shè)備數(shù)據(jù)采集上云和云端下發(fā)命令給設(shè)備進(jìn)行遠(yuǎn)程控制,配合華為云其他產(chǎn)品,幫助我們快速構(gòu)筑物聯(lián)網(wǎng)解決方案。

使用物聯(lián)網(wǎng)平臺(tái)構(gòu)建一個(gè)完整的物聯(lián)網(wǎng)解決方案主要包括3部分:物聯(lián)網(wǎng)平臺(tái)、業(yè)務(wù)應(yīng)用和設(shè)備。

物聯(lián)網(wǎng)平臺(tái)作為連接業(yè)務(wù)應(yīng)用和設(shè)備的中間層,屏蔽了各種復(fù)雜的設(shè)備接口,實(shí)現(xiàn)設(shè)備的快速接入;同時(shí)提供強(qiáng)大的開(kāi)放能力,支撐行業(yè)用戶構(gòu)建各種物聯(lián)網(wǎng)解決方案。

設(shè)備可以通過(guò)固網(wǎng)、2G/3G/4G/5G、NB-IoT、Wifi等多種網(wǎng)絡(luò)接入物聯(lián)網(wǎng)平臺(tái),并使用LWM2M/CoAP、MQTT、HTTPS協(xié)議將業(yè)務(wù)數(shù)據(jù)上報(bào)到平臺(tái),平臺(tái)也可以將控制命令下發(fā)給設(shè)備。

業(yè)務(wù)應(yīng)用通過(guò)調(diào)用物聯(lián)網(wǎng)平臺(tái)提供的API,實(shí)現(xiàn)設(shè)備數(shù)據(jù)采集、命令下發(fā)、設(shè)備管理等業(yè)務(wù)場(chǎng)景。

img

3.2 開(kāi)通物聯(lián)網(wǎng)服務(wù)

地址: https://www.huaweicloud.com/product/iothub.html

image-20221204194233414

進(jìn)來(lái)默認(rèn)會(huì)提示開(kāi)通標(biāo)準(zhǔn)版,在2023的1月1號(hào)年之后沒(méi)有基礎(chǔ)版了。

image-20230313171311582

image-20230313171325183

開(kāi)通之后,點(diǎn)擊總覽,查看接入信息。 我們當(dāng)前設(shè)備準(zhǔn)備采用MQTT協(xié)議接入華為云平臺(tái),這里可以看到MQTT協(xié)議的地址和端口號(hào)等信息。

image-20230321154943337

總結(jié):

端口號(hào):   MQTT (1883)| MQTTS (8883)   
接入地址: 7445c6bcd3.st1.iotda-app.cn-north-4.myhuaweicloud.com

根據(jù)域名地址得到IP地址信息:

Microsoft Windows [版本 10.0.19044.2728]
(c) Microsoft Corporation。保留所有權(quán)利。

C:Users11266>ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com

正在 Ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字節(jié)的數(shù)據(jù):
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=42ms TTL=30
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=35ms TTL=30
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=36ms TTL=30
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=36ms TTL=30

117.78.5.125 的 Ping 統(tǒng)計(jì)信息:
    數(shù)據(jù)包: 已發(fā)送 = 4,已接收 = 4,丟失 = 0 (0% 丟失),
往返行程的估計(jì)時(shí)間(以毫秒為單位):
    最短 = 35ms,最長(zhǎng) = 42ms,平均 = 37ms

C:Users11266>

image-20230321161044723

MQTT協(xié)議接入端口號(hào)有兩個(gè),1883是非加密端口,8883是證書(shū)加密端口,單片機(jī)無(wú)法加載證書(shū),所以使用1883端口比較合適。 接下來(lái)的ESP8266就采用1883端口連接華為云物聯(lián)網(wǎng)平臺(tái)。

3.3 創(chuàng)建產(chǎn)品

(1)創(chuàng)建產(chǎn)品

點(diǎn)擊產(chǎn)品頁(yè),再點(diǎn)擊左上角創(chuàng)建產(chǎn)品。

image-20230313171503547

(2)填寫產(chǎn)品信息

根據(jù)自己產(chǎn)品名字填寫。

image-20230728110839855

(3)產(chǎn)品創(chuàng)建成功

image-20230728110854861

(4)添加自定義模型

產(chǎn)品創(chuàng)建完成之后,點(diǎn)擊進(jìn)入產(chǎn)品詳情頁(yè)面,翻到最下面可以看到模型定義。

先點(diǎn)擊自定義模型。

image-20230313171815860

再創(chuàng)建一個(gè)服務(wù)ID。

image-20230321155733514

接著點(diǎn)擊新增屬性。

image-20230321155756735

3.4 添加設(shè)備

產(chǎn)品是屬于上層的抽象模型,接下來(lái)在產(chǎn)品模型下添加實(shí)際的設(shè)備。添加的設(shè)備最終需要與真實(shí)的設(shè)備關(guān)聯(lián)在一起,完成數(shù)據(jù)交互。

(1)注冊(cè)設(shè)備

image-20230313173158883

(2)根據(jù)自己的設(shè)備填寫

image-20230728110745853

(3)保存設(shè)備信息

創(chuàng)建完畢之后,點(diǎn)擊保存并關(guān)閉,得到創(chuàng)建的設(shè)備密匙信息。該信息在后續(xù)生成MQTT三元組的時(shí)候需要使用。

image-20230321160252288

(4) 設(shè)備創(chuàng)建完成

image-20230728110819739

3.5 MQTT協(xié)議主題訂閱與發(fā)布

(1)MQTT協(xié)議介紹

當(dāng)前的設(shè)備是采用MQTT協(xié)議與華為云平臺(tái)進(jìn)行通信。

MQTT是一個(gè)物聯(lián)網(wǎng)傳輸協(xié)議,它被設(shè)計(jì)用于輕量級(jí)的發(fā)布/訂閱式消息傳輸,旨在為低帶寬和不穩(wěn)定的網(wǎng)絡(luò)環(huán)境中的物聯(lián)網(wǎng)設(shè)備提供可靠的網(wǎng)絡(luò)服務(wù)。MQTT是專門針對(duì)物聯(lián)網(wǎng)開(kāi)發(fā)的輕量級(jí)傳輸協(xié)議。MQTT協(xié)議針對(duì)低帶寬網(wǎng)絡(luò),低計(jì)算能力的設(shè)備,做了特殊的優(yōu)化,使得其能適應(yīng)各種物聯(lián)網(wǎng)應(yīng)用場(chǎng)景。目前MQTT擁有各種平臺(tái)和設(shè)備上的客戶端,已經(jīng)形成了初步的生態(tài)系統(tǒng)。

MQTT是一種消息隊(duì)列協(xié)議,使用發(fā)布/訂閱消息模式,提供一對(duì)多的消息發(fā)布,解除應(yīng)用程序耦合,相對(duì)于其他協(xié)議,開(kāi)發(fā)更簡(jiǎn)單;MQTT協(xié)議是工作在TCP/IP協(xié)議上;由TCP/IP協(xié)議提供穩(wěn)定的網(wǎng)絡(luò)連接;所以,只要具備TCP協(xié)議棧的網(wǎng)絡(luò)設(shè)備都可以使用MQTT協(xié)議。 本次設(shè)備采用的ESP8266就具備TCP協(xié)議棧,能夠建立TCP連接,所以,配合STM32代碼里封裝的MQTT協(xié)議,就可以與華為云平臺(tái)完成通信。

華為云的MQTT協(xié)議接入幫助文檔在這里: https://support.huaweicloud.com/devg-iothub/iot_02_2200.html

img

業(yè)務(wù)流程:

img

(2)華為云平臺(tái)MQTT協(xié)議使用限制

描述 限制
支持的MQTT協(xié)議版本 3.1.1
與標(biāo)準(zhǔn)MQTT協(xié)議的區(qū)別 支持Qos 0和Qos 1支持Topic自定義不支持QoS2不支持will、retain msg
MQTTS支持的安全等級(jí) 采用TCP通道基礎(chǔ) + TLS協(xié)議(最高TLSv1.3版本)
單帳號(hào)每秒最大MQTT連接請(qǐng)求數(shù) 無(wú)限制
單個(gè)設(shè)備每分鐘支持的最大MQTT連接數(shù) 1
單個(gè)MQTT連接每秒的吞吐量,即帶寬,包含直連設(shè)備和網(wǎng)關(guān) 3KB/s
MQTT單個(gè)發(fā)布消息最大長(zhǎng)度,超過(guò)此大小的發(fā)布請(qǐng)求將被直接拒絕 1MB
MQTT連接心跳時(shí)間建議值 心跳時(shí)間限定為30至1200秒,推薦設(shè)置為120秒
產(chǎn)品是否支持自定義Topic 支持
消息發(fā)布與訂閱 設(shè)備只能對(duì)自己的Topic進(jìn)行消息發(fā)布與訂閱
每個(gè)訂閱請(qǐng)求的最大訂閱數(shù) 無(wú)限制

(3)主題訂閱格式

幫助文檔地址:https://support.huaweicloud.com/devg-iothub/iot_02_2200.html

image-20221207153310037

對(duì)于設(shè)備而言,一般會(huì)訂閱平臺(tái)下發(fā)消息給設(shè)備 這個(gè)主題。

設(shè)備想接收平臺(tái)下發(fā)的消息,就需要訂閱平臺(tái)下發(fā)消息給設(shè)備 的主題,訂閱后,平臺(tái)下發(fā)消息給設(shè)備,設(shè)備就會(huì)收到消息。

如果設(shè)備想要知道平臺(tái)下發(fā)的消息,需要訂閱上面圖片里標(biāo)注的主題。

以當(dāng)前設(shè)備為例,最終訂閱主題的格式如下:
$oc/devices/{device_id}/sys/messages/down

最終的格式:
$oc/devices/6419627e40773741f9fbdac7_dev1/sys/messages/down

?

(4)主題發(fā)布格式

對(duì)于設(shè)備來(lái)說(shuō),主題發(fā)布表示向云平臺(tái)上傳數(shù)據(jù),將最新的傳感器數(shù)據(jù),設(shè)備狀態(tài)上傳到云平臺(tái)。

這個(gè)操作稱為:屬性上報(bào)。

幫助文檔地址:https://support.huaweicloud.com/usermanual-iothub/iot_06_v5_3010.html

image-20221207153637391

根據(jù)幫助文檔的介紹, 當(dāng)前設(shè)備發(fā)布主題,上報(bào)屬性的格式總結(jié)如下:

發(fā)布的主題格式:
$oc/devices/{device_id}/sys/properties/report
 
最終的格式:
$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/report
發(fā)布主題時(shí),需要上傳數(shù)據(jù),這個(gè)數(shù)據(jù)格式是JSON格式。

上傳的JSON數(shù)據(jù)格式如下:

{
  "services": [
    {
      "service_id": <填服務(wù)ID>,
      "properties": {
        "<填屬性名稱1>": <填屬性值>,
        "<填屬性名稱2>": <填屬性值>,
        ..........
      }
    }
  ]
}
根據(jù)JSON格式,一次可以上傳多個(gè)屬性字段。 這個(gè)JSON格式里的,服務(wù)ID,屬性字段名稱,屬性值類型,在前面創(chuàng)建產(chǎn)品的時(shí)候就已經(jīng)介紹了,不記得可以翻到前面去查看。

根據(jù)這個(gè)格式,組合一次上傳的屬性數(shù)據(jù):
{"services": [{"service_id": "stm32","properties":{"DS18B20":18,"motor_water":1,"motor_oxygen":1,"temp_max":10,"water_hp":130,"motor_food":0,"time_food":0,"oxygen_food":3}}]}

3.6 MQTT三元組

MQTT協(xié)議登錄需要填用戶ID,設(shè)備ID,設(shè)備密碼等信息,就像我們平時(shí)登錄QQ,微信一樣要輸入賬號(hào)密碼才能登錄。MQTT協(xié)議登錄的這3個(gè)參數(shù),一般稱為MQTT三元組。

接下來(lái)介紹,華為云平臺(tái)的MQTT三元組參數(shù)如何得到。

(1)MQTT服務(wù)器地址

要登錄MQTT服務(wù)器,首先記得先知道服務(wù)器的地址是多少,端口是多少。

幫助文檔地址:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home

image-20230302135718882

MQTT協(xié)議的端口支持1883和8883,它們的區(qū)別是:8883 是加密端口更加安全。但是單片機(jī)上使用比較困難,所以當(dāng)前的設(shè)備是采用1883端口進(jìn)連接的。

根據(jù)上面的域名和端口號(hào),得到下面的IP地址和端口號(hào)信息: 如果設(shè)備支持填寫域名可以直接填域名,不支持就直接填寫IP地址。 (IP地址就是域名解析得到的)

華為云的MQTT服務(wù)器地址:114.116.232.138
域名:7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com
華為云的MQTT端口號(hào):1883

(2)生成MQTT三元組

華為云提供了一個(gè)在線工具,用來(lái)生成MQTT鑒權(quán)三元組: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

打開(kāi)這個(gè)工具,填入設(shè)備的信息(也就是剛才創(chuàng)建完設(shè)備之后保存的信息),點(diǎn)擊生成,就可以得到MQTT的登錄信息了。

下面是打開(kāi)的頁(yè)面:

image-20221207154917230

填入設(shè)備的信息: (上面兩行就是設(shè)備創(chuàng)建完成之后保存得到的)

直接得到三元組信息。

image-20230321160708924

image-20230321160718302

得到三元組之后,設(shè)備端通過(guò)MQTT協(xié)議登錄鑒權(quán)的時(shí)候,填入?yún)?shù)即可。

ClientId 6419627e40773741f9fbdac7_dev1_0_0_2023032108
Username 6419627e40773741f9fbdac7_dev1
Password 861ac9e6a579d36888b2aaf97714be7af6c77017b017162884592bd68b086a6e

3.7 模擬設(shè)備登錄測(cè)試

經(jīng)過(guò)上面的步驟介紹,已經(jīng)創(chuàng)建了產(chǎn)品,設(shè)備,數(shù)據(jù)模型,得到MQTT登錄信息。 接下來(lái)就用MQTT客戶端軟件模擬真實(shí)的設(shè)備來(lái)登錄平臺(tái)。測(cè)試與服務(wù)器通信是否正常。

(1)填入登錄信息

打開(kāi)MQTT客戶端軟件,對(duì)號(hào)填入相關(guān)信息(就是上面的文本介紹)。然后,點(diǎn)擊登錄,訂閱主題,發(fā)布主題。

image-20230321161132971

(2)打開(kāi)網(wǎng)頁(yè)查看

完成上面的操作之后,打開(kāi)華為云網(wǎng)頁(yè)后臺(tái),可以看到設(shè)備已經(jīng)在線了。

點(diǎn)擊詳情頁(yè)面,可以看到上傳的數(shù)據(jù)。

到此,云平臺(tái)的部署已經(jīng)完成,設(shè)備已經(jīng)可以正常上傳數(shù)據(jù)了。

四、上位機(jī)開(kāi)發(fā)

為了方便查看設(shè)備上傳的數(shù)據(jù),對(duì)設(shè)備進(jìn)行遠(yuǎn)程控制,接下來(lái)利用Qt開(kāi)發(fā)一款A(yù)ndroid和windows系統(tǒng)的上位機(jī)。

使用華為云平臺(tái)提供的API接口獲取設(shè)備上傳的數(shù)據(jù),也可以給設(shè)備下發(fā)指令,控制設(shè)備。

為了方便查看設(shè)備上傳的數(shù)據(jù),對(duì)設(shè)備進(jìn)行遠(yuǎn)程控制,接下來(lái)利用Qt開(kāi)發(fā)一款A(yù)ndroid和windows系統(tǒng)的上位機(jī)。

使用華為云平臺(tái)提供的API接口獲取設(shè)備上傳的數(shù)據(jù),也可以給設(shè)備下發(fā)指令,控制設(shè)備。

4.1 Qt開(kāi)發(fā)環(huán)境安裝

Qt的中文官網(wǎng): https://www.qt.io/zh-cn/image-20221207160550486

image-20221207160606892

QT5.12.6的下載地址:https://download.qt.io/archive/qt/5.12/5.12.6

打開(kāi)下載鏈接后選擇下面的版本進(jìn)行下載:

qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details

軟件安裝時(shí)斷網(wǎng)安裝,否則會(huì)提示輸入賬戶。

安裝的時(shí)候,第一個(gè)復(fù)選框里勾選一個(gè)mingw 32編譯器即可,其他的不管默認(rèn)就行,直接點(diǎn)擊下一步繼續(xù)安裝。

image-20221203151742653

說(shuō)明: 我這里只是介紹PC端的環(huán)境搭建(這個(gè)比較簡(jiǎn)單)。 Android的開(kāi)發(fā)環(huán)境比較麻煩,可以去我的博客里看詳細(xì)文章。

選擇MinGW 32-bit 編譯器:

image-20221203151750344

4.2 創(chuàng)建IAM賬戶

創(chuàng)建一個(gè)IAM賬戶,因?yàn)榻酉聛?lái)開(kāi)發(fā)上位機(jī),需要使用云平臺(tái)的API接口,這些接口都需要token進(jìn)行鑒權(quán)。簡(jiǎn)單來(lái)說(shuō),就是身份的認(rèn)證。 調(diào)用接口獲取Token時(shí),就需要填寫IAM賬號(hào)信息。所以,接下來(lái)演示一下過(guò)程。

地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

獲取Token時(shí),除了AIM賬號(hào)外,還需要項(xiàng)目憑證:

faa0973835ab409ab48182e2590f4ad3

image-20230321161348409

image-20230321161414487

鼠標(biāo)點(diǎn)擊自己昵稱,點(diǎn)擊統(tǒng)一身份認(rèn)證。

image-20230321161433209

點(diǎn)擊左上角創(chuàng)建用戶

image-20230321161450557

image-20221207161209880

image-20221207161308917

image-20221207161327200

創(chuàng)建成功:

image-20221212174359962

image-20221212174412097

image-20230321161557848

4.3 獲取影子數(shù)據(jù)

幫助文檔:https://support.huaweicloud.com/api-iothub/iot_06_v5_0079.html

設(shè)備影子介紹:

設(shè)備影子是一個(gè)用于存儲(chǔ)和檢索設(shè)備當(dāng)前狀態(tài)信息的JSON文檔。
每個(gè)設(shè)備有且只有一個(gè)設(shè)備影子,由設(shè)備ID唯一標(biāo)識(shí)
設(shè)備影子僅保存最近一次設(shè)備的上報(bào)數(shù)據(jù)和預(yù)期數(shù)據(jù)
無(wú)論該設(shè)備是否在線,都可以通過(guò)該影子獲取和設(shè)置設(shè)備的屬性

簡(jiǎn)單來(lái)說(shuō):設(shè)備影子就是保存,設(shè)備最新上傳的一次數(shù)據(jù)。

我們?cè)O(shè)計(jì)的軟件里,如果想要獲取設(shè)備的最新?tīng)顟B(tài)信息,就采用設(shè)備影子接口。

如果對(duì)接口不熟悉,可以先進(jìn)行在線調(diào)試:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow

在線調(diào)試接口,可以請(qǐng)求影子接口,了解請(qǐng)求,與返回的數(shù)據(jù)格式。

image-20230321161636567

image-20230321161701419

設(shè)備影子接口返回的數(shù)據(jù)如下:

{
 "device_id": "6419627e40773741f9fbdac7_dev1",
 "shadow": [
  {
   "service_id": "stm32",
   "desired": {
    "properties": null,
    "event_time": null
   },
   "reported": {
    "properties": {
     "DS18B20": 18,
     "motor_water": 1,
     "motor_oxygen": 1,
     "temp_max": 10,
     "water_hp": 130,
     "motor_food": 0,
     "time_food": 0,
     "oxygen_food": 3
    },
    "event_time": "20230321T081126Z"
   },
   "version": 0
  }
 ]
}

4.4 修改設(shè)備屬性

地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html

接口說(shuō)明

設(shè)備的產(chǎn)品模型中定義了物聯(lián)網(wǎng)平臺(tái)可向設(shè)備下發(fā)的屬性,應(yīng)用服務(wù)器可調(diào)用此接口向指定設(shè)備下發(fā)屬性。平臺(tái)負(fù)責(zé)將屬性以同步方式發(fā)送給設(shè)備,并將設(shè)備執(zhí)行屬性結(jié)果同步返回。

修改設(shè)備屬性的接口,可以讓服務(wù)器給設(shè)備下發(fā)指令,如果需要控制設(shè)備。

在線調(diào)試地址:

https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=UpdateProperties

修改設(shè)備屬性是屬于同步命令,需要設(shè)備在線才可以進(jìn)行調(diào)試,先使用MQTT客戶端登錄服務(wù)器,模擬設(shè)備上線。

然后進(jìn)行調(diào)試,測(cè)試數(shù)據(jù)遠(yuǎn)程下發(fā)給設(shè)備。

【1】利用MQTT客戶端先登錄設(shè)備 (這是同步命令,必須在線才能調(diào)試)

image-20230321161923007

【2】點(diǎn)擊調(diào)試

image-20230321161905033

{"services":{"temp_max":100}}

【4】可以看到,MQTT客戶端軟件上已經(jīng)收到了服務(wù)器下發(fā)的消息

image-20230313175819901

由于是同步命令,服務(wù)器必須要收到設(shè)備的響應(yīng)才能順利完成一個(gè)流程,設(shè)備響應(yīng)了服務(wù)器才能確定數(shù)據(jù)下發(fā)成功。

image-20230321161941584

MQTT設(shè)備端如何響應(yīng)呢?

設(shè)備響應(yīng)格式說(shuō)明:https://support.huaweicloud.com/api-iothub/iot_06_v5_3008.html

image-20221203163532648

下面進(jìn)行實(shí)操:

當(dāng)服務(wù)器通過(guò)在線調(diào)試,發(fā)送指令下來(lái)之后,客戶端將請(qǐng)求ID復(fù)制下來(lái),添加到發(fā)布主題的格式里,再回復(fù)回去,服務(wù)器收到了響應(yīng),一次屬性修改就完美完成了。

image-20230321162053263

就是成功的狀態(tài):

image-20230321162026282

**下面是請(qǐng)求的總結(jié): ** (響應(yīng)服務(wù)器的修改設(shè)備屬性請(qǐng)求)

上報(bào)主題的格式:$oc/devices/{device_id}/sys/properties/set/response/request_id=

$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/set/response/request_id=

響應(yīng)的數(shù)據(jù):
{"result_code": 0,"result_desc": "success"}

4.5 設(shè)計(jì)上位機(jī)

前面2講解了需要用的API接口,接下來(lái)就使用Qt設(shè)計(jì)上位機(jī),設(shè)計(jì)界面,完成整體上位機(jī)的邏輯設(shè)計(jì)。

【1】新建Qt工程

image-20230302144331541

選擇工程路徑,放在英文路徑下。

image-20230321162532573

image-20230313180428670

image-20230313180451177

image-20230313180504518

image-20230321162620141

創(chuàng)建完畢。

新建Android的模板:

image-20230321162657975

image-20230321162731010

image-20230321162741791

image-20230321162812486

【2】界面設(shè)計(jì)

image-20230728111857337

【4】代碼設(shè)計(jì):配置參數(shù)讀取與保存

/*
功能: 保存數(shù)據(jù)到文件
*/
void Widget::SaveDataToFile(QString text)
{
    /*保存數(shù)據(jù)到文件,方便下次加載*/
    QString file;
    file=QCoreApplication::applicationDirPath()+"/"+ConfigFile;
    QFile filesrc(file);
    filesrc.open(QIODevice::WriteOnly);
    QDataStream out(&filesrc);
    out << text;  //序列化寫字符串
    filesrc.flush();
    filesrc.close();
}


/*
功能: 從文件讀取數(shù)據(jù)
*/
QString Widget::ReadDataFile(void)
{
    //讀取配置文件
    QString text,data;
    text=QCoreApplication::applicationDirPath()+"/"+ConfigFile;

    //判斷文件是否存在
    if(QFile::exists(text))
    {
        QFile filenew(text);
        filenew.open(QIODevice::ReadOnly);
        QDataStream in(&filenew); // 從文件讀取序列化數(shù)據(jù)
        in >> data; //提取寫入的數(shù)據(jù)
        filenew.close();
    }
    return data; //返回值讀取的值
}

【3】代碼設(shè)計(jì):云端數(shù)據(jù)解析

//解析反饋結(jié)果
void Widget::replyFinished(QNetworkReply *reply)
{
    QString displayInfo;

    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    //讀取所有數(shù)據(jù)
    QByteArray replyData = reply->readAll();

    qDebug()<<"狀態(tài)碼:"<<statusCode;
    qDebug()<<"反饋的數(shù)據(jù):"<<QString(replyData);

    //更新token
    if(function_select==3)
    {
        displayInfo="token 更新失敗.";
        //讀取HTTP響應(yīng)頭的數(shù)據(jù)
        QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs();
        qDebug()<<"HTTP響應(yīng)頭數(shù)量:"<<RawHeader.size();
        for(int i=0;i<RawHeader.size();i++)
        {
            QString first=RawHeader.at(i).first;
            QString second=RawHeader.at(i).second;
            if(first=="X-Subject-Token")
            {
                Token=second.toUtf8();
                displayInfo="token 更新成功.";

                //保存到文件
                SaveDataToFile(Token);
                break;
            }
        }
        QMessageBox::information(this,"提示",displayInfo,QMessageBox::Ok,QMessageBox::Ok);
        return;
    }

    //判斷狀態(tài)碼
    if(200 != statusCode)
    {
        //解析數(shù)據(jù)
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判斷是否是對(duì)象,然后開(kāi)始解析數(shù)據(jù)
            if(document.isObject())
            {
                QString error_str="";
                QJsonObject obj = document.object();
                QString error_code;
                //解析錯(cuò)誤代碼
                if(obj.contains("error_code"))
                {
                    error_code=obj.take("error_code").toString();
                    error_str+="錯(cuò)誤代碼:";
                    error_str+=error_code;
                    error_str+="n";
                }
                if(obj.contains("error_msg"))
                {
                    error_str+="錯(cuò)誤消息:";
                    error_str+=obj.take("error_msg").toString();
                    error_str+="n";
                }

                //顯示錯(cuò)誤代碼
                QMessageBox::information(this,"提示",error_str,QMessageBox::Ok,QMessageBox::Ok);
            }
         }
        return;
    }

    //設(shè)置屬性
    if(function_select==12 || function_select==13)
    {
        //解析數(shù)據(jù)
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判斷是否是對(duì)象,然后開(kāi)始解析數(shù)據(jù)
            if(document.isObject())
            {
                QJsonObject obj = document.object();
                if(obj.contains("response"))
                {
                    QJsonObject obj1=obj.take("response").toObject();
                    int val=0;
                    QString success;
                    if(obj1.contains("result_code"))
                    {
                         val=obj1.take("result_code").toInt();
                    }
                    if(obj1.contains("result_desc"))
                    {
                         success=obj1.take("result_desc").toString();
                    }

                    if(val==0 && success =="success")
                    {
                        //顯示狀態(tài)
                        QMessageBox::information(this,"提示","遠(yuǎn)程命令操作完成.",QMessageBox::Ok,QMessageBox::Ok);
                        return;
                    }
                    else
                    {
                        //顯示狀態(tài)
                        QMessageBox::information(this,"提示","設(shè)備未正確回應(yīng).請(qǐng)檢查設(shè)備網(wǎng)絡(luò).",QMessageBox::Ok,QMessageBox::Ok);
                        return;
                    }
                }
            }
         }
    }

    //查詢?cè)O(shè)備屬性
    if(function_select==0)
    {
        //解析數(shù)據(jù)
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判斷是否是對(duì)象,然后開(kāi)始解析數(shù)據(jù)
            if(document.isObject())
            {
                QJsonObject obj = document.object();
                if(obj.contains("shadow"))
                {
                    QJsonArray array=obj.take("shadow").toArray();
                    for(int i=0;i<array.size();i++)
                    {
                        QJsonObject obj2=array.at(i).toObject();
                        if(obj2.contains("reported"))
                        {
                            QJsonObject obj3=obj2.take("reported").toObject();


                            if(obj3.contains("properties"))
                            {
                                QJsonObject properties=obj3.take("properties").toObject();

                                qDebug()<<"開(kāi)始解析數(shù)據(jù)....";
                            }
                        }
                    }
                }
            }
         }
        return;
    }
}

五、代碼實(shí)現(xiàn)

5.1 ESP8266連接云平臺(tái)實(shí)現(xiàn)代碼

以下是使用STM32F103ZET6和ESP8266連接華為云物聯(lián)網(wǎng)平臺(tái),通過(guò)MQTT協(xié)議實(shí)現(xiàn)設(shè)備登錄、主題訂閱和主題發(fā)布的實(shí)現(xiàn)代碼:

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"

// 定義ESP8266的串口
USART_TypeDef* ESP_USARTx = USART1;

// 定義MQTT服務(wù)器的地址和端口
const char* MQTT_SERVER = "mqtt.eclipse.org";
const int MQTT_PORT = 1883;

// 定義設(shè)備ID和設(shè)備密碼
const char* DEVICE_ID = "your_device_id";
const char* DEVICE_PASSWORD = "your_device_password";

// 定義訂閱的主題
const char* SUBSCRIBE_TOPIC = "your_subscribe_topic";

// 定義發(fā)布的主題
const char* PUBLISH_TOPIC = "your_publish_topic";

// 定義接收緩沖區(qū)和發(fā)送緩沖區(qū)的大小
#define RX_BUFFER_SIZE 1024
#define TX_BUFFER_SIZE 1024

// 定義接收緩沖區(qū)和發(fā)送緩沖區(qū)
char rxBuffer[RX_BUFFER_SIZE];
char txBuffer[TX_BUFFER_SIZE];

// 定義接收緩沖區(qū)的索引和標(biāo)志位
volatile uint16_t rxIndex = 0;
volatile uint8_t rxComplete = 0;

// 發(fā)送數(shù)據(jù)到ESP8266
void ESP8266_SendData(const char* data) {
    sprintf(txBuffer, "%srn", data);
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
    USART_SendData(ESP_USARTx, (uint16_t)'r');
    USART_SendData(ESP_USARTx, (uint16_t)'n');
}

// 從ESP8266接收數(shù)據(jù)
void ESP8266_ReceiveData(uint16_t size) {
    while (size--) {
        rxBuffer[rxIndex++] = USART_ReceiveData(ESP_USARTx);
    }
    if (rxIndex >= RX_BUFFER_SIZE) {
        rxComplete = 1;
        rxIndex = 0;
    }
}

// 處理接收到的數(shù)據(jù)
void ProcessReceivedData() {
    // TODO: 根據(jù)接收到的數(shù)據(jù)進(jìn)行處理
}

// ESP8266串口中斷處理函數(shù)
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(ESP_USARTx, USART_IT_RXNE) != RESET) {
        ESP8266_ReceiveData(1);
    }
}

// 連接到MQTT服務(wù)器
void MQTT_Connect() {
    // 發(fā)送連接請(qǐng)求
    sprintf(txBuffer, "AT+CIPSTART="TCP","%s",%drn", MQTT_SERVER, MQTT_PORT);
    ESP8266_SendData(txBuffer);
    // 等待連接成功
    while (!strstr(rxBuffer, "CONNECTED")) {
        if (rxComplete) {
            ProcessReceivedData();
            rxComplete = 0;
        }
    }
    // 發(fā)送MQTT連接請(qǐng)求
    sprintf(txBuffer, "AT+MQTTCONNECT="%s","%s"rn", DEVICE_ID, DEVICE_PASSWORD);
    ESP8266_SendData(txBuffer);
    // 等待連接成功
    while (!strstr(rxBuffer, "CONNECTED")) {
        if (rxComplete) {
            ProcessReceivedData();
            rxComplete = 0;
        }
    }
}

// 訂閱主題
void MQTT_Subscribe() {
    sprintf(txBuffer, "AT+MQTTSUBSCRIBE="%s"rn", SUBSCRIBE_TOPIC);
    ESP8266_SendData(txBuffer);
}

// 發(fā)布消息
void MQTT_Publish(const char* message) {
    sprintf(txBuffer, "AT+MQTTPUBLISH="%s","%s"rn", PUBLISH_TOPIC, message);
    ESP8266_SendData(txBuffer);
}

int main(void) {
    // 初始化ESP8266的串口
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(ESP_USARTx, &USART_InitStructure);
    USART_Cmd(ESP_USARTx, ENABLE);
    USART_ITConfig(ESP_USARTx, USART_IT_RXNE, ENABLE);
    NVIC_EnableIRQ(USART1_IRQn);

    // 連接到MQTT服務(wù)器
    MQTT_Connect();

    // 訂閱主題
    MQTT_Subscribe();

    while (1) {
        if (rxComplete) {
            ProcessReceivedData();
            rxComplete = 0;
        }
        
        // TODO: 處理其他業(yè)務(wù)邏輯
        
        // 發(fā)布消息
        MQTT_Publish("Hello, MQTT!");
        
        // 延時(shí)一段時(shí)間
        delay_ms(1000);
    }
}

以上代碼用于演示使用STM32F103ZET6和ESP8266連接華為云物聯(lián)網(wǎng)平臺(tái),通過(guò)MQTT協(xié)議實(shí)現(xiàn)設(shè)備登錄、主題訂閱和主題發(fā)布的基本功能。

5.2 ESP8266的MQTT協(xié)議指令

ESP8266通過(guò)MQTT協(xié)議連接到服務(wù)器的相關(guān)AT指令主要有以下幾個(gè):

【1】AT+CIPSTART:建立TCP連接

  • 功能:使用TCP協(xié)議連接到遠(yuǎn)程服務(wù)器
  • 用法:AT+CIPSTART=“TCP”,“<服務(wù)器地址>”,<服務(wù)器端口>
  • 示例:AT+CIPSTART=“TCP”,“mqtt.eclipse.org”,1883

【2】AT+MQTTCONNECT:連接到MQTT服務(wù)器

  • 功能:使用MQTT協(xié)議連接到MQTT服務(wù)器
  • 用法:AT+MQTTCONNECT=“<設(shè)備ID>”,“<設(shè)備密碼>”
  • 示例:AT+MQTTCONNECT=“your_device_id”,“your_device_password”

【3】AT+MQTTPUBLISH:發(fā)布消息

  • 功能:向指定主題發(fā)布消息
  • 用法:AT+MQTTPUBLISH=“<主題>”,“<消息內(nèi)容>”
  • 示例:AT+MQTTPUBLISH=“your_publish_topic”,“Hello, MQTT!”

【4】AT+MQTTSUBSCRIBE:訂閱主題

  • 功能:訂閱指定的主題
  • 用法:AT+MQTTSUBSCRIBE=“<主題>”
  • 示例:AT+MQTTSUBSCRIBE=“your_subscribe_topic”

【5】AT+CIPCLOSE:關(guān)閉TCP連接

  • 功能:關(guān)閉當(dāng)前的TCP連接
  • 用法:AT+CIPCLOSE

這些AT指令可以通過(guò)串口與ESP8266進(jìn)行通信,實(shí)現(xiàn)與MQTT服務(wù)器的連接、消息發(fā)布和訂閱等功能。通過(guò)這些指令,可以在嵌入式設(shè)備上實(shí)現(xiàn)與云端的通信和數(shù)據(jù)交換,從而實(shí)現(xiàn)物聯(lián)網(wǎng)應(yīng)用。

5.2 步進(jìn)電機(jī)控制代碼

以下是使用STM32F103ZET6單片機(jī)通過(guò)ULN2003驅(qū)動(dòng)芯片控制28BYJ-48步進(jìn)電機(jī)實(shí)現(xiàn)角度控制和速度控制的實(shí)現(xiàn)代碼:

#include "stm32f10x.h"
#include "delay.h"

// 定義步進(jìn)電機(jī)控制引腳
#define IN1_PIN GPIO_Pin_0
#define IN2_PIN GPIO_Pin_1
#define IN3_PIN GPIO_Pin_2
#define IN4_PIN GPIO_Pin_3
#define IN_PORT GPIOA

// 定義步進(jìn)電機(jī)角度和速度參數(shù)
#define ANGLE_1 512 // 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)一圈的步數(shù)
#define SPEED_1 5   // 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)的速度

// 步進(jìn)電機(jī)轉(zhuǎn)動(dòng)順序
const uint8_t stepSequence[8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09};

// 步進(jìn)電機(jī)當(dāng)前角度和速度
volatile uint16_t currentAngle = 0;
volatile uint8_t currentSpeed = 0;

// 初始化步進(jìn)電機(jī)控制引腳
void StepperMotor_Init() {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(IN_PORT, &GPIO_InitStructure);
}

// 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)一步
void StepperMotor_Step() {
    static uint8_t stepIndex = 0;
    GPIO_Write(IN_PORT, stepSequence[stepIndex]);
    stepIndex = (stepIndex + 1) % 8;
}

// 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)到指定角度
void StepperMotor_MoveToAngle(uint16_t targetAngle) {
    uint16_t steps = targetAngle - currentAngle;
    uint16_t absSteps = steps > 0 ? steps : -steps;
    uint8_t direction = steps > 0 ? 1 : -1;
    for (uint16_t i = 0; i < absSteps; i++) {
        StepperMotor_Step();
        delay_ms(2); // 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)的速度
    }
    currentAngle = targetAngle;
}

// 控制步進(jìn)電機(jī)以指定速度連續(xù)轉(zhuǎn)動(dòng)
void StepperMotor_MoveWithSpeed(uint8_t speed) {
    currentSpeed = speed;
    while (1) {
        StepperMotor_Step();
        delay_ms(20 - currentSpeed); // 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)的速度
    }
}

int main(void) {
    // 初始化步進(jìn)電機(jī)控制引腳
    StepperMotor_Init();
    
    // 控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)到指定角度
    StepperMotor_MoveToAngle(ANGLE_1);
    
    // 控制步進(jìn)電機(jī)以指定速度連續(xù)轉(zhuǎn)動(dòng)
    StepperMotor_MoveWithSpeed(SPEED_1);
    
    while (1) {
        // 主循環(huán)中可以添加其他邏輯代碼
    }
}

5.3 LD3320識(shí)別代碼

以下是使用STM32F103的串口2接收LD3320語(yǔ)音識(shí)別結(jié)果并進(jìn)行判斷控制的代碼:

#include "stm32f10x.h"
#include <stdio.h>

// 定義LD3320串口通信引腳
#define LD3320_RX_PIN GPIO_Pin_2
#define LD3320_RX_PORT GPIOA
#define LD3320_USART USART2

// 定義接收緩沖區(qū)大小
#define BUFFER_SIZE 128

// 接收緩沖區(qū)
volatile char rxBuffer[BUFFER_SIZE];
volatile uint8_t rxIndex = 0;
volatile uint8_t rxComplete = 0;

// 初始化LD3320串口通信引腳
void LD3320_UART_Init() {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = LD3320_RX_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(LD3320_RX_PORT, &GPIO_InitStructure);
    
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx;
    USART_Init(LD3320_USART, &USART_InitStructure);
    
    USART_ITConfig(LD3320_USART, USART_IT_RXNE, ENABLE);
    
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    USART_Cmd(LD3320_USART, ENABLE);
}

// 串口2中斷處理函數(shù)
void USART2_IRQHandler() {
    if (USART_GetITStatus(LD3320_USART, USART_IT_RXNE) != RESET) {
        char data = USART_ReceiveData(LD3320_USART);
        if (rxIndex < BUFFER_SIZE - 1) {
            rxBuffer[rxIndex++] = data;
        }
        if (data == 'n') {
            rxComplete = 1;
        }
    }
}

// 處理接收到的LD3320識(shí)別結(jié)果
void ProcessLD3320Result() {
    // 在這里進(jìn)行LD3320識(shí)別結(jié)果的判斷和控制邏輯
    // 可以根據(jù)接收到的字符串進(jìn)行判斷,例如使用strcmp()函數(shù)進(jìn)行比較
    // 示例:if (strcmp(rxBuffer, "ON") == 0) { // 執(zhí)行打開(kāi)操作 }
    
    // 清空接收緩沖區(qū)
    rxIndex = 0;
    rxComplete = 0;
}

int main(void) {
    // 初始化LD3320串口通信引腳
    LD3320_UART_Init();
    
    while (1) {
        if (rxComplete) {
            ProcessLD3320Result();
        }
    }
}

以上代碼使用STM32F103的串口2接收LD3320語(yǔ)音識(shí)別結(jié)果并進(jìn)行判斷控制。

代碼中使用了串口2的接收中斷來(lái)接收LD3320的識(shí)別結(jié)果。在中斷處理函數(shù)USART2_IRQHandler()中,將接收到的數(shù)據(jù)存儲(chǔ)到接收緩沖區(qū)rxBuffer中,并通過(guò)檢測(cè)換行符n來(lái)判斷一條完整的識(shí)別結(jié)果是否接收完成。當(dāng)識(shí)別結(jié)果接收完成時(shí),調(diào)用ProcessLD3320Result()函數(shù)進(jìn)行識(shí)別結(jié)果的判斷和控制邏輯處理。

ProcessLD3320Result()函數(shù)中,可以根據(jù)接收到的字符串進(jìn)行判斷和控制邏輯的實(shí)現(xiàn)。例如,使用字符串比較函數(shù)strcmp()來(lái)比較接收到的字符串與預(yù)設(shè)的控制命令是否匹配,從而執(zhí)行相應(yīng)的操作。在這個(gè)函數(shù)中,可以添加你需要的控制邏輯,例如打開(kāi)或關(guān)閉某個(gè)設(shè)備,執(zhí)行特定的動(dòng)作等。

  • 更多詳細(xì)資料請(qǐng)聯(lián)系.docx
    下載
意法半導(dǎo)體

意法半導(dǎo)體

意法半導(dǎo)體(ST)集團(tuán)于1987年6月成立,是由意大利的SGS微電子公司和法國(guó)Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長(zhǎng)市場(chǎng)之間分布均衡(五大市場(chǎng)占2007年銷售收入的百分比):通信(35%),消費(fèi)(17%),計(jì)算機(jī)(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計(jì)數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場(chǎng)居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機(jī)頂盒芯片供應(yīng)商,而且在分立器件、手機(jī)相機(jī)模塊和車用集成電路領(lǐng)域居世界前列.

意法半導(dǎo)體(ST)集團(tuán)于1987年6月成立,是由意大利的SGS微電子公司和法國(guó)Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長(zhǎng)市場(chǎng)之間分布均衡(五大市場(chǎng)占2007年銷售收入的百分比):通信(35%),消費(fèi)(17%),計(jì)算機(jī)(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計(jì)數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場(chǎng)居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機(jī)頂盒芯片供應(yīng)商,而且在分立器件、手機(jī)相機(jī)模塊和車用集成電路領(lǐng)域居世界前列.收起

查看更多

相關(guān)推薦