国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

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

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

3天內不再提示

智能農業監控系統:MQTT阿里云平臺監測+內置Web網頁控制+代碼解析

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

掃碼添加小助手

加入工程師交流群

軟硬件開源項目-智能農業監控系統:MQTT阿里云平臺監測+內置Web網頁控制+代碼解析

智能農業監控系統:開源項目推薦

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

完整顯示視頻bilibili|點擊跳轉

1 項目構思與核心目標

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

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

核心目標:

硬件層面:實現傳感器數據采集與執行器(水泵)控制的穩定聯動,確保環境數據實時性與設備響應可靠性。

軟件層面:完成 MQTT 協議對接阿里云,實現設備與云端的雙向數據傳輸,同時支持本地網頁控制和環境數據查看。

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

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

1.1 方案圖示

wKgZPGiVaIOAGFKmAACJ-5yiZaI734.png

2 硬件選型與搭建

2.1 核心組件清單

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

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

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

輔助設備:外部 5V 電源、網線、路由器、杜邦線若干。

2.2 電路連接技巧

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

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

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

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

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

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

3 開發環境搭建

3.1 軟件工具鏈

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

調試工具:WIZ UartTool串口助手,其他串口助手也可。

瀏覽器:用于打開網頁查看。

云平臺:阿里云物聯網平臺(需完成實名認證)。

源碼:gitee倉庫項目倉庫地址|點擊跳轉

4 連接阿里云物聯網平臺

4.1 MQTT連接阿里云收發數據流程

4.1.1 準備階段

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

創建產品和添加物模型:登錄阿里云物聯網平臺,創建產品并在產品下添加以下物模型功能。

wKgZO2iVaIWATUqbAAXq13gW2BI244.png

創建設備:在剛剛創建的產品下創建一個設備。

wKgZO2iVaIOAd6PxAAD0br08nQ0304.png

4.1.2 記錄參數

連接參數:在剛剛創建的設備詳情頁中找到MQTT連接參數。

wKgZPGiVaISAMExlAAJql4u5KMM271.png

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

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

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

wKgZO2iVaIOAGGqWAAFrxzSq4T4795.png

4.1.3 連接、訂閱和發布消息

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

在阿里云平臺,如果產品創建階段選擇的數據格式為Alink JSON格式時,接收和發送數據格式都會遵守下面這個格式:

