亚洲精品久久久久久久久久久,亚洲国产精品一区二区制服,亚洲精品午夜精品,国产成人精品综合在线观看,最近2019中文字幕一页二页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

智能農(nóng)業(yè)監(jiān)控系統(tǒng):MQTT阿里云平臺監(jiān)測+內(nèi)置Web網(wǎng)頁控制+代碼解析

王亞龍 ? 來源:jf_04762332 ? 作者:jf_04762332 ? 2025-08-08 11:07 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

軟硬件開源項目-智能農(nóng)業(yè)監(jiān)控系統(tǒng):MQTT阿里云平臺監(jiān)測+內(nèi)置Web網(wǎng)頁控制+代碼解析

智能農(nóng)業(yè)監(jiān)控系統(tǒng):開源項目推薦

【下載地址】智能農(nóng)業(yè)監(jiān)控系統(tǒng)源碼
本倉庫提供了一套完整的智能農(nóng)業(yè)監(jiān)控系統(tǒng)源碼,基于 W55MH32 以太網(wǎng)單片機實現(xiàn)三大核心功能:通過 ADC 采集土壤濕度與光照數(shù)據(jù),基于閾值自動控制水泵灌溉;經(jīng) MQTT 協(xié)議對接阿里云,實現(xiàn)數(shù)據(jù)遠程查看與設(shè)備控制;提供本地 Web 接口,支持實時監(jiān)測與閾值調(diào)整。
項目倉庫地址:https://gitee.com/shenzhen-weishi_3_0/W55MH32

完整顯示視頻bilibili|點擊跳轉(zhuǎn)

1 項目構(gòu)思與核心目標

老家親戚種大棚,灌溉總讓人頭疼:每天來回查濕度,憑經(jīng)驗澆水,忙時作物缺水蔫苗,雨天積水爛根,既費人力又浪費水,環(huán)境調(diào)節(jié)總跟不上作物需求。我便琢磨著做套簡易系統(tǒng)解決這些問題。?

之前用過 WIZnet 的 W5500 芯片做以太網(wǎng)項目,對他們的芯片挺熟悉。聽說新出了帶 MCU 的 W55MH32 以太網(wǎng)芯片,就申請了開發(fā)板試試。拿到板子后,先連接傳感器在自家盆栽做測試,確認硬件兼容和數(shù)據(jù)穩(wěn)定后,正式搭建智能農(nóng)業(yè)監(jiān)管系統(tǒng)。這板子自帶硬件 TCP/IP 引擎,外設(shè)接口豐富,剛好滿足傳感器連接和數(shù)據(jù)傳輸需求,官方還有阿里云連接例程,省了不少事。有之前的經(jīng)驗打底,用它連阿里云、搭局域網(wǎng)監(jiān)控網(wǎng)頁,心里挺有底。?我計劃搭傳感器與水泵聯(lián)動模型:傳感器采集土壤濕度、光照等數(shù)據(jù),傳云端后自動控制水泵啟停。說干就干,畫接線圖、連傳感器和繼電器,優(yōu)化 MQTT 邏輯接阿里云,還做了簡易網(wǎng)頁方便遠程查看操作。調(diào)試后,數(shù)據(jù)采集和水泵自動啟停功能都穩(wěn)定實現(xiàn)了。?這個模型還在完善中,后續(xù)會優(yōu)化硬件集成和代碼邏輯,讓運行更穩(wěn)定耐用?,F(xiàn)在整理開發(fā)細節(jié)記錄下來,之后會開源代碼和 PCB 文件,希望給想在田間用物聯(lián)網(wǎng)技術(shù)的朋友做個參考,提供思路,讓技術(shù)真正為農(nóng)活添力。?

核心目標:

硬件層面:實現(xiàn)傳感器數(shù)據(jù)采集與執(zhí)行器(水泵)控制的穩(wěn)定聯(lián)動,確保環(huán)境數(shù)據(jù)實時性與設(shè)備響應(yīng)可靠性。

軟件層面:完成 MQTT 協(xié)議對接阿里云,實現(xiàn)設(shè)備與云端的雙向數(shù)據(jù)傳輸,同時支持本地網(wǎng)頁控制和環(huán)境數(shù)據(jù)查看。

應(yīng)用層面:默認土壤濕度低于 30% 自動啟動灌溉,高于 50% 自動停止,支持遠程動態(tài)調(diào)整閾值,兼顧自動化與靈活性。

后續(xù)計劃進一步將W55MH32以太網(wǎng)單片機芯片與光照傳感器、土壤濕度傳感器深度集成,同時匹配適配田間環(huán)境的防護外殼——既通過硬件整合提升系統(tǒng)穩(wěn)定性,又借助外殼抵御大棚內(nèi)的溫濕度波動、粉塵等干擾,讓設(shè)備在實際農(nóng)業(yè)場景中更耐用、易部署。此外,還會公開完整的硬件原理圖和PCB設(shè)計文件,方便有需要的朋友參考復(fù)用,降低技術(shù)落地的門檻,讓這套方案能更便捷地應(yīng)用到田間地頭。

1.1 方案圖示

wKgZPGiVaIOAGFKmAACJ-5yiZaI734.png

2 硬件選型與搭建

2.1 核心組件清單

主控:W55MH32L-EVB(216MHz主頻、自帶硬件TCP/IP引擎)。

傳感器:土壤濕度傳感器(模擬輸出)、光照傳感器(模擬輸出)。

執(zhí)行器:5V繼電器模塊、小型水泵。

輔助設(shè)備:外部 5V 電源、網(wǎng)線、路由器、杜邦線若干。

2.2 電路連接技巧

開發(fā)板引腳定義復(fù)雜,我采用"功能分組"法簡化連接:

模擬量輸入組:PA0接土壤濕度傳感器,PA3接光照傳感器(利用單片機ADC功能)。

數(shù)字輸出組:PB10 接繼電器IN引腳(控制信號)。

電源組:開發(fā)板5V輸出給繼電器供電,傳感器獨立接3.3V(避免干擾),繼電器COM端接外接電源正極。

水泵:正極接繼電器常開端,負極接外接電源負極。

特別注意繼電器的"低電平有效"特性——初始化時需將PB10置高,通過拉低電平觸發(fā)動作,這一點在后續(xù)軟件設(shè)計中需重點匹配。

3 開發(fā)環(huán)境搭建

3.1 軟件工具鏈

編譯環(huán)境:Keil uVision5,版本大于V5.3(需安裝W55MH32 系列芯片包)。

調(diào)試工具:WIZ UartTool串口助手,其他串口助手也可。

瀏覽器:用于打開網(wǎng)頁查看。

云平臺:阿里云物聯(lián)網(wǎng)平臺(需完成實名認證)。

源碼:gitee倉庫項目倉庫地址|點擊跳轉(zhuǎn)

4 連接阿里云物聯(lián)網(wǎng)平臺

4.1 MQTT連接阿里云收發(fā)數(shù)據(jù)流程

4.1.1 準備階段

注冊與實名認證:用戶需要在阿里云平臺注冊賬號,并完成實名認證。

創(chuàng)建產(chǎn)品和添加物模型:登錄阿里云物聯(lián)網(wǎng)平臺,創(chuàng)建產(chǎn)品并在產(chǎn)品下添加以下物模型功能。

wKgZO2iVaIWATUqbAAXq13gW2BI244.png

