一、項(xiàng)目介紹
隨著科技的不斷發(fā)展和人們生活水平的提高,農(nóng)業(yè)生產(chǎn)也逐漸向智能化、高效化的方向發(fā)展。水稻作為我國(guó)主要的糧食作物之一,其生長(zhǎng)過(guò)程中的灌溉管理尤為重要。傳統(tǒng)的灌溉方式往往依賴于人工觀察和控制,不僅效率低下,而且容易出現(xiàn)誤差,無(wú)法滿足現(xiàn)代農(nóng)業(yè)生產(chǎn)的需求。
當(dāng)前設(shè)計(jì)了一款基于STM32的水稻田智能灌溉系統(tǒng)。該系統(tǒng)能夠通過(guò)水位傳感器和溫度傳感器實(shí)時(shí)監(jiān)測(cè)稻田的水位和水溫,并根據(jù)設(shè)定的閾值自動(dòng)控制水泵的開(kāi)關(guān),實(shí)現(xiàn)自動(dòng)灌溉。同時(shí),通過(guò)NBIOT模塊將實(shí)時(shí)數(shù)據(jù)上傳到華為云物聯(lián)網(wǎng)云平臺(tái),用戶可以通過(guò)手機(jī)APP遠(yuǎn)程監(jiān)控和控制設(shè)備的運(yùn)行,實(shí)現(xiàn)遠(yuǎn)程管理。相當(dāng)于直接將水稻田搬到了云端,后期還會(huì)加入攝像頭監(jiān)控,加入圖像處理,在家就可以了解到每一塊稻田的生長(zhǎng)情況。
整個(gè)系統(tǒng)的電源采用太陽(yáng)能板供電。
整個(gè)系統(tǒng)的應(yīng)用可以大大提高水稻灌溉的效率和準(zhǔn)確性,減少人力資源的浪費(fèi),降低生產(chǎn)成本,并為農(nóng)業(yè)生產(chǎn)提供更有力的技術(shù)保障。此外,系統(tǒng)還可以推廣到其他領(lǐng)域的智能灌溉和控制中,具有廣闊的市場(chǎng)應(yīng)用前景。
二、設(shè)計(jì)需求
該系統(tǒng)通過(guò)水位傳感器檢測(cè)稻田的水位,根據(jù)預(yù)先設(shè)置的水位閾值,自動(dòng)控制繼電器開(kāi)啟水泵進(jìn)行抽水灌溉,從而實(shí)現(xiàn)自動(dòng)補(bǔ)充灌溉水。同時(shí),溫度傳感器可以監(jiān)測(cè)水溫的變化,確保水溫適宜。利用NBIOT模塊實(shí)現(xiàn)與華為云物聯(lián)網(wǎng)云平臺(tái)的連接,將實(shí)時(shí)的水位和水溫?cái)?shù)據(jù)上傳到云平臺(tái)。
為了方便用戶遠(yuǎn)程操作和監(jiān)控,開(kāi)發(fā)了手機(jī)APP。用戶可以通過(guò)APP遠(yuǎn)程手動(dòng)控制水泵的開(kāi)關(guān),實(shí)現(xiàn)遠(yuǎn)程操作。同時(shí),手機(jī)APP可以實(shí)時(shí)顯示設(shè)備上傳的水溫和水位數(shù)據(jù),提供可視化的界面,方便用戶監(jiān)控農(nóng)田狀況。
主控芯片采用STM32F103C8T6,具有豐富的外設(shè)資源和良好的性能,能夠滿足系統(tǒng)的需求。水溫檢測(cè)方面采用DS18B20防水溫度傳感器,具有高精度和穩(wěn)定性,可以準(zhǔn)確地監(jiān)測(cè)水溫。NBIOT聯(lián)網(wǎng)模塊采用BC26,支持NB-IoT通信技術(shù),能夠?qū)崿F(xiàn)與云平臺(tái)的連接。云服務(wù)器采用華為云物聯(lián)網(wǎng)服務(wù)器,提供穩(wěn)定可靠的云端服務(wù)。手機(jī)APP采用Qt進(jìn)行開(kāi)發(fā),可以在不同的平臺(tái)上運(yùn)行,并提供友好的用戶界面和交互體驗(yàn)。
系統(tǒng)的功能主要包括以下幾個(gè)方面:
(1)水位檢測(cè):系統(tǒng)需要通過(guò)水位傳感器實(shí)時(shí)監(jiān)測(cè)稻田的水位,并能夠根據(jù)設(shè)定的閾值自動(dòng)控制水泵的開(kāi)關(guān),實(shí)現(xiàn)自動(dòng)灌溉。
(2)水溫檢測(cè):系統(tǒng)需要通過(guò)溫度傳感器實(shí)時(shí)監(jiān)測(cè)稻田的水溫,并將數(shù)據(jù)傳輸到云平臺(tái)進(jìn)行遠(yuǎn)程監(jiān)控。
(3)數(shù)據(jù)傳輸:系統(tǒng)需要通過(guò)NBIOT模塊將實(shí)時(shí)水溫和水位數(shù)據(jù)上傳到華為云物聯(lián)網(wǎng)云平臺(tái),實(shí)現(xiàn)遠(yuǎn)程監(jiān)控和控制。
(4)遠(yuǎn)程控制:用戶可以通過(guò)手機(jī)APP遠(yuǎn)程監(jiān)控和控制設(shè)備的運(yùn)行,包括水泵的開(kāi)關(guān)和閾值的設(shè)置等。
(5)人機(jī)界面:手機(jī)APP需要提供友好的人機(jī)界面,能夠?qū)崟r(shí)顯示設(shè)備上傳的水溫和水位數(shù)據(jù),并提供相應(yīng)的操作按鈕。
在硬件選型方面,主要考慮了以下幾個(gè)方面:
(1)主控芯片:選擇了STM32F103C8T6作為主控芯片。STM32F103C8T6是一款基于ARM Cortex-M3內(nèi)核的32位微控制器,具有高性能、低功耗、易于開(kāi)發(fā)等優(yōu)點(diǎn)。該芯片具有豐富的外設(shè)接口,能夠滿足本系統(tǒng)的需求。
(2)水位傳感器:選擇了防水型的水位傳感器,以確保在潮濕環(huán)境下能夠正常工作。該傳感器具有高精度、高可靠性、低功耗等優(yōu)點(diǎn),能夠滿足本系統(tǒng)的需求。
(3)溫度傳感器:選擇了DS18B20防水溫度傳感器,該傳感器具有高精度、高可靠性、低功耗等優(yōu)點(diǎn),能夠?qū)崟r(shí)檢測(cè)稻田的水溫,并將數(shù)據(jù)傳輸?shù)街骺匦酒?/p>
(4)NBIOT模塊:選擇了BC26模塊作為NBIOT通信模塊。該模塊具有低功耗、高穩(wěn)定性、易于開(kāi)發(fā)等優(yōu)點(diǎn),能夠?qū)?shí)時(shí)數(shù)據(jù)上傳到華為云物聯(lián)網(wǎng)云平臺(tái)。
(5)水泵:選擇具有自動(dòng)控制功能的水泵,能夠根據(jù)主控芯片的控制信號(hào)自動(dòng)開(kāi)關(guān)。
三、華為云產(chǎn)品設(shè)備創(chuàng)建
這一章節(jié)主要是介紹華為云物聯(lián)網(wǎng)云端產(chǎn)品與設(shè)備的創(chuàng)建流程。
3.1 開(kāi)通物聯(lián)網(wǎng)服務(wù)
地址: https://www.huaweicloud.com/product/iothub.html
點(diǎn)擊總覽
,查看接入信息。 我們當(dāng)前設(shè)備準(zhǔn)備采用MQTT協(xié)議接入華為云平臺(tái),這里可以看到MQTT協(xié)議的地址和端口號(hào)等信息。
總結(jié):
端口號(hào): MQTT (1883)
接入地址: e244e6efb9.st1.iotda-device.cn-north-4.myhuaweicloud.com
根據(jù)域名地址得到IP地址信息:
Microsoft Windows [版本 10.0.19045.3448]
(c) Microsoft Corporation。保留所有權(quán)利。
C:Users11266>ping e244e6efb9.st1.iotda-device.cn-north-4.myhuaweicloud.com
正在 Ping e244e6efb9.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í)間=41ms TTL=94
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=44ms TTL=94
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=43ms TTL=94
來(lái)自 117.78.5.125 的回復(fù): 字節(jié)=32 時(shí)間=42ms TTL=94
117.78.5.125 的 Ping 統(tǒng)計(jì)信息:
數(shù)據(jù)包: 已發(fā)送 = 4,已接收 = 4,丟失 = 0 (0% 丟失),
往返行程的估計(jì)時(shí)間(以毫秒為單位):
最短 = 41ms,最長(zhǎng) = 44ms,平均 = 42ms
C:Users11266>
MQTT協(xié)議接入端口號(hào)有兩個(gè),1883是非加密端口,8883是證書加密端口,單片機(jī)無(wú)法加載證書,所以使用1883端口比較合適。 接下來(lái)的ESP8266就采用1883端口連接華為云物聯(lián)網(wǎng)平臺(tái)。
3.2 創(chuàng)建產(chǎn)品
(1)創(chuàng)建產(chǎn)品
點(diǎn)擊產(chǎn)品頁(yè),再點(diǎn)擊創(chuàng)建產(chǎn)品。
(2)填寫產(chǎn)品信息
根據(jù)自己產(chǎn)品名字填寫。
(3)品創(chuàng)建成功
(4)添加自定義模型
產(chǎn)品創(chuàng)建完成之后,點(diǎn)擊進(jìn)入產(chǎn)品詳情頁(yè)面,翻到最下面可以看到模型定義。
這個(gè)模型就是定義自己設(shè)備接下來(lái)需要向服務(wù)器上傳那些數(shù)據(jù)類型。根據(jù)自己的數(shù)據(jù)類型進(jìn)行編寫。
3.3 添加設(shè)備
產(chǎn)品是屬于上層的抽象模型,接下來(lái)在產(chǎn)品模型下添加實(shí)際的設(shè)備。添加的設(shè)備最終需要與真實(shí)的設(shè)備關(guān)聯(lián)在一起,完成數(shù)據(jù)交互。
(1)注冊(cè)設(shè)備
(2)根據(jù)自己的設(shè)備填寫
設(shè)備標(biāo)識(shí)碼、密碼這些根據(jù)自己情況認(rèn)真填寫。
(3)保存設(shè)備信息
創(chuàng)建完畢之后,點(diǎn)擊保存并關(guān)閉,得到創(chuàng)建的設(shè)備密匙信息。該信息在后續(xù)生成MQTT三元組的時(shí)候需要使用。
創(chuàng)建之后,得到的設(shè)備信息如下:
{
"device_id": "65113d05a559fd7cd41435f8_lock1",
"secret": "12345678"
}
(4)設(shè)備創(chuàng)建完成
可以點(diǎn)擊設(shè)備進(jìn)入到設(shè)備詳情頁(yè)面。
3.4 MQTT協(xié)議主題訂閱與發(fā)布
(1)主題訂閱格式
幫助文檔地址:https://support.huaweicloud.com/devg-iothub/iot_02_2200.html
對(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/65113d05a559fd7cd41435f8_lock1/sys/messages/down
?
(2)主題發(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/api-iothub/iot_06_v5_3010.html
根據(jù)幫助文檔的介紹, 當(dāng)前設(shè)備發(fā)布主題,上報(bào)屬性的格式總結(jié)如下:
發(fā)布的主題格式:
$oc/devices/{device_id}/sys/properties/report
最終的格式:
$oc/devices/65113d05a559fd7cd41435f8_lock1/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": "lock","properties":{"lock":1}}]}
3.5 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
MQTT協(xié)議的端口支持1883和8883,它們的區(qū)別是:8883 是加密端口更加安全。但是單片機(jī)上使用比較困難,所以當(dāng)前的設(shè)備是采用1883端口進(jìn)連接的。
根據(jù)上面的域名和端口號(hào),得到下面的IP地址和端口號(hào)信息: 如果設(shè)備支持填寫域名可以直接填域名,不支持就直接填寫IP地址。 (IP地址就是域名解析得到的)
華為云的MQTT服務(wù)器地址:117.78.5.125
域名:e244e6efb9.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è)面:
填入設(shè)備的信息: (上面兩行就是設(shè)備創(chuàng)建完成之后保存得到的)
得到三元組之后,設(shè)備端通過(guò)MQTT協(xié)議登錄鑒權(quán)的時(shí)候,填入?yún)?shù)即可。
ClientId 65113d05a559fd7cd41435f8_lock1_0_0_2023092508
Username 65113d05a559fd7cd41435f8_lock1
Password 1a3e7f486aa551bca7b6ff5c19c29d2006e940ec1f98ab416e10be1288106953
3.6 模擬設(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ā)布主題。
(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ù)了。
四、硬件選型
下面是為了驗(yàn)證設(shè)計(jì)而選型的相關(guān)的硬件模型,能夠?qū)崿F(xiàn)最終的設(shè)計(jì)效果。 模型設(shè)計(jì)最終驗(yàn)證成功之后,重新畫板選型硬件一體化設(shè)計(jì)產(chǎn)品就方便多了。
【1】STM32開(kāi)發(fā)板
【2】水泵電機(jī)
【3】BC26-NBIOT
【4】水溫檢測(cè)
【5】水位檢測(cè)
鏈接:https://item.taobao.com/item.htm?spm=a21n57.1.0.0.636b523cIyIKxC&id=735112974467&ns=1&abbucket=19#detail
【6】太陽(yáng)能板
五、代碼設(shè)計(jì)
5.1 主函數(shù)代碼框架
#include "stm32f10x.h"
#include "ds18b20.h"
#include "nbiot.h"
// 定義水位傳感器引腳和繼電器引腳
#define WATER_LEVEL_PIN GPIO_Pin_0
#define WATER_LEVEL_PORT GPIOA
#define RELAY_PIN GPIO_Pin_1
#define RELAY_PORT GPIOA
// 定義溫度傳感器引腳
#define TEMP_SENSOR_PIN GPIO_Pin_2
#define TEMP_SENSOR_PORT GPIOA
// 定義NBIOT模塊和云服務(wù)器相關(guān)參數(shù)
#define NBIOT_RX_PIN GPIO_Pin_3
#define NBIOT_RX_PORT GPIOA
#define NBIOT_TX_PIN GPIO_Pin_4
#define NBIOT_TX_PORT GPIOA
#define SERVER_ADDRESS "your_server_address"
#define DEVICE_ID "your_device_id"
#define DEVICE_KEY "your_device_key"
// 定義APP開(kāi)關(guān)水泵控制命令
#define CMD_PUMP_ON '1'
#define CMD_PUMP_OFF '0'
// 初始化函數(shù)
void init();
// 獲取水位值
uint8_t getWaterLevel();
// 控制水泵
void controlPump(uint8_t state);
// 獲取溫度值
float getTemperature();
// 更新數(shù)據(jù)到華為云服務(wù)器
void updateDataToCloud(float temperature, uint8_t waterLevel);
// 處理NBIOT模塊接收到的命令
void handleNBIOTCommand(char cmd);
int main(void) {
// 初始化
init();
while (1) {
// 獲取水位值
uint8_t waterLevel = getWaterLevel();
// 控制水泵
controlPump(waterLevel);
// 獲取溫度值
float temperature = getTemperature();
// 更新數(shù)據(jù)到華為云服務(wù)器
updateDataToCloud(temperature, waterLevel);
// 處理NBIOT模塊接收到的命令
char command = receiveNBIOTCommand();
handleNBIOTCommand(command);
}
}
void init() {
// 初始化GPIO和相關(guān)外設(shè)
// ...
// 初始化DS18B20溫度傳感器
DS18B20_Init(TEMP_SENSOR_PIN);
// 初始化NBIOT模塊
NBIOT_Init(NBIOT_RX_PIN, NBIOT_TX_PIN, SERVER_ADDRESS, DEVICE_ID, DEVICE_KEY);
}
uint8_t getWaterLevel() {
// 讀取水位傳感器的值
// ...
}
void controlPump(uint8_t state) {
if (state == 0) {
// 關(guān)閉繼電器,停止水泵
GPIO_ResetBits(RELAY_PORT, RELAY_PIN);
} else {
// 打開(kāi)繼電器,啟動(dòng)水泵
GPIO_SetBits(RELAY_PORT, RELAY_PIN);
}
}
float getTemperature() {
// 讀取溫度傳感器的值
// ...
}
void updateDataToCloud(float temperature, uint8_t waterLevel) {
// 將溫度和水位值上傳到華為云服務(wù)器
// ...
}
void handleNBIOTCommand(char cmd) {
if (cmd == CMD_PUMP_ON) {
// 手機(jī)APP發(fā)送打開(kāi)水泵的命令
controlPump(1);
} else if (cmd == CMD_PUMP_OFF) {
// 手機(jī)APP發(fā)送關(guān)閉水泵的命令
controlPump(0);
}
}
5.2 BC26模塊代碼
#include <stm32f10x.h>
#include <usart.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <delay.h>
// 定義BC26串口
#define BC26_USART USART1
// 定義MQTT服務(wù)器信息
#define MQTT_SERVER_IP "192.168.1.100"
#define MQTT_SERVER_PORT "1883"
#define MQTT_USERNAME "username"
#define MQTT_PASSWORD "password"
#define MQTT_CLIENT_ID "client_id"
// 串口發(fā)送字符串
void sendString(const char *str) {
while (*str) {
USART_SendData(BC26_USART, *str++);
while (USART_GetFlagStatus(BC26_USART, USART_FLAG_TC) == RESET);
}
}
// 延時(shí)等待響應(yīng)
bool waitForResponse(const char *response, uint32_t timeout) {
uint32_t startTime = millis();
uint32_t elapsedTime = 0;
uint8_t rxData = 0;
uint8_t responseIndex = 0;
while (elapsedTime < timeout) {
if (USART_GetFlagStatus(BC26_USART, USART_FLAG_RXNE) != RESET) {
rxData = USART_ReceiveData(BC26_USART);
if (rxData == response[responseIndex]) {
responseIndex++;
if (response[responseIndex] == '?') {
return true; // 收到完整響應(yīng)
}
} else {
responseIndex = 0; // 重置響應(yīng)索引
}
}
elapsedTime = millis() - startTime;
}
return false; // 超時(shí)未收到完整響應(yīng)
}
// 初始化BC26模塊
bool initBC26Module() {
sendString("AT+CFUN=1rn"); // 設(shè)置BC26模塊為全功能模式
if (!waitForResponse("OK", 1000)) {
return false;
}
sendString("AT+CIMIrn"); // 獲取SIM卡的IMSI號(hào)碼
if (!waitForResponse("OK", 1000)) {
return false;
}
sendString("AT+QCFG="nwscanmode",0,1rn"); // 設(shè)置網(wǎng)絡(luò)掃描模式為自動(dòng)模式
if (!waitForResponse("OK", 1000)) {
return false;
}
sendString("AT+QCFG="iotopmode",2,1rn"); // 設(shè)置連接模式為Cat M1/NB1優(yōu)先模式
if (!waitForResponse("OK", 1000)) {
return false;
}
sendString("AT+QICSGP=1,1,"your_apn","","",1rn"); // 配置APN參數(shù),根據(jù)具體網(wǎng)絡(luò)運(yùn)營(yíng)商設(shè)置
if (!waitForResponse("OK", 1000)) {
return false;
}
sendString("AT+QIACT=1rn"); // 激活PDP上下文
if (!waitForResponse("OK", 10000)) {
return false;
}
sendString("AT+QMTOPEN=0,"");
sendString(MQTT_SERVER_IP); // 連接MQTT服務(wù)器
sendString("",");
sendString(MQTT_SERVER_PORT);
sendString("rn");
if (!waitForResponse("+QMTOPEN: 0,0", 20000)) {
return false;
}
sendString("AT+QMTCONN=0,"");
sendString(MQTT_CLIENT_ID); // 使用指定的Client ID連接MQTT服務(wù)器
sendString("","");
sendString(MQTT_USERNAME);
sendString("","");
sendString(MQTT_PASSWORD);
sendString(""rn");
if (!waitForResponse("+QMTCONN: 0,0,0", 10000)) {
return false;
}
return true; // 初始化成功
}
int main(void) {
// 初始化系統(tǒng)時(shí)鐘等
USART_InitTypeDef USART_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_Mode_Tx;
USART_Init(BC26_USART, &USART_InitStructure);
USART_Cmd(BC26_USART, ENABLE);
initBC26Module();
while (1) {
// 執(zhí)行其他操作或處理MQTT消息
}
}
5.3 電機(jī)控制代碼
#include <stm32f10x.h>
#include <stdbool.h>
// 定義電機(jī)引腳
#define MOTOR_PORT GPIOA
#define MOTOR_PIN GPIO_Pin_0
// 初始化電機(jī)引腳
void initMotor() {
// 使能GPIO時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 初始化GPIO引腳
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = MOTOR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽輸出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MOTOR_PORT, &GPIO_InitStructure);
}
// 控制電機(jī)狀態(tài)
void setMotorState(bool enabled) {
if (enabled) {
GPIO_SetBits(MOTOR_PORT, MOTOR_PIN); // 電機(jī)打開(kāi)
} else {
GPIO_ResetBits(MOTOR_PORT, MOTOR_PIN); // 電機(jī)關(guān)閉
}
}
int main(void) {
// 初始化系統(tǒng)時(shí)鐘等
initMotor();
while (1) {
// 控制電機(jī)狀態(tài)
setMotorState(true); // 打開(kāi)電機(jī)
// 延時(shí)一段時(shí)間
setMotorState(false); // 關(guān)閉電機(jī)
// 延時(shí)一段時(shí)間
}
}
5.4 水位檢測(cè)代碼
#include <stm32f10x.h>
#include <stdio.h>
#include <delay.h>
// 定義ADC引腳和通道
#define ADC_PORT GPIOA
#define ADC_PIN GPIO_Pin_0
#define ADC_CHANNEL ADC_Channel_0
// ADC初始化
void initADC() {
// 使能ADC時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// 初始化GPIO引腳
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(ADC_PORT, &GPIO_InitStructure);
// 初始化ADC參數(shù)
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 獨(dú)立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 單通道掃描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 連續(xù)轉(zhuǎn)換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 不用外部觸發(fā)
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 數(shù)據(jù)右對(duì)齊
ADC_InitStructure.ADC_NbrOfChannel = 1; // 采樣通道數(shù)量
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC采樣通道
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);
// 使能ADC
ADC_Cmd(ADC1, ENABLE);
// ADC校準(zhǔn)
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
}
// 讀取ADC轉(zhuǎn)換值
uint16_t readADC() {
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
int main(void) {
// 初始化系統(tǒng)時(shí)鐘等
initADC();
while (1) {
uint16_t adcValue = readADC();
printf("ADC Value: %drn", adcValue);
// 進(jìn)行水位傳感器的處理和其他操作
delay_ms(1000); // 延時(shí)1秒
}
}
5.5 水溫檢測(cè)代碼
#include <stm32f10x.h>
#include <delay.h>
// 定義溫度傳感器引腳
#define TEMPERATURE_PIN GPIO_Pin_1
#define TEMPERATURE_GPIO GPIOA
// 初始化溫度傳感器
void initTemperatureSensor() {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = TEMPERATURE_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 使用開(kāi)漏輸出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(TEMPERATURE_GPIO, &GPIO_InitStructure);
}
// 發(fā)送復(fù)位信號(hào)
void resetSensor() {
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(500);
GPIO_ResetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(500);
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(500);
}
// 讀取一位數(shù)據(jù)
uint8_t readBit() {
uint8_t data = 0;
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(2);
GPIO_ResetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(2);
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(1);
if (GPIO_ReadInputDataBit(TEMPERATURE_GPIO, TEMPERATURE_PIN)) {
data = 1;
}
delay_us(60);
return data;
}
// 讀取一個(gè)字節(jié)數(shù)據(jù)
uint8_t readByte() {
uint8_t byte = 0;
for (int i = 0; i < 8; i++) {
byte |= readBit() << i;
}
return byte;
}
// 寫入一位數(shù)據(jù)
void writeBit(uint8_t bit) {
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(2);
GPIO_ResetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
delay_us(2);
if (bit) {
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
}
delay_us(60);
GPIO_SetBits(TEMPERATURE_GPIO, TEMPERATURE_PIN);
}
// 寫入一個(gè)字節(jié)數(shù)據(jù)
void writeByte(uint8_t byte) {
for (int i = 0; i < 8; i++) {
writeBit(byte & 0x01);
byte >>= 1;
}
}
// 獲取溫度值
float getTemperature() {
uint8_t temperature[2];
resetSensor();
writeByte(0xCC); // 跳過(guò)ROM命令
writeByte(0x44); // 啟動(dòng)溫度轉(zhuǎn)換命令
delay_ms(800); // 等待轉(zhuǎn)換完成
resetSensor();
writeByte(0xCC); // 跳過(guò)ROM命令
writeByte(0xBE); // 讀取溫度值命令
temperature[0] = readByte();
temperature[1] = readByte();
int16_t rawTemperature = (temperature[1] << 8) | temperature[0];
float temp = rawTemperature * 0.0625;
return temp;
}
int main(void) {
// 初始化系統(tǒng)時(shí)鐘等
initTemperatureSensor();
while (1) {
float temperature = getTemperature();
// 處理溫度數(shù)據(jù)
}
}
六、上位機(jī)開(kāi)發(fā)
這篇主要介紹硬件端的設(shè)計(jì)、華為云物聯(lián)網(wǎng)服務(wù)器端的設(shè)計(jì)。下一篇詳細(xì)介紹WEB網(wǎng)頁(yè)端、手機(jī)APP和微信小程序的開(kāi)發(fā)。