{
   "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.系統初始化與硬件配置

完成基礎硬件初始化(時鐘、延時、串口、定時器等),配置ADC(模數轉換)用于傳感器數據采集,初始化繼電器控制模塊,并設置WIZnet以太網芯片的網絡參數(MAC、IP、網關等)。

2.網絡通信功能 實現雙重網絡通信能力:

MQTT協議:通過MQTT客戶端(do_mqtt()和mqtt_post_properties())實現傳感器數據的遠程發布。

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

3.傳感器數據處理與控制

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

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

將實時數據(濕度、光照、繼電器狀態)通過MQTT發布到阿里平臺同時刷新網頁環境數據。

#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 

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

/* 濕度閾值(與阿里云IoT模型對齊,范圍0~100) */
int g_humidity_low_threshold = 30;  // 澆水的下限閾值
int g_humidity_high_threshold = 50; // 停止澆水的上限閾值

/* 函數原型 */
extern void mqtt_post_properties(void);

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

uint16_t g_tcp_listen_port = 8080;     // TCP服務器監聽端口
wiz_NetInfo g_default_network_info = { // 默認網絡配置
    .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}; // 以太網數據緩沖區
static uint8_t s_mqtt_send_buf[ETHERNET_BUF_MAX_SIZE] = {
    0}; // MQTT發送緩沖區(靜態)
static uint8_t s_mqtt_recv_buf[ETHERNET_BUF_MAX_SIZE] = {
    0}; // MQTT接收緩沖區(靜態)

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

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

  printf("%s 傳感器監控系統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); // 網絡初始化
  mqtt_init(SOCKET_MQTT_ID, s_mqtt_send_buf, s_mqtt_recv_buf); // MQTT初始化
  printf("系統初始化完成。rn");
  
  while (1) {
    do_mqtt(); // 處理MQTT通信

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

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

5.2 ADC采集

1.關鍵配置:

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

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

設置DMA以循環方式將 ADC 數據傳輸到緩沖區,無需CPU干預。

2.數據處理:

采樣數據交替存儲在s_adc_dma_buffer緩沖區中。

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

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


/* ADC DMA數據靜態緩沖區(存儲交替的通道讀數) */
static uint16_t s_adc_dma_buffer[ADC_BUFFER_SIZE];

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

  // 使能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為連續掃描模式
  ADC_StructInit(&adc_init_struct);  // 初始化ADC結構體為默認值
  adc_init_struct.ADC_Mode = ADC_Mode_Independent;  // 獨立模式
  adc_init_struct.ADC_ScanConvMode = ENABLE;  // 使能掃描模式
  adc_init_struct.ADC_ContinuousConvMode = ENABLE;  // 使能連續轉換模式
  adc_init_struct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 無外部觸發
  adc_init_struct.ADC_DataAlign = ADC_DataAlign_Right;  // 數據右對齊
  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數據傳輸
  DMA_DeInit(DMA1_Channel1);  // 重置DMA通道1配置
  dma_init_struct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  // 外設基地址(ADC數據寄存器)
  dma_init_struct.DMA_MemoryBaseAddr = (uint32_t)s_adc_dma_buffer;  // 內存基地址(DMA緩沖區)
  dma_init_struct.DMA_DIR = DMA_DIR_PeripheralSRC;  // 傳輸方向:外設到內存
  dma_init_struct.DMA_BufferSize = ADC_BUFFER_SIZE;  // 緩沖區大小
  dma_init_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // 禁止外設地址遞增
  dma_init_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 使能內存地址遞增
  dma_init_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  // 外設數據大?。喊胱郑?6位)
  dma_init_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  // 內存數據大小:半字(16位)
  dma_init_struct.DMA_Mode = DMA_Mode_Circular;  // 循環模式
  dma_init_struct.DMA_Priority = DMA_Priority_High;  // 高優先級
  dma_init_struct.DMA_M2M = DMA_M2M_Disable;  // 禁止內存到內存傳輸
  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);  // 軟件觸發ADC轉換
}

/**
 * @brief 獲取特定通道的ADC平均值
 * @param channel_index ADC通道索引(0: 濕度, 1: 光照)
 * @param sample_count 用于平均的樣本數量
 * @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;  // 有效樣本數

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

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

5.3 傳感器數據讀取

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

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

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

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

對結果進行范圍限制,確保在有效區間內。

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

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

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

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

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

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

根據濕度閾值控制繼電器:低于低閾值打開(澆水),高于高閾值關閉(停止澆水)。

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


#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原始值轉換為相對濕度(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值轉換為電壓(參考電壓3.3V,12位ADC)
  float voltage = adc_raw_value * 3.3f / 4096.0f;

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

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

  return humidity;
}

/**
 * @brief 從傳感器讀取光照強度
 * @details 將ADC原始值轉換為光照強度(任意單位)
 * @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值轉換為光照強度(傳感器特定公式)
  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(); // 關閉閥門(停止澆水)
  }

  // 打印當前狀態
  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() 函數負責初始化GPIO:

使能GPIOB時鐘。

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

初始狀態設置為高電平(關閉繼電器,利用開漏模式的內部上拉)。

2.核心控制函數:

sv_close():通過設置引腳為高電平關閉繼電器,停止澆水,并打印狀態信息。

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

#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);

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

/**
 * @brief 關閉繼電器(停止澆水)
 * @details 設置繼電器控制引腳為高電平,使電磁閥失活
 */
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 協議實現設備與阿里云 IoT 平臺的雙向通信,完成傳感器數據上報與云端控制指令接收。

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

3.關鍵流程:

初始化:解析域名、建立網絡連接、配置MQTT客戶端參數。

通信機制:通過狀態機管理連接、訂閱、消息收發及錯誤重連。

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

4.與系統集成:關聯傳感器數據全局變量,調用繼電器控制函數,實現本地設備狀態與云端的同步。

需要注意:mqttconn s_mqtt_connection_params函數中參數要修改為4.1.2中創建設備的MQTT參數和訂閱發布主題。

#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緩沖區最大大小

/* 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狀態機狀態

/* MQTT連接參數(替換為你的設備憑證) */
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接收緩沖區(靜態) */
static char s_mqtt_received_msg[512] = {0};
static uint8_t s_mqtt_receive_flag = 0; // 新MQTT消息標志

/* MQTT消息/配置結構 */
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;

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

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

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

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

  // 初始化網絡和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連接參數
  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消息(設置閾值/閥門狀態)
 * @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"字段存在,更新電磁閥狀態
  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消息的回調函數
 * @param md 消息數據(主題和負載)
 */
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);

  // 存儲消息并設置標志
  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發布傳感器數據
 * @details 以JSON格式發送濕度、光照、閥門狀態和閾值
 */