創(chuàng)建設(shè)備:在剛剛創(chuàng)建的產(chǎn)品下創(chuàng)建一個設(shè)備。

wKgZO2iVaIOAd6PxAAD0br08nQ0304.png

4.1.2 記錄參數(shù)

連接參數(shù):在剛剛創(chuàng)建的設(shè)備詳情頁中找到MQTT連接參數(shù)。

wKgZPGiVaISAMExlAAJql4u5KMM271.png

訂閱主題:/sys/k1zh33h3hte/${deviceName}/thing/service/property/set(屬性設(shè)置主題)

發(fā)布主題:/sys/k1zh33h3hte/${deviceName}/thing/event/property/post(上報消息主題)

注意:上面兩個主題中的${deviceName}需要替換成設(shè)備名。

wKgZO2iVaIOAGGqWAAFrxzSq4T4795.png

4.1.3 連接、訂閱和發(fā)布消息

接著我們可以使用上面記錄的連接參數(shù)進行連接,當連接成功后,訂閱上面的訂閱主題。并通過發(fā)布主題上報物模型數(shù)據(jù)。

在阿里云平臺,如果產(chǎn)品創(chuàng)建階段選擇的數(shù)據(jù)格式為Alink JSON格式時,接收和發(fā)送數(shù)據(jù)格式都會遵守下面這個格式:

{
   "method": "thing.event.property.post", 
   "id": "2241348", 
   "params": {
       "prop_float": 1.25, 
       "prop_int16": 4658, 
       "prop_bool": 1
   }, 
   "version": "1.0"
}

5 主要程序解析

5.1 main.c分析

1.系統(tǒng)初始化與硬件配置

完成基礎(chǔ)硬件初始化(時鐘、延時、串口、定時器等),配置ADC(模數(shù)轉(zhuǎn)換)用于傳感器數(shù)據(jù)采集,初始化繼電器控制模塊,并設(shè)置WIZnet以太網(wǎng)芯片的網(wǎng)絡(luò)參數(shù)(MAC、IP、網(wǎng)關(guān)等)。

2.網(wǎng)絡(luò)通信功能 實現(xiàn)雙重網(wǎng)絡(luò)通信能力:

MQTT協(xié)議:通過MQTT客戶端(do_mqtt()和mqtt_post_properties())實現(xiàn)傳感器數(shù)據(jù)的遠程發(fā)布。

獲取網(wǎng)頁:通過loopback_tcps()提供TCP服務(wù)器功能,進行HTTP請求和響應(yīng)處理。

3.傳感器數(shù)據(jù)處理與控制

周期性(5秒間隔)通過process_sensors_and_control()讀取傳感器數(shù)據(jù)(濕度、光照強度)。

基于濕度閾值(高低閾值)實現(xiàn)繼電器自動控制邏輯。

將實時數(shù)據(jù)(濕度、光照、繼電器狀態(tài))通過MQTT發(fā)布到阿里平臺同時刷新網(wǎng)頁環(huán)境數(shù)據(jù)。

#include "bsp_adc.h"
#include "bsp_rcc.h"
#include "bsp_tim.h"
#include "bsp_uart.h"
#include "delay.h"
#include "do_mqtt.h"
#include "do_sensor.h"
#include "loopback.h"
#include "sv.h"
#include "wiz_interface.h"
#include "wizchip_conf.h"
#include 
#include 
#include 

/* 全局實時傳感器數(shù)據(jù)(在do_mqtt.c中定義) */
extern float g_humidity_value;         // 當前濕度讀數(shù)
extern float g_light_intensity;        // 當前光照強度讀數(shù)
extern uint8_t g_solenoid_valve_state; // 電磁閥狀態(tài)(1:開啟, 0:關(guān)閉)

/* 濕度閾值(與阿里云IoT模型對齊,范圍0~100) */
int g_humidity_low_threshold = 30;  // 澆水的下限閾值
int g_humidity_high_threshold = 50; // 停止?jié)菜纳舷揲撝?
/* 函數(shù)原型 */
extern void mqtt_post_properties(void);

/* 套接字和緩沖區(qū)配置常量 */
#define SOCKET_TCP_ID 0
#define SOCKET_MQTT_ID 1
#define ETHERNET_BUF_MAX_SIZE (1024 * 2) // 以太網(wǎng)緩沖區(qū)最大大小
#define SENSOR_READ_INTERVAL 5000        // 傳感器采樣間隔(毫秒)

uint16_t g_tcp_listen_port = 8080;     // TCP服務(wù)器監(jiān)聽端口
wiz_NetInfo g_default_network_info = { // 默認網(wǎng)絡(luò)配置
    .mac = {0x00, 0x08, 0xdc, 0x12, 0x22, 0x12},
    .ip = {192, 168, 1, 30},
    .gw = {192, 168, 1, 1},
    .sn = {255, 255, 255, 0},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_DHCP};

uint8_t g_ethernet_data_buf[ETHERNET_BUF_MAX_SIZE] = {
    0}; // 以太網(wǎng)數(shù)據(jù)緩沖區(qū)
static uint8_t s_mqtt_send_buf[ETHERNET_BUF_MAX_SIZE] = {
    0}; // MQTT發(fā)送緩沖區(qū)(靜態(tài))
static uint8_t s_mqtt_recv_buf[ETHERNET_BUF_MAX_SIZE] = {
    0}; // MQTT接收緩沖區(qū)(靜態(tài))

/* 聲明systick_count,名稱與bsp_tim.o中的引用匹配 */
volatile uint32_t systick_count =
    0; // 系統(tǒng)滴答計數(shù)器(毫秒)- bsp_tim使用的名稱

/**
 * @brief 主程序循環(huán)
 * @details 處理MQTT通信、TCP回環(huán)和傳感器處理
 */
int main(void) {
  rcc_clk_config();          // RCC時鐘配置
  delay_init();              // 延時初始化
  console_usart_init(115200); // 控制臺串口初始化,波特率115200
  tim3_init();               // TIM3定時器初始化

  printf("%s 傳感器監(jiān)控系統(tǒng)rn", _WIZCHIP_ID_);

  adc_dma_init(); // ADC DMA初始化
  sv_init();      // 電磁閥初始化

  wiz_toe_init();                // WIZ芯片TOE初始化
  wiz_phy_link_check();          // WIZ物理層連接檢查
  network_init(g_ethernet_data_buf, &g_default_network_info); // 網(wǎng)絡(luò)初始化
  mqtt_init(SOCKET_MQTT_ID, s_mqtt_send_buf, s_mqtt_recv_buf); // MQTT初始化
  printf("系統(tǒng)初始化完成。rn");
  
  while (1) {
    do_mqtt(); // 處理MQTT通信

    // 處理TCP回環(huán)
    loopback_tcps(SOCKET_TCP_ID, g_ethernet_data_buf, g_tcp_listen_port);

    // 按間隔讀取傳感器并發(fā)布數(shù)據(jù)
    if (systick_count >= SENSOR_READ_INTERVAL) {
      systick_count = 0;
      process_sensors_and_control(); // 處理傳感器數(shù)據(jù)并控制設(shè)備
      mqtt_post_properties();        // 通過MQTT發(fā)布傳感器數(shù)據(jù)
    }
  }
}

5.2 ADC采集

1.關(guān)鍵配置:

初始化ADC為連續(xù)掃描模式,同時啟用DMA傳輸。

配置GPIO為模擬輸入模式,對應(yīng)傳感器連接的引腳。