void mqtt_post_properties(void) {
  char json_payload[256] = {0};

  // 將傳感器數據格式化為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);

  // 發布消息
  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狀態機(處理連接、訂閱和消息)
 */
void do_mqtt(void) {
  uint8_t ret;
  switch (s_mqtt_run_status) {
  case CONN: // 連接到MQTT服務器
    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;
    }
    // 繼續處理接收的消息
  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 網頁控制

1.功能定位:提供Web服務接口,支持通過HTTP協議獲取設備狀態和控制參數。

2.核心功能:

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

提供多個API端點:

根路徑/:返回網頁內容。

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

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

3.數據交互:

讀取全局變量獲取傳感器狀態和閾值。

通過HTTP響應返回JSON格式數據。

解析POST請求中的JSON數據更新系統參數。

4.通信管理:

基于TCP狀態機管理連接生命周期(建立、數據傳輸、關閉)。

處理不同HTTP狀態碼(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 // 用于行號的字符串化宏

/* 全局傳感器數據(與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請求行結構(方法、URI、版本)
 */
typedef struct {
  char method[16];  // 例如:"GET"
  char uri[256];    // 例如:"/api/sensor"
  char version[16]; // 例如:"HTTP/1.1"
} HttpReqLine;

/**
 * @brief 從原始數據解析HTTP請求行
 * @param request 原始HTTP請求數據
 * @param req_line 存儲解析結果的輸出結構
 * @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] = ''; // 確保字符串以空字符結尾

  // 查找第一行的結束符("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; // 請求行不完整
  }

  // 將解析的值復制到結構中
  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 發送帶有CORS頭的HTTP響應
 * @param sn 套接字號
 * @param status HTTP狀態碼(例如:"200 OK")
 * @param content_type MIME類型(例如:"application/json")
 * @param body 響應體內容
 */
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);

  // 構建帶有CORS頭的響應
  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);

  // 發送完整響應
  send(sn, (uint8_t *)response, strlen(response));
}