設(shè)置DMA以循環(huán)方式將 ADC 數(shù)據(jù)傳輸?shù)骄彌_區(qū),無需CPU干預(yù)。

2.數(shù)據(jù)處理:

采樣數(shù)據(jù)交替存儲在s_adc_dma_buffer緩沖區(qū)中。

提供adc_get_average_value()函數(shù),可獲取指定通道的平均采樣值,減少噪聲影響。

#include "bsp_adc.h"
#include "w55mh32_adc.h"
#include "w55mh32_dma.h"
#include "w55mh32_gpio.h"
#include "w55mh32_rcc.h"


/* ADC DMA數(shù)據(jù)靜態(tài)緩沖區(qū)(存儲交替的通道讀數(shù)) */
static uint16_t s_adc_dma_buffer[ADC_BUFFER_SIZE];

/**
 * @brief 初始化帶DMA功能的ADC
 * @details 配置ADC通道(濕度和光照)、GPIO和DMA以實現(xiàn)連續(xù)采樣
 */
void adc_dma_init(void) {
  ADC_InitTypeDef adc_init_struct;  // ADC初始化結(jié)構(gòu)體
  GPIO_InitTypeDef gpio_init_struct; // GPIO初始化結(jié)構(gòu)體
  DMA_InitTypeDef dma_init_struct;  // DMA初始化結(jié)構(gòu)體

  // 使能ADC、GPIO和DMA的時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  // 配置GPIO引腳為模擬輸入(PA0: 濕度, PA3: 光照)
  gpio_init_struct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3;
  gpio_init_struct.GPIO_Mode = GPIO_Mode_AIN;  // 模擬輸入模式
  GPIO_Init(GPIOA, &gpio_init_struct);

  // 配置ADC為連續(xù)掃描模式
  ADC_StructInit(&adc_init_struct);  // 初始化ADC結(jié)構(gòu)體為默認值
  adc_init_struct.ADC_Mode = ADC_Mode_Independent;  // 獨立模式
  adc_init_struct.ADC_ScanConvMode = ENABLE;  // 使能掃描模式
  adc_init_struct.ADC_ContinuousConvMode = ENABLE;  // 使能連續(xù)轉(zhuǎn)換模式
  adc_init_struct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 無外部觸發(fā)
  adc_init_struct.ADC_DataAlign = ADC_DataAlign_Right;  // 數(shù)據(jù)右對齊
  adc_init_struct.ADC_NbrOfChannel = 2;  // 2個通道(濕度+光照)
  ADC_Init(ADC1, &adc_init_struct);

  // 配置ADC通道和采樣時間
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1,
                           ADC_SampleTime_55Cycles5);  // 濕度通道(PA0)
  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2,
                           ADC_SampleTime_55Cycles5);  // 光照通道(PA3)

  // 配置DMA用于ADC數(shù)據(jù)傳輸
  DMA_DeInit(DMA1_Channel1);  // 重置DMA通道1配置
  dma_init_struct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  // 外設(shè)基地址(ADC數(shù)據(jù)寄存器)
  dma_init_struct.DMA_MemoryBaseAddr = (uint32_t)s_adc_dma_buffer;  // 內(nèi)存基地址(DMA緩沖區(qū))
  dma_init_struct.DMA_DIR = DMA_DIR_PeripheralSRC;  // 傳輸方向:外設(shè)到內(nèi)存
  dma_init_struct.DMA_BufferSize = ADC_BUFFER_SIZE;  // 緩沖區(qū)大小
  dma_init_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // 禁止外設(shè)地址遞增
  dma_init_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 使能內(nèi)存地址遞增
  dma_init_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  // 外設(shè)數(shù)據(jù)大?。喊胱郑?6位)
  dma_init_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  // 內(nèi)存數(shù)據(jù)大小:半字(16位)
  dma_init_struct.DMA_Mode = DMA_Mode_Circular;  // 循環(huán)模式
  dma_init_struct.DMA_Priority = DMA_Priority_High;  // 高優(yōu)先級
  dma_init_struct.DMA_M2M = DMA_M2M_Disable;  // 禁止內(nèi)存到內(nèi)存?zhèn)鬏?  DMA_Init(DMA1_Channel1, &dma_init_struct);

  // 使能DMA和ADC
  DMA_Cmd(DMA1_Channel1, ENABLE);  // 使能DMA通道1
  ADC_DMACmd(ADC1, ENABLE);  // 使能ADC的DMA請求

  // 校準并啟動ADC
  ADC_Cmd(ADC1, ENABLE);  // 使能ADC1
  ADC_ResetCalibration(ADC1);  // 重置校準寄存器
  while (ADC_GetResetCalibrationStatus(ADC1))  // 等待重置校準完成
    ;
  ADC_StartCalibration(ADC1);  // 開始校準
  while (ADC_GetCalibrationStatus(ADC1))  // 等待校準完成
    ;

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 軟件觸發(fā)ADC轉(zhuǎn)換
}

/**
 * @brief 獲取特定通道的ADC平均值
 * @param channel_index ADC通道索引(0: 濕度, 1: 光照)
 * @param sample_count 用于平均的樣本數(shù)量
 * @return 平均ADC值(12位)
 */
uint16_t adc_get_average_value(uint8_t channel_index, uint8_t sample_count) {
  uint32_t sum = 0;  // 樣本總和
  uint8_t valid_samples = 0;  // 有效樣本數(shù)

  // 從DMA緩沖區(qū)讀取交替的樣本(通道0在偶數(shù)索引,通道1在奇數(shù)索引)
  for (uint8_t i = 0; i < sample_count && i < ADC_BUFFER_SIZE / 2; i++) {
    sum += s_adc_dma_buffer[i * 2 + channel_index];  // 累加對應(yīng)通道的樣本
    valid_samples++;  // 計數(shù)有效樣本
  }

  return (valid_samples > 0) ? (sum / valid_samples) : 0;  // 返回平均值(避免除零)
}

5.3 傳感器數(shù)據(jù)讀取

1.濕度傳感器讀?。╤umidity_read):

從ADC獲取濕度通道的平均原始值。

將ADC值轉(zhuǎn)換為電壓(基于3.3V參考電壓和12位ADC)。

通過傳感器特定公式將電壓轉(zhuǎn)換為濕度值(0-100%)。

對結(jié)果進行范圍限制,確保在有效區(qū)間內(nèi)。

2.光照強度讀?。╨ight_read_intensity):

從 ADC 獲取光照通道的平均原始值。

處理零值情況避免除零錯誤。

通過傳感器公式將ADC值轉(zhuǎn)換為光照強度(自定義單位)。

3.傳感器處理與控制(process_sensors_and_control):

讀取濕度和光照值并更新全局變量。

根據(jù)濕度閾值控制繼電器:低于低閾值打開(澆水),高于高閾值關(guān)閉(停止?jié)菜?/p>

打印當前狀態(tài)信息(濕度、光照、閥門狀態(tài)及閾值)。


#include "bsp_adc.h"
#include "do_sensor.h"
#include "sv.h"
#include 
extern float g_humidity_value;
extern float g_light_intensity;
extern uint8_t g_solenoid_valve_state;
extern int g_humidity_low_threshold;
extern int g_humidity_high_threshold;

/**
 * @brief 從傳感器讀取濕度值
 * @details 將ADC原始值轉(zhuǎn)換為相對濕度(0~100%)
 * @return 濕度值(0.0~100.0)
 */