/**
 * @brief 帶HTTP支持的TCP服務器回環測試
 * @param sn 套接字號
 * @param network_buf 網絡數據緩沖區
 * @param port 監聽端口
 * @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); // 清除連接中斷標志
    }

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

      // 讀取接收的數據
      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預檢)
        if (strcmp(req_line.method, "OPTIONS") == 0) {
          send_http_response(sn, "204 No Content", "text/plain", "");
          disconnect(sn);
          close(sn);
        }

        // 處理GET /(提供網頁)
        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(返回傳感器數據)
        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: // 關閉等待狀態 if ((ret = disconnect(sn)) != SOCK_OK) { return ret; } break; case SOCK_INIT: // 套接字已初始化,開始監聽 if ((ret = listen(sn)) != SOCK_OK) { return ret; } break; case SOCK_CLOSED: // 套接字已關閉,重新初始化 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采集一次數據發送到云平臺,當我們把光照傳感器逐漸靠近光源,光照值越來越大。此時土壤濕度傳感器未插入土壤,在空氣中檢測濕度小于30%RH,繼電器打開,開始澆灌。

wKgZO2iVaISAEVPTAAN1jqcGqso148.pngwKgZO2iVaJOARsYvAFpZ7_vtiBQ973.png

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

wKgZO2iVaIeAe0LdAAg-_bDyPD4184.pngwKgZPGiVaJWALbVwAGow3Lx-be0266.png

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

wKgZO2iVaImAG5jlAA_zCL5JI7A949.png

服務器下發指令控制繼電器開關,進而實現對澆灌啟停的控制。

wKgZPGiVaIqAJiZxAAzLYddel64222.png

6.2 網頁控制

通過網頁平臺不僅能實時監測農田環境數據,更可遠程靈活設定調控閾值,讓田間管理實現精準化、智能化調控。

wKgZPGiVaIeAUB13AANEmCYUlgI206.png

7總結

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

審核編輯 黃宇

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

    關注

    6076

    文章

    45494

    瀏覽量

    670269
  • 阿里云
    +關注

    關注

    3

    文章

    1038

    瀏覽量

    45689
  • MQTT協議
    +關注

    關注

    0

    文章

    104

    瀏覽量

    6531
  • 智能農業
    +關注

    關注

    0

    文章

    136

    瀏覽量

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    基于阿里MQTT物聯網平臺視頻監控(下)

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

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

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

    【NXP LPC54110試用申請】基于計算的農業智能檢測及農產品溯源系統

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

    基于阿里HiTSDB搭建工業物聯網平臺實踐

    :https://promotion.aliyun.com/ntms/act/hitsdbdebute2018.html平臺架構邊緣計算:采集的工業數據上傳到阿里的物聯網套件,中間經過了MQ
    發表于 04-24 15:37

    基于onenet平臺MQTT協議數據采集以及遠程控制的個人總結資料

    基于onenet平臺的環境監測采集以及相應遠程控制的個人總結修改的代碼資料。網絡傳輸協議為MQTT
    發表于 04-01 12:33

    如何通過MQTT協議連接物聯網阿里實現設備的遠程IO監控開關量數字量模擬量狀態的讀取及控制

    本文介紹一種基于綜科智控科技開發有限公司的物聯網網關ZKB-1E1L實現的通過MQTT協議連接物聯網阿里實現設備的遠程IO監控開關量數字量模擬量狀態的讀取及
    發表于 09-19 11:59

    基于鴻蒙Hi3861V100 MQTT協議 對接阿里物聯網平臺

    更新啦?。。。。。。。。?!基于鴻蒙HarmonyOS Hi3861V100 開發板通過MQTT協議 對接阿里IOT物聯網平臺同時支持APP端、IOT
    發表于 01-25 08:31

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

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

    如何用阿里的Iot Studio制作web網頁

    如何用阿里的Iot Studio制作web網頁呢?并用產品自帶的topic傳輸數據網頁端呢?
    發表于 02-22 06:21

    基于OpenHarmony的阿里IoT服務實現

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

    【OpenHarmony開源開發者成長計劃解決方案學生挑戰賽】--基于OpenHarmony的智慧農業環境監控系統設計

    【項目名稱】基于OpenHarmony的智慧農業環境監控系統設計【項目負責人】:張銘哲1、項目描述?環境監控和自動化控制
    發表于 09-02 21:20

    微信小程序使用MQTT遠程控制單片機——阿里物聯網平臺

    微信小程序使用MQTT遠程控制單片機——阿里物聯網平臺
    發表于 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>物聯網<b class='flag-5'>平臺</b>

    基于阿里MQTT物聯網平臺視頻監控(上)

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

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

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

    如何輕松實現MQTT接入阿里IoT平臺

    教你輕松實現使用MQTT協議接入阿里平臺
    發表于 03-29 11:05 ?10次下載