float humidity_read(void) {
  // 從濕度通道(索引0)讀取ADC平均值
  uint16_t adc_raw_value = adc_get_average_value(0, ADC_BUFFER_SIZE / 2);

  // 將ADC值轉(zhuǎn)換為電壓(參考電壓3.3V,12位ADC)
  float voltage = adc_raw_value * 3.3f / 4096.0f;

  // 將電壓轉(zhuǎn)換為濕度(傳感器特定公式)
  float humidity = (3.3f - voltage) * 30.3f;

  // 將值限制在有效范圍內(nèi)(0~100%)
  if (humidity < 0.0f) {
    humidity = 0.0f;
  }
  if (humidity > 100.0f) {
    humidity = 100.0f;
  }

  return humidity;
}

/**
 * @brief 從傳感器讀取光照強度
 * @details 將ADC原始值轉(zhuǎn)換為光照強度(任意單位)
 * @return 光照強度值
 */
float light_read_intensity(void) {
  // 從光照通道(索引1)讀取ADC平均值
  uint16_t adc_raw_value = adc_get_average_value(1, ADC_BUFFER_SIZE / 2);

  // 避免除零錯誤
  if (adc_raw_value == 0) {
    adc_raw_value = 1;
  }

  // 將ADC值轉(zhuǎn)換為光照強度(傳感器特定公式)
  return 500000.0f / (float)adc_raw_value;
}

/**
 * @brief 讀取傳感器并控制電磁閥
 * @details 讀取濕度和光照傳感器,基于閾值控制閥門
 */
void process_sensors_and_control(void) {
  g_humidity_value = humidity_read();
  g_light_intensity = light_read_intensity();

  // 基于濕度閾值控制電磁閥
  if (g_humidity_value < g_humidity_low_threshold) {
    g_solenoid_valve_state = 1;
    sv_open(); // 打開閥門(開始澆水)
  } else if (g_humidity_value > g_humidity_high_threshold) {
    g_solenoid_valve_state = 0;
    sv_close(); // 關(guān)閉閥門(停止?jié)菜?
  }

  // 打印當前狀態(tài)
  printf("Humidity:%.1f Light:%.0f Valve:%s Low:%d High:%drn",
         g_humidity_value, g_light_intensity,
         g_solenoid_valve_state ? "ON" : "OFF", g_humidity_low_threshold,
         g_humidity_high_threshold);
}

5.4 繼電器控制澆灌

1.硬件定義與初始化:

定義繼電器控制引腳為 GPIOB的Pin10。

sv_init() 函數(shù)負責初始化GPIO:

使能GPIOB時鐘。

配置引腳為開漏輸出模式(GPIO_Mode_Out_OD),速度50MHz。

初始狀態(tài)設(shè)置為高電平(關(guān)閉繼電器,利用開漏模式的內(nèi)部上拉)。

2.核心控制函數(shù):

sv_close():通過設(shè)置引腳為高電平關(guān)閉繼電器,停止?jié)菜?,并打印狀態(tài)信息。

sv_open():通過清除引腳為低電平打開繼電器,開始澆水,并打印狀態(tài)信息。

#include "bsp_uart.h"
#include "sv.h"
#include "w55mh32_rcc.h"
#include 

/* 電磁閥控制引腳 */
#define SOLENOID_VALVE_PIN GPIO_Pin_10
#define SOLENOID_VALVE_PORT GPIOB

/**
 * @brief 初始化電磁閥(繼電器)控制
 * @details 配置GPIO引腳為開漏模式用于繼電器控制
 */
void sv_init(void) {
  GPIO_InitTypeDef gpio_init_struct;

  // 使能GPIOB時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  // 配置引腳為開漏輸出(繼電器控制)
  gpio_init_struct.GPIO_Mode = GPIO_Mode_Out_OD;
  gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz;
  gpio_init_struct.GPIO_Pin = SOLENOID_VALVE_PIN;
  GPIO_Init(SOLENOID_VALVE_PORT, &gpio_init_struct);

  // 初始狀態(tài):閥門關(guān)閉(引腳高電平,開漏模式配合內(nèi)部上拉)
  GPIO_SetBits(SOLENOID_VALVE_PORT, SOLENOID_VALVE_PIN);
}

/**
 * @brief 關(guān)閉繼電器(停止?jié)菜? * @details 設(shè)置繼電器控制引腳為高電平,使電磁閥失活
 */
void sv_close(void) {
  GPIO_SetBits(SOLENOID_VALVE_PORT, SOLENOID_VALVE_PIN);
  printf("Solenoid valve closed (high humidity).rn");
}

/**
 * @brief 打開繼電器(開始澆水)
 * @details 清除繼電器控制引腳為低電平,使電磁閥激活
 */
void sv_open(void) {
  GPIO_ResetBits(SOLENOID_VALVE_PORT, SOLENOID_VALVE_PIN);
  printf("Solenoid valve opened (low humidity).rn");
}
    

5.5 連接阿里云

1.功能定位:通過 MQTT 協(xié)議實現(xiàn)設(shè)備與阿里云 IoT 平臺的雙向通信,完成傳感器數(shù)據(jù)上報與云端控制指令接收。

2.核心配置:包含阿里云MQTT 服務(wù)器地址、端口、認證信息(客戶端ID、用戶名、密碼)及收發(fā)主題,采用QoS0等級通信。

3.關(guān)鍵流程:

初始化:解析域名、建立網(wǎng)絡(luò)連接、配置MQTT客戶端參數(shù)。

通信機制:通過狀態(tài)機管理連接、訂閱、消息收發(fā)及錯誤重連。

數(shù)據(jù)交互:將傳感器數(shù)據(jù)(濕度、光照、閥門狀態(tài))打包為JSON上報;解析云端上下發(fā)的JSON指令,控制閥門門開關(guān)及更新濕度閾值。

4.與系統(tǒng)集成:關(guān)聯(lián)傳感器數(shù)據(jù)全局變量,調(diào)用繼電器控制函數(shù),實現(xiàn)本地設(shè)備狀態(tài)與云端的同步。

需要注意:mqttconn s_mqtt_connection_params函數(shù)中參數(shù)要修改為4.1.2中創(chuàng)建設(shè)備的MQTT參數(shù)和訂閱發(fā)布主題。

#include "MQTTClient.h"
#include "cJSON.h"
#include "delay.h"
#include "do_dns.h"
#include "do_mqtt.h"
#include "mqtt_interface.h"
#include "sv.h"
#include "wiz_interface.h"
#include "wizchip_conf.h"
#include 


#define MQTT_ETHERNET_MAX_SIZE (1024 * 2) // MQTT緩沖區(qū)最大大小

/* MQTT控制句柄 */
MQTTClient g_mqtt_client = {0};
Network g_mqtt_network = {0};
int g_mqtt_conn_status;
static uint8_t s_mqtt_run_status = CONN; // MQTT狀態(tài)機狀態(tài)

/* MQTT連接參數(shù)(替換為你的設(shè)備憑證) */
static mqttconn s_mqtt_connection_params = {
    .mqttHostUrl = "iot-06z009vm5y6jfwj.mqtt.iothub.aliyuncs.com",
    .server_ip =
        {
            0,
        },
    .port = 1883,
    .clientid = "k1zh33h3hte.IGAT|securemode=2,signmethod=hmacsha256,timestamp="
                "1752635274022|",
    .username = "IGAT&k1zh33h3hte",
    .passwd =
        "f04b7d14d10a981e0eb6248da38b52060ff443c3f4b825d01594dfaa7e5720c1",
    .pubtopic = "/sys/k1zh33h3hte/IGAT/thing/event/property/post",
    .subtopic = "/sys/k1zh33h3hte/IGAT/thing/service/property/set",
    .pubQoS = QOS0,
};

/* MQTT接收緩沖區(qū)(靜態(tài)) */
static char s_mqtt_received_msg[512] = {0};
static uint8_t s_mqtt_receive_flag = 0; // 新MQTT消息標志

/* MQTT消息/配置結(jié)構(gòu) */
MQTTMessage g_mqtt_pub_msg = {.qos = QOS0, .retained = 0, .dup = 0, .id = 0};
MQTTPacket_willOptions g_mqtt_will = MQTTPacket_willOptions_initializer;
MQTTPacket_connectData g_mqtt_conn_data = MQTTPacket_connectData_initializer;

/* 全局傳感器數(shù)據(jù)(與main.c共享) */
float g_humidity_value = 0.0f;      // 當前濕度
float g_light_intensity = 0.0f;     // 當前光照強度
uint8_t g_solenoid_valve_state = 0; // 電磁閥狀態(tài)(1:開啟, 0:關(guān)閉)

/* 濕度閾值(與main.c共享) */
extern int g_humidity_low_threshold;
extern int g_humidity_high_threshold;

/**
 * @brief 初始化MQTT客戶端
 * @param sn 套接字號
 * @param send_buf MQTT發(fā)送數(shù)據(jù)緩沖區(qū)
 * @param recv_buf MQTT接收數(shù)據(jù)緩沖區(qū)
 */
void mqtt_init(uint8_t sn, uint8_t *send_buf, uint8_t *recv_buf) {
  wiz_NetInfo network_info = {0};
  wizchip_getnetinfo(&network_info);

  // 將MQTT服務(wù)器域名解析為IP地址
  if (do_dns(send_buf, (uint8_t *)s_mqtt_connection_params.mqttHostUrl,
             s_mqtt_connection_params.server_ip)) {
    while (1)
      ; // DNS解析失敗時停機
  }

  // 初始化網(wǎng)絡(luò)和MQTT客戶端
  NewNetwork(&g_mqtt_network, sn);
  ConnectNetwork(&g_mqtt_network, s_mqtt_connection_params.server_ip,
                 s_mqtt_connection_params.port);
  MQTTClientInit(&g_mqtt_client, &g_mqtt_network, 1000, send_buf,
                 MQTT_ETHERNET_MAX_SIZE, recv_buf, MQTT_ETHERNET_MAX_SIZE);

  // 配置MQTT連接參數(shù)
  g_mqtt_conn_data.willFlag = 0;
  g_mqtt_conn_data.MQTTVersion = 4;
  g_mqtt_conn_data.clientID.cstring = s_mqtt_connection_params.clientid;
  g_mqtt_conn_data.username.cstring = s_mqtt_connection_params.username;
  g_mqtt_conn_data.password.cstring = s_mqtt_connection_params.passwd;
  g_mqtt_conn_data.keepAliveInterval = 30;
  g_mqtt_conn_data.cleansession = 1;
}

/**
 * @brief 解碼MQTT JSON消息(設(shè)置閾值/閥門狀態(tài))
 * @param msg JSON消息負載
 */
void mqtt_json_decode(char *msg) {
  cJSON *root_json = cJSON_Parse(msg);
  if (!root_json) {
    printf("MQTT JSON parse failedrn");
    return;
  }

  // 從JSON中提取"params"對象
  cJSON *params_json = cJSON_GetObjectItem(root_json, "params");
  if (!params_json) {
    cJSON_Delete(root_json);
    return;
  }

  // 如果"Elect"字段存在,更新電磁閥狀態(tài)
  cJSON *valve_json = cJSON_GetObjectItem(params_json, "Elect");
  if (valve_json) {
    g_solenoid_valve_state = valve_json->valueint;
    if (g_solenoid_valve_state) {
      sv_open();
    } else {
      sv_close();
    }
  }

  // 如果"Low"/"High"字段存在,更新濕度閾值
  cJSON *low_threshold_json = cJSON_GetObjectItem(params_json, "Low");
  cJSON *high_threshold_json = cJSON_GetObjectItem(params_json, "High");
  if (low_threshold_json) {
    g_humidity_low_threshold = low_threshold_json->valueint;
  }
  if (high_threshold_json) {
    g_humidity_high_threshold = high_threshold_json->valueint;
  }

  // 確保閾值范圍有效(下限 <= 上限)
  if (g_humidity_low_threshold > g_humidity_high_threshold) {
    g_humidity_low_threshold = g_humidity_high_threshold - 1;
  }

  cJSON_Delete(root_json); // 釋放JSON對象
}

/**
 * @brief 接收MQTT消息的回調(diào)函數(shù)
 * @param md 消息數(shù)據(jù)(主題和負載)
 */
void mqtt_message_arrived(MessageData *md) {
  char topic_name[64] = {0};
  char msg_payload[512] = {0};

  // 提取主題和負載
  sprintf(topic_name, "%.*s", (int)md->topicName->lenstring.len,
          md->topicName->lenstring.data);
  sprintf(msg_payload, "%.*s", (int)md->message->payloadlen,
          (char *)md->message->payload);
  printf("MQTT recv: %s, %srnrn", topic_name, msg_payload);

  // 存儲消息并設(shè)置標志
  s_mqtt_receive_flag = 1;
  memset(s_mqtt_received_msg, 0, sizeof(s_mqtt_received_msg));
  memcpy(s_mqtt_received_msg, msg_payload, strlen(msg_payload));
}

/**
 * @brief 通過MQTT發(fā)布傳感器數(shù)據(jù)
 * @details 以JSON格式發(fā)送濕度、光照、閥門狀態(tài)和閾值
 */
void mqtt_post_properties(void) {
  char json_payload[256] = {0};

  // 將傳感器數(shù)據(jù)格式化為JSON負載
  int payload_len =
      snprintf(json_payload, sizeof(json_payload),
               "{"id":"123","version":"1.0","params":{"
               ""Elect":%d,"
               ""Humidity":%.1f,"
               ""light":%.0f,"
               ""Low":%d,"
               ""High":%d"
               "},"method":"thing.event.property.post"}",
               g_solenoid_valve_state, g_humidity_value, g_light_intensity,
               g_humidity_low_threshold, g_humidity_high_threshold);

  // 發(fā)布消息
  g_mqtt_pub_msg.payload = json_payload;
  g_mqtt_pub_msg.payloadlen = payload_len;
  MQTTPublish(&g_mqtt_client, s_mqtt_connection_params.pubtopic,
              &g_mqtt_pub_msg);
  printf("MQTT published: %s, %srnrn", s_mqtt_connection_params.pubtopic,
         json_payload);
}

/**
 * @brief MQTT狀態(tài)機(處理連接、訂閱和消息)
 */
void do_mqtt(void) {
  uint8_t ret;
  switch (s_mqtt_run_status) {
  case CONN: // 連接到MQTT服務(wù)器
    ret = MQTTConnect(&g_mqtt_client, &g_mqtt_conn_data);
    printf("Connecting to MQTT server: %d.%d.%d.%d:%drn",
           s_mqtt_connection_params.server_ip[0],
           s_mqtt_connection_params.server_ip[1],
           s_mqtt_connection_params.server_ip[2],
           s_mqtt_connection_params.server_ip[3],
           s_mqtt_connection_params.port);
    printf("Connection %srnrn", ret == SUCCESSS ? "success" : "failed");
    s_mqtt_run_status = (ret == SUCCESSS) ? SUB : ERR;
    break;

  case SUB: // 訂閱主題
    ret = MQTTSubscribe(&g_mqtt_client, s_mqtt_connection_params.subtopic,
                        s_mqtt_connection_params.pubQoS, mqtt_message_arrived);
    printf("Subscribing to %srn", s_mqtt_connection_params.subtopic);
    printf("Subscription %srnrn", ret == SUCCESSS ? "success" : "failed");
    s_mqtt_run_status = (ret == SUCCESSS) ? KEEPALIVE : ERR;
    break;

  case KEEPALIVE: // 維持連接并檢查消息
    if (MQTTYield(&g_mqtt_client, 30) != SUCCESSS) {
      s_mqtt_run_status = ERR;
      break;
    }
    // 繼續(xù)處理接收的消息
  case RECV: // 處理接收的消息
    if (s_mqtt_receive_flag) {
      s_mqtt_receive_flag = 0;
      mqtt_json_decode(s_mqtt_received_msg); // 解碼并處理消息
    }
    break;

  case ERR: // 處理錯誤(重試)
    printf("MQTT error! Reconnecting...rn");
    delay_ms(1000);
    s_mqtt_run_status = CONN; // 重試連接
    break;

  default:
    break;
  }
}
    

5.6 網(wǎng)頁控制

1.功能定位:提供Web服務(wù)接口,支持通過HTTP協(xié)議獲取設(shè)備狀態(tài)和控制參數(shù)。

2.核心功能:

解析HTTP 請求(支持 GET、POST方法)。

提供多個API端點:

根路徑/:返回網(wǎng)頁內(nèi)容。

/api/sensor:以JSON格式返回傳感器數(shù)據(jù)(濕度、光照、閥門狀態(tài)、閾值)。

/api/threshold:接收POST請求更新濕度閾值。

3.數(shù)據(jù)交互:

讀取全局變量獲取傳感器狀態(tài)和閾值。

通過HTTP響應(yīng)返回JSON格式數(shù)據(jù)。

解析POST請求中的JSON數(shù)據(jù)更新系統(tǒng)參數(shù)。

4.通信管理:

基于TCP狀態(tài)機管理連接生命周期(建立、數(shù)據(jù)傳輸、關(guān)閉)。

處理不同HTTP狀態(tài)碼(200、204、400、404)。

#include "cJSON.h"
#include "loopback.h"
#include "socket.h"
#include "web_page.h"
#include "wizchip_conf.h"
#include 
#include 
#include 


/* 使用web_page.h中定義的HTTP_RESPONSE_404 */
#define DATA_BUF_SIZE 1024
#define STR(x) #x // 用于行號的字符串化宏

/* 全局傳感器數(shù)據(jù)(與main.c共享) */
extern float g_humidity_value;
extern float g_light_intensity;
extern uint8_t g_solenoid_valve_state;
extern int g_humidity_low_threshold;
extern int g_humidity_high_threshold;

/**
 * @brief HTTP請求行結(jié)構(gòu)(方法、URI、版本)
 */
typedef struct {
  char method[16];  // 例如:"GET"
  char uri[256];    // 例如:"/api/sensor"
  char version[16]; // 例如:"HTTP/1.1"
} HttpReqLine;

/**
 * @brief 從原始數(shù)據(jù)解析HTTP請求行
 * @param request 原始HTTP請求數(shù)據(jù)
 * @param req_line 存儲解析結(jié)果的輸出結(jié)構(gòu)
 * @return 成功返回0,失敗返回-1
 */
static int http_parse_request_line(const char *request, HttpReqLine *req_line) {
  char buffer[1024];
  strncpy(buffer, request, sizeof(buffer));
  buffer[sizeof(buffer) - 1] = ''; // 確保字符串以空字符結(jié)尾

  // 查找第一行的結(jié)束符("rn"或"n")
  char *line_end = strstr(buffer, "rn");
  if (!line_end) {
    line_end = strstr(buffer, "n"); // 兼容Unix換行符
  }
  if (!line_end) {
    return -1; // 格式無效
  }
  *line_end = ''; // 截斷到第一行

  // 使用空格分割為方法、URI和版本
  char *method = strtok(buffer, " ");
  char *uri = strtok(NULL, " ");
  char *version = strtok(NULL, " ");

  if (!method || !uri || !version) {
    return -1; // 請求行不完整
  }

  // 將解析的值復(fù)制到結(jié)構(gòu)中
  strncpy(req_line->method, method, sizeof(req_line->method) - 1);
  strncpy(req_line->uri, uri, sizeof(req_line->uri) - 1);
  strncpy(req_line->version, version, sizeof(req_line->version) - 1);

  return 0;
}

/**
 * @brief 發(fā)送帶有CORS頭的HTTP響應(yīng)
 * @param sn 套接字號
 * @param status HTTP狀態(tài)碼(例如:"200 OK")
 * @param content_type MIME類型(例如:"application/json")
 * @param body 響應(yīng)體內(nèi)容
 */
static void send_http_response(uint8_t sn, const char *status,
                               const char *content_type, const char *body) {
  char response[512];
  int body_len = strlen(body);

  // 構(gòu)建帶有CORS頭的響應(yīng)
  sprintf(response,
          "HTTP/1.1 %srn"
          "Content-Type: %srn"
          "Access-Control-Allow-Origin: *rn"
          "Access-Control-Allow-Methods: GET, POST, OPTIONSrn"
          "Access-Control-Allow-Headers: Content-Typern"
          "Connection: closern"
          "Content-Length: %drn"
          "rn"
          "%s",
          status, content_type, body_len, body);

  // 發(fā)送完整響應(yīng)
  send(sn, (uint8_t *)response, strlen(response));
}

/**
 * @brief 帶HTTP支持的TCP服務(wù)器回環(huán)測試
 * @param sn 套接字號
 * @param network_buf 網(wǎng)絡(luò)數(shù)據(jù)緩沖區(qū)
 * @param port 監(jiān)聽端口
 * @return 成功返回1,失敗返回錯誤碼
 */
int32_t loopback_tcps(uint8_t sn, uint8_t *network_buf, uint16_t port) {
  int32_t ret;
  uint16_t recv_size = 0;
  uint16_t send_size = 0;

  switch (getSn_SR(sn)) {
  case SOCK_ESTABLISHED: // 連接已建立
    if (getSn_IR(sn) & Sn_IR_CON) {
      setSn_IR(sn, Sn_IR_CON); // 清除連接中斷標志
    }

    // 檢查接收數(shù)據(jù)
    if ((recv_size = getSn_RX_RSR(sn)) > 0) {
      if (recv_size > DATA_BUF_SIZE) {
        recv_size = DATA_BUF_SIZE; // 限制為緩沖區(qū)大小
      }

      // 讀取接收的數(shù)據(jù)
      ret = recv(sn, network_buf, recv_size);
      if (ret <= 0) {
        return ret; // 處理錯誤
      }
      recv_size = (uint16_t)ret;
      network_buf[recv_size] = ''; // 添加空終止符

      // 解析HTTP請求行
      HttpReqLine req_line;
      if (http_parse_request_line((char *)network_buf, &req_line) == 0) {
        printf("HTTP Method: %s, URI: %sn", req_line.method, req_line.uri);

        // 處理OPTIONS請求(CORS預(yù)檢)
        if (strcmp(req_line.method, "OPTIONS") == 0) {
          send_http_response(sn, "204 No Content", "text/plain", "");
          disconnect(sn);
          close(sn);
        }

        // 處理GET /(提供網(wǎng)頁)
        else if (strcmp(req_line.method, "GET") == 0 &&
                 strcmp(req_line.uri, "/") == 0) {
          uint16_t content_len = strlen(index_page);
          send_size = 0;
          while (strlen(index_page) != send_size) {
            ret = send(sn, (uint8_t *)index_page + send_size,
                       strlen(index_page) - send_size);
            if (ret < 0) {
              close(sn);
              return ret;
            }
            send_size += ret;
          }
          disconnect(sn);
          close(sn);
        }

        // 處理GET /api/sensor(返回傳感器數(shù)據(jù))
        else if (strcmp(req_line.method, "GET") == 0 &&
                 strcmp(req_line.uri, "/api/sensor") == 0) {
          char sensor_json[128];
          sprintf(sensor_json,
                  "{"humi":%.1f,"light":%.0f,"sv":"%s","low":%d,"
                  ""high":%d}",
                  g_humidity_value, g_light_intensity,
                  g_solenoid_valve_state ? "ON" : "OFF",
                  g_humidity_low_threshold, g_humidity_high_threshold);

          send_http_response(sn, "200 OK", "application/json", sensor_json);
          disconnect(sn);
          close(sn);
        }

        // 處理POST /api/threshold(更新閾值)
        else if (strcmp(req_line.method, "POST") == 0 &&
                 strcmp(req_line.uri, "/api/threshold") == 0) {
          // 查找請求體(健壯解析)
          char *body_start = NULL;
          char *header_end = strstr((char *)network_buf, "rnrn");

          if (header_end) {
            body_start = header_end + 4; // 跳過"rnrn"
          } else {
            // 兼容Unix換行符
            header_end = strstr((char *)network_buf, "nn");
            if (header_end) {
              body_start = header_end + 2; // 跳過"nn"
            }
          }

          // 驗證請求體存在
          if (!body_start || body_start >= (char *)network_buf + recv_size) {
            send_http_response(
                sn, "400 Bad Request", "application/json",
                "{"success":false, "error":"Missing request body"}");
            disconnect(sn);
            close(sn);
            return 1;
          }

          // 解析JSON請求體
          cJSON *root_json = cJSON_Parse(body_start);
          if (!root_json) {
            send_http_response(
                sn, "400 Bad Request", "application/json",
                "{"success":false, "error":"Invalid JSON format"}");
            disconnect(sn);
            close(sn);
            return 1;
          }

          // 提取并驗證閾值
          cJSON *low_json = cJSON_GetObjectItem(root_json, "low");
          cJSON *high_json = cJSON_GetObjectItem(root_json, "high");

          if (cJSON_IsNumber(low_json) && cJSON_IsNumber(high_json)) {
            int new_low = low_json->valueint;
            int new_high = high_json->valueint;

            // 驗證范圍
            if (new_low < 0 || new_high > 100 || new_low >= new_high) {
              send_http_response(sn, "400 Bad Request", "application/json",
                                 "{"success":false, "error":"Invalid "
                                 "range (0-100, low < high)"}");
            } else {
              // 更新閾值
              g_humidity_low_threshold = new_low;
              g_humidity_high_threshold = new_high;
              printf("Thresholds updated: Low=%d, High=%dn", new_low,
                     new_high);

              send_http_response(sn, "200 OK", "application/json",
                                 "{"success":true}");
            }
          } else {
            send_http_response(sn, "400 Bad Request", "application/json",
                               "{"success":false, "error":"Missing 'low' "
                               "or 'high' parameters"}");
          }

          cJSON_Delete(root_json); // 釋放JSON對象
          disconnect(sn);
          close(sn);
        }

        // 處理未知請求
        else {
          send_http_response(sn, "404 Not Found", "text/html",
                             "
Page Not Found"); disconnect(sn); close(sn); } } else { printf("Failed to parse HTTP requestn"); send_http_response( sn, "400 Bad Request", "application/json", "{"success":false, "error":"Invalid request format"}"); disconnect(sn); close(sn); } } break; case SOCK_CLOSE_WAIT: // 關(guān)閉等待狀態(tài) if ((ret = disconnect(sn)) != SOCK_OK) { return ret; } break; case SOCK_INIT: // 套接字已初始化,開始監(jiān)聽 if ((ret = listen(sn)) != SOCK_OK) { return ret; } break; case SOCK_CLOSED: // 套接字已關(guān)閉,重新初始化 if ((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) { return ret; } break; default: break; } return 1; }

6 功能驗證

程序燒錄完畢,硬件連接完成如下圖所示:

wKgZO2iVaIWARj4jAAQN6z0w7u0234.png

硬件連接完畢,上電通過串口助手打印如下信息:

wKgZPGiVaISAUsQYAAJf0cW25-A933.png

6.1 同步阿里云

通過串口每5S采集一次數(shù)據(jù)發(fā)送到云平臺,當我們把光照傳感器逐漸靠近光源,光照值越來越大。此時土壤濕度傳感器未插入土壤,在空氣中檢測濕度小于30%RH,繼電器打開,開始澆灌。

wKgZO2iVaISAEVPTAAN1jqcGqso148.pngwKgZO2iVaJOARsYvAFpZ7_vtiBQ973.png

當我們把土壤濕度傳感器插入盆栽中,可以看到當濕度小于30%RH時自動開始灌溉,當濕度大于50%RH時停止灌溉。

wKgZO2iVaIeAe0LdAAg-_bDyPD4184.pngwKgZPGiVaJWALbVwAGow3Lx-be0266.png

當濕度小于30%RH時繼電器打開,開始澆灌,當濕度大于50%RH時繼電器關(guān)閉停止灌溉。

wKgZO2iVaImAG5jlAA_zCL5JI7A949.png

服務(wù)器下發(fā)指令控制繼電器開關(guān),進而實現(xiàn)對澆灌啟停的控制。

wKgZPGiVaIqAJiZxAAzLYddel64222.png

6.2 網(wǎng)頁控制

通過網(wǎng)頁平臺不僅能實時監(jiān)測農(nóng)田環(huán)境數(shù)據(jù),更可遠程靈活設(shè)定調(diào)控閾值,讓田間管理實現(xiàn)精準化、智能化調(diào)控。

wKgZPGiVaIeAUB13AANEmCYUlgI206.png

7總結(jié)

該系統(tǒng)以W55MH32L-EVB為核心,通過MQTT連阿里云,采集土壤濕度、光照數(shù)據(jù),實現(xiàn)水泵智能控制。支持自動與遠程調(diào)控,5秒采集一次,同時支持網(wǎng)頁修改濕度閾值,功能穩(wěn)定,為智能灌溉提供有效方案。感謝大家的耐心閱讀!如果您在搭建過程中遇到硬件接線、阿里云配置或代碼調(diào)試問題,歡迎在評論區(qū)留言交流~ 覺得有幫助的話也請點贊收藏,您的支持是我分享的動力!

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機
    +關(guān)注

    關(guān)注

    6072

    文章

    45273

    瀏覽量

    661613
  • 阿里云
    +關(guān)注

    關(guān)注

    3

    文章

    1025

    瀏覽量

    45379
  • MQTT協(xié)議
    +關(guān)注

    關(guān)注

    0

    文章

    103

    瀏覽量

    6375
  • 智能農(nóng)業(yè)
    +關(guān)注

    關(guān)注

    0

    文章

    132

    瀏覽量

    8736
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    基于阿里MQTT物聯(lián)網(wǎng)平臺視頻監(jiān)控(下)

    1.項目介紹 ? ? ? 本項目基于物聯(lián)量平臺遠程的視頻監(jiān)控項目,通過MQTT協(xié)議實現(xiàn)兩個設(shè)備間的數(shù)據(jù)上報與訂閱。通過這個項目來演示,兩個MQTT設(shè)備如何互相訂閱,進行消息流轉(zhuǎn)。在
    的頭像 發(fā)表于 04-24 14:41 ?2332次閱讀
    基于<b class='flag-5'>阿里</b><b class='flag-5'>云</b><b class='flag-5'>MQTT</b>物聯(lián)網(wǎng)<b class='flag-5'>平臺</b>視頻<b class='flag-5'>監(jiān)控</b>(下)

    esp8266連接阿里平臺mqtt連接超時

    esp8266nodemcu在使用arduino.ide連接阿里平臺的時候,wifi配置正常但連接不上mqtt,顯示報錯如下: Attempting
    發(fā)表于 10-26 21:39

    【NXP LPC54110試用申請】基于計算的農(nóng)業(yè)智能檢測及農(nóng)產(chǎn)品溯源系統(tǒng)

    、平板電腦端、PC電腦端無縫對接。管理者可隨時隨地對種植園區(qū)進行遠程監(jiān)控。項目的獨特之處:目前市場上大多溯源系統(tǒng)只能展示如品種、產(chǎn)地、生產(chǎn)企業(yè)、產(chǎn)品簡介等簡單的信息,基于計算的農(nóng)業(yè)
    發(fā)表于 08-01 11:31

    基于阿里HiTSDB搭建工業(yè)物聯(lián)網(wǎng)平臺實踐

    :https://promotion.aliyun.com/ntms/act/hitsdbdebute2018.html平臺架構(gòu)邊緣計算:采集的工業(yè)數(shù)據(jù)上傳到阿里的物聯(lián)網(wǎng)套件,中間經(jīng)過了MQ
    發(fā)表于 04-24 15:37

    基于onenet平臺MQTT協(xié)議數(shù)據(jù)采集以及遠程控制的個人總結(jié)資料

    基于onenet平臺的環(huán)境監(jiān)測采集以及相應(yīng)遠程控制的個人總結(jié)修改的代碼資料。網(wǎng)絡(luò)傳輸協(xié)議為MQTT
    發(fā)表于 04-01 12:33

    如何通過MQTT協(xié)議連接物聯(lián)網(wǎng)阿里實現(xiàn)設(shè)備的遠程IO監(jiān)控開關(guān)量數(shù)字量模擬量狀態(tài)的讀取及控制

    本文介紹一種基于綜科智控科技開發(fā)有限公司的物聯(lián)網(wǎng)網(wǎng)關(guān)ZKB-1E1L實現(xiàn)的通過MQTT協(xié)議連接物聯(lián)網(wǎng)阿里實現(xiàn)設(shè)備的遠程IO監(jiān)控開關(guān)量數(shù)字量模擬量狀態(tài)的讀取及
    發(fā)表于 09-19 11:59

    基于鴻蒙Hi3861V100 MQTT協(xié)議 對接阿里物聯(lián)網(wǎng)平臺

    更新啦?。。。。。。。。?!基于鴻蒙HarmonyOS Hi3861V100 開發(fā)板通過MQTT協(xié)議 對接阿里IOT物聯(lián)網(wǎng)平臺同時支持APP端、IOT
    發(fā)表于 01-25 08:31

    stm32+W5500 與 阿里微消息隊列 MQTT版本

    本帖最后由 北洋水師 于 2021-7-23 11:00 編輯 目的: STM32 + W5500 嵌入式以太網(wǎng)卡訪問 阿里微消息隊列 MQTT 服務(wù)器、實現(xiàn)基礎(chǔ)的發(fā)布和訂閱。開發(fā)工具
    發(fā)表于 07-23 10:55

    如何用阿里的Iot Studio制作web網(wǎng)頁

    如何用阿里的Iot Studio制作web網(wǎng)頁呢?并用產(chǎn)品自帶的topic傳輸數(shù)據(jù)網(wǎng)頁端呢?
    發(fā)表于 02-22 06:21

    基于OpenHarmony的阿里IoT服務(wù)實現(xiàn)

    用,廣泛應(yīng)用于物聯(lián)網(wǎng)(IoT)。MQTT協(xié)議在衛(wèi)星鏈路通信傳感器、醫(yī)療設(shè)備、智能家居、及一些小型化設(shè)備中已廣泛使用。阿里為國內(nèi)主流的
    發(fā)表于 06-17 09:36

    【OpenHarmony開源開發(fā)者成長計劃解決方案學生挑戰(zhàn)賽】--基于OpenHarmony的智慧農(nóng)業(yè)環(huán)境監(jiān)控系統(tǒng)設(shè)計

    【項目名稱】基于OpenHarmony的智慧農(nóng)業(yè)環(huán)境監(jiān)控系統(tǒng)設(shè)計【項目負責人】:張銘哲1、項目描述?環(huán)境監(jiān)控和自動化控制
    發(fā)表于 09-02 21:20

    微信小程序使用MQTT遠程控制單片機——阿里物聯(lián)網(wǎng)平臺

    微信小程序使用MQTT遠程控制單片機——阿里物聯(lián)網(wǎng)平臺
    發(fā)表于 11-13 17:36 ?36次下載
    微信小程序使用<b class='flag-5'>MQTT</b>遠程<b class='flag-5'>控制</b>單片機——<b class='flag-5'>阿里</b><b class='flag-5'>云</b>物聯(lián)網(wǎng)<b class='flag-5'>平臺</b>

    基于阿里MQTT物聯(lián)網(wǎng)平臺視頻監(jiān)控(上)

    本項目基于物聯(lián)量平臺遠程的視頻監(jiān)控項目,通過MQTT協(xié)議實現(xiàn)兩個設(shè)備間的數(shù)據(jù)上報與訂閱。通過這個項目來演示,兩個MQTT設(shè)備如何互相訂閱,進行消息流轉(zhuǎn)。在
    的頭像 發(fā)表于 04-18 16:58 ?2297次閱讀
    基于<b class='flag-5'>阿里</b><b class='flag-5'>云</b><b class='flag-5'>MQTT</b>物聯(lián)網(wǎng)<b class='flag-5'>平臺</b>視頻<b class='flag-5'>監(jiān)控</b>(上)

    MQTT接入阿里IoT平臺使用說明

    MQTT接入阿里IoT平臺使用說明
    發(fā)表于 03-06 17:37 ?4次下載

    如何輕松實現(xiàn)MQTT接入阿里IoT平臺

    教你輕松實現(xiàn)使用MQTT協(xié)議接入阿里平臺
    發(fā)表于 03-29 11:05 ?10次下載