軟硬件開源項(xiàng)目-智能路燈系統(tǒng):OneNET云平臺(tái)監(jiān)測(cè)+Web網(wǎng)頁(yè)控制+代碼解析
智能路燈系統(tǒng)項(xiàng)目下載源碼
本倉(cāng)庫(kù)提供了完整的智能路燈系統(tǒng)項(xiàng)目的源碼,旨在幫助開發(fā)者快速搭建和理解智能路燈系統(tǒng)的實(shí)現(xiàn)過(guò)程。
項(xiàng)目地址:https://gitee.com/zhu-heyang/w55mh32-smart-street-light.git
1 前言
前兩天晚上出去溜達(dá)的時(shí)候,路過(guò)路燈的時(shí)候,感覺(jué)燈光很強(qiáng)刺的人睜不開眼,而且那么高的亮度一直亮著也不省電,當(dāng)時(shí)我就想要是我來(lái)設(shè)計(jì)路燈的話可能不會(huì)這樣設(shè)計(jì),如果是我的話一定會(huì)加上一個(gè)亮度自適應(yīng)的功能,沒(méi)人的時(shí)候就亮度低一點(diǎn)有人的時(shí)候就更亮一點(diǎn)人走一會(huì)才恢復(fù)原來(lái)的亮度,而且現(xiàn)在物聯(lián)網(wǎng)那么發(fā)達(dá),應(yīng)該加上一個(gè)遠(yuǎn)程控制的功能。于是說(shuō)干就干,挑硬件時(shí)在淘寶上發(fā)現(xiàn)了 W55MH32Q 這款開發(fā)板,它的性能跟我這個(gè)項(xiàng)目的需求特別對(duì)得上,然后就選擇了這款開發(fā)板,我選它主要有三個(gè)原因:
一是自帶以太網(wǎng)功能,無(wú)需額外掛載通信模塊,就能穩(wěn)定運(yùn)行 MQTT 協(xié)議傳輸數(shù)據(jù),省去了模塊兼容調(diào)試的麻煩,數(shù)據(jù)傳輸?shù)目煽啃砸哺斜U稀?br /> 二是接口設(shè)計(jì)合理,紅外傳感器器和光照傳感器可直接通過(guò)標(biāo)準(zhǔn)接口連接,硬件層無(wú)需額外電平轉(zhuǎn)換或隔離電路,適配過(guò)程很順暢。
三是集成了串口芯片,無(wú)需外接 USB 轉(zhuǎn)串口模塊,直接通過(guò)串口助手就能打印調(diào)試信息,對(duì)嵌入式開發(fā)來(lái)說(shuō),這種無(wú)需外接模塊的調(diào)試支持簡(jiǎn)直是太方便了。
以此搭建的系統(tǒng)通過(guò)紅外和光照傳感器每 5 秒采集一次環(huán)境數(shù)據(jù),經(jīng)開發(fā)板處理后上傳 OneNET 平臺(tái)。自動(dòng)模式下,光照低于網(wǎng)頁(yè)設(shè)定閾值時(shí) LED 以 20% 初始亮度開啟(初始亮度可通過(guò)網(wǎng)頁(yè)端調(diào)節(jié)),紅外檢測(cè)到行人 / 車輛即升至 100%,離開 10 秒后恢復(fù)低亮;手動(dòng)模式支持網(wǎng)頁(yè)端直接控制LED燈的開關(guān)與亮度。開發(fā)板的接口兼容性與網(wǎng)絡(luò)穩(wěn)定性保障了系統(tǒng)精準(zhǔn)響應(yīng)與節(jié)能目標(biāo)。
2 項(xiàng)目環(huán)境
2.1 硬件要求
- W55MH32Q開發(fā)板
- LED燈、光照傳感器、紅外傳感器
- USB Type-C數(shù)據(jù)線
- 路由器
2.2 軟件環(huán)境
3 硬件連接和方案
3.1 系統(tǒng)硬件連接
- LED燈正極連接開發(fā)板A0引腳
- 紅外傳感器數(shù)據(jù)采樣引腳OUT接開發(fā)板A3引腳
- 光照傳感器數(shù)據(jù)采樣引腳AO連接開發(fā)板A4引腳
3.2 方案圖示
![![Alternative Text][1754209011187]](https://file1.elecfans.com/web3/M00/28/9D/wKgZPGiVXheAUXiMAACqSCbWgjQ488.png)
4 MQTT連接OneNET云平臺(tái)收發(fā)數(shù)據(jù)流程
4.1 準(zhǔn)備階段
注冊(cè)賬號(hào)在這里不進(jìn)行贅述,下面我們看如何建立物模型。
創(chuàng)建產(chǎn)品和添加物模型:登錄OneNET物聯(lián)網(wǎng)平臺(tái),創(chuàng)建產(chǎn)品并在產(chǎn)品下添加以下物模型功能。
創(chuàng)建設(shè)備:在剛剛創(chuàng)建的產(chǎn)品下創(chuàng)建相應(yīng)設(shè)備。

4.2 設(shè)備詳情
設(shè)備詳情:在設(shè)備詳情頁(yè)中可以查看設(shè)備密鑰和產(chǎn)品ID等重要信息。
![![Alternative Text][1754444580728]](https://file1.elecfans.com/web3/M00/28/9D/wKgZPGiVXheAHjFgAALtUUL50_M419.png)
4.3 Token 密鑰生成
設(shè)備與 OneNet 平臺(tái)通信時(shí),Token 作為身份憑證用于安全認(rèn)證。需使用 Token 生成工具:
OneNET Token 生成工具文檔
- res 字段:
products/{產(chǎn)品id}/devices/{設(shè)備名}(使用設(shè)備級(jí) Key)。替換{產(chǎn)品id}和{設(shè)備名}。 - et 字段: 訪問(wèn)過(guò)期時(shí)間 (Unix 時(shí)間戳)??墒褂迷诰€轉(zhuǎn)換工具獲取。
- key 字段: 填寫設(shè)備的密鑰。
- 點(diǎn)擊
generate生成 Token 密鑰 。

4.4 連接、訂閱和發(fā)布消息
訂閱主題:$sys/{pid}/{device-name}/thing/property/set
發(fā)布主題:$sys/{pid}/{device-name}/thing/property/post
pid是product_id的簡(jiǎn)稱,即產(chǎn)品ID。
device-name是設(shè)備名稱。
接著我們可以使用上面記錄的連接參數(shù)進(jìn)行連接,當(dāng)連接成功后,訂閱上面的訂閱主題。并通過(guò)發(fā)布主題上報(bào)物模型數(shù)據(jù)。
在OneNET平臺(tái),如果產(chǎn)品創(chuàng)建階段選擇的數(shù)據(jù)格式為OneJSON格式時(shí),接收和發(fā)送數(shù)據(jù)格式都會(huì)遵守下面這個(gè)格式:
{
"id": "123",
"version": "1.0",
"params": {
"temperature":"30.5"
}
}
id:值為"123",這是一個(gè)唯一的標(biāo)識(shí)符;params是一個(gè)包含設(shè)備屬性數(shù)據(jù)的對(duì)象用于上報(bào)物模型數(shù)據(jù);version:值為 "1.0",表示該消息所遵循的協(xié)議版本。
4.5 接收消息處理
接收消息:當(dāng)接收到消息時(shí),我們只需要按照上面的json格式進(jìn)行解析,然后進(jìn)行相應(yīng)的處理即可。
5 HBuilder X
- HBuilder X工程下載:
- 鏈接: https://pan.baidu.com/s/1oIIr3oTnHG-we22AkLQu8w?pwd=6en9
- 提取碼:
6en9
- 修改步驟:
- 下載后導(dǎo)入 HBuilder X 。
- 修改
index.vue文件:- 修改 Token: 替換 const params = {
author_key: '', //用戶密鑰
version: '2022-05-01',
user_id: '', //用戶ID
} 中的author_key和user_id即可生成用戶 Token。 - 修改產(chǎn)品 ID 和設(shè)備名: 在
url中替換product_id和device_name參數(shù)為實(shí)際值。
- 修改 Token: 替換 const params = {
- 修改完畢后即可通過(guò)HBuilder X自帶的發(fā)行功能對(duì)文件進(jìn)行打包,可打包成網(wǎng)頁(yè)或者APP根據(jù)需要可自行選擇。
![![Alternative Text][1754124884773]](https://file1.elecfans.com/web3/M00/28/9D/wKgZPGiVXheAatQzAANcQ9V8szM344.png)
6 主要程序解析
6.1 main.c分析
在主函數(shù)中實(shí)現(xiàn)以下軟硬件初始化:配置時(shí)鐘、串口、定時(shí)器,初始化紅外傳感器、光照傳感器和LED燈。
網(wǎng)絡(luò)初始化:配置開發(fā)板和MQTT客戶端,支持DHCP 動(dòng)態(tài)獲取IP。
數(shù)據(jù)采集與控制:每5秒采集一次光照強(qiáng)度和監(jiān)測(cè)紅外感應(yīng),調(diào)用LED燈控制函數(shù)。
數(shù)據(jù)上傳:調(diào)用light_control()和do_mqtt()函數(shù)將傳感器數(shù)據(jù)和設(shè)備狀態(tài)發(fā)送到云平臺(tái)。
#include "PWM.h"
#include "Timer.h"
#include "adc.h"
#include "bsp_rcc.h"
#include "bsp_tim.h"
#include "bsp_uart.h"
#include "delay.h"
#include "do_mqtt.h"
#include "infrared.h"
#include "light.h"
#include "w55mh32_gpio.h"
#include "wiz_interface.h"
#include "wizchip_conf.h"
#include < stdbool.h >
#include < stdint.h >
#include < stdio.h >
#include < stdlib.h >
#include < string.h >
#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
/* network information */
wiz_NetInfo default_net_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 ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};
static uint8_t mqtt_send_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};
static uint8_t mqtt_recv_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};
int main(void) {
/* hardware initialization */
rcc_clk_config();
delay_init();
console_usart_init(115200);
tim3_init();
light_init();
infrared_init();
pwm_init();
timer_init();
ad_init();
printf("%s MQTT OneNET examplern", _WIZCHIP_ID_);
/* wiztoe init */
wiz_toe_init();
wiz_phy_link_check();
network_init(ethernet_buf, &default_net_info);
mqtt_init(SOCKET_ID, mqtt_send_ethernet_buf, mqtt_recv_ethernet_buf);
while (1) {
light_control();
do_mqtt();
}
}
6.2 do_mqtt.c分析
核心代碼功能:通過(guò)MQTT協(xié)議實(shí)現(xiàn)設(shè)備、OneNET云平臺(tái)的雙向交互,包括傳感器數(shù)據(jù)(紅外感應(yīng)、光照、LED燈狀態(tài))上報(bào)及命令下發(fā)。
/**
* @brief 解析JSON格式的控制消息,并根據(jù)消息內(nèi)容控制硬件,最后回復(fù)處理結(jié)果
* @param msg 待解析的JSON格式字符串,包含控制指令(如LED開關(guān)、模式切換等)
* @note 該函數(shù)使用cJSON庫(kù)解析JSON,提取相關(guān)控制參數(shù)后更新全局變量以控制硬件,
* 并通過(guò)MQTT協(xié)議向云平臺(tái)回復(fù)處理結(jié)果
*/
void json_decode(char *msg)
{
int ret; // 函數(shù)返回值,用于判斷MQTT發(fā)布是否成功
char replymsg[128] = {0}; // 存儲(chǔ)回復(fù)云平臺(tái)的JSON格式字符串
cJSON *id = NULL; // 指向JSON中"id"字段的cJSON對(duì)象(消息標(biāo)識(shí))
cJSON *jsondata = NULL; // 指向解析后的根cJSON對(duì)象
cJSON *params = NULL; // 指向JSON中"params"字段的cJSON對(duì)象(參數(shù)集合)
cJSON *LED = NULL; // 指向"params"中"LED"字段(LED開關(guān)控制)
cJSON *Mode_switch = NULL; // 指向"params"中"Mode_switch"字段(模式切換控制)
cJSON *Brightness_set = NULL; // 指向"params"中"Brightness_set"字段(亮度設(shè)置)
cJSON *light_threshold = NULL; // 指向"params"中"light_threshold"字段(光感閾值設(shè)置)
// 解析輸入的JSON字符串,生成cJSON對(duì)象樹
jsondata = cJSON_Parse(msg);
if (jsondata == NULL)
{
printf("json parse fail.rn"); // 解析失?。ㄈ绺袷藉e(cuò)誤),打印錯(cuò)誤信息
return;
}
// 從根對(duì)象中獲取各字段值
id = cJSON_GetObjectItem(jsondata, "id"); // 獲取消息標(biāo)識(shí)"id"
params = cJSON_GetObjectItem(jsondata, "params"); // 獲取參數(shù)集合"params"
LED = cJSON_GetObjectItem(params, "LED"); // 從params中獲取LED控制參數(shù)
Mode_switch = cJSON_GetObjectItem(params, "Mode_switch"); // 獲取模式切換參數(shù)
Brightness_set = cJSON_GetObjectItem(params, "Brightness_set"); // 獲取亮度設(shè)置參數(shù)
light_threshold = cJSON_GetObjectItem(params, "light_threshold"); // 獲取光感閾值參數(shù)
// 根據(jù)LED參數(shù)控制LED開關(guān)(通過(guò)PWM占空比實(shí)現(xiàn))
if (LED != NULL) // 僅當(dāng)JSON中包含"LED"字段時(shí)處理
{
if (LED- >valueint) // LED值為非0(通常1表示開啟)
{
g_pwm_DutyCycle = 20; // 設(shè)置PWM占空比為20(LED開啟,亮度20%)
}
else // LED值為0(表示關(guān)閉)
{
g_pwm_DutyCycle = 0; // PWM占空比設(shè)為0(LED關(guān)閉)
}
}
// 根據(jù)模式切換參數(shù)切換工作模式
if (Mode_switch != NULL) // 僅當(dāng)JSON中包含"Mode_switch"字段時(shí)處理
{
if (Mode_switch- >valueint) // 模式值為非0(通常1表示自動(dòng)模式)
{
g_Modes_witch = 1; // 更新全局模式變量為自動(dòng)模式
}
else // 模式值為0(表示手動(dòng)模式/關(guān)閉自動(dòng))
{
g_Modes_witch = 0; // 更新全局模式變量為手動(dòng)模式
g_pwm_DutyCycle = 0; // 同時(shí)關(guān)閉LED(手動(dòng)模式初始狀態(tài))
}
}
// 根據(jù)亮度設(shè)置參數(shù)調(diào)整LED亮度
if (Brightness_set != NULL) // 僅當(dāng)JSON中包含"Brightness_set"字段時(shí)處理
{
if (Brightness_set- >valueint) // 亮度值有效(非0)
{
g_Brightness_set = Brightness_set- >valueint; // 更新全局亮度設(shè)置變量
g_pwm_DutyCycle = Brightness_set- >valueint; // 直接設(shè)置PWM占空比(控制亮度)
g_Low_bright = Brightness_set- >valueint; // 更新低亮度閾值(可能用于自動(dòng)模式)
}
}
// 根據(jù)光感閾值參數(shù)設(shè)置光感檢測(cè)閾值
if (light_threshold != NULL) // 僅當(dāng)JSON中包含"light_threshold"字段時(shí)處理
{
if (light_threshold- >valueint) // 閾值有效(非0)
{
g_light_thres_low = light_threshold- >valueint; // 更新全局光感低閾值變量
}
}
// 應(yīng)用PWM占空比設(shè)置(硬件層面更新LED亮度)
PWM_SetCompare1(g_pwm_DutyCycle);
// 構(gòu)建回復(fù)云平臺(tái)的JSON消息(包含原消息id和成功狀態(tài))
pubmessage.qos = QOS0; // 設(shè)置MQTT消息的QoS等級(jí)為0(最多一次)
// 格式化回復(fù)消息,包含消息標(biāo)識(shí)id和處理結(jié)果(200表示成功)
sprintf(replymsg, "{"id":"%s","code":200,"msg":"success"}", id- >valuestring);
printf("reply:%srn", replymsg); // 打印回復(fù)消息用于調(diào)試
// 設(shè)置MQTT發(fā)布消息的負(fù)載(內(nèi)容)及長(zhǎng)度
pubmessage.payload = replymsg;
pubmessage.payloadlen = strlen(replymsg);
// 通過(guò)MQTT協(xié)議發(fā)布回復(fù)消息到指定主題
ret = MQTTPublish(&c, mqtt_params.subtopic_reply, &pubmessage);
if (ret != SUCCESSS) // 發(fā)布失敗
{
run_status = MQTT_ERR; // 更新全局運(yùn)行狀態(tài)為MQTT錯(cuò)誤
}
else // 發(fā)布成功
{
// 打印發(fā)布成功的信息(主題和消息內(nèi)容)
printf("publish:%s,%srnrn", mqtt_params.subtopic_reply, (char *)pubmessage.payload);
}
// 釋放cJSON對(duì)象樹,避免內(nèi)存泄漏
cJSON_Delete(jsondata);
}
/**
* @brief 生成包含傳感器數(shù)據(jù)和設(shè)備狀態(tài)的JSON格式字符串
* @param json_buf 用于存儲(chǔ)生成的JSON字符串的緩沖區(qū)
* @param buf_len 緩沖區(qū)的長(zhǎng)度(字節(jié))
* @return 1 - 生成成功;0 - 生成失?。▍?shù)無(wú)效或緩沖區(qū)過(guò)?。? * @note 該函數(shù)將當(dāng)前傳感器數(shù)據(jù)(如光照強(qiáng)度、人體檢測(cè)狀態(tài))和設(shè)備狀態(tài)(如LED開關(guān)、模式等)
* 格式化為JSON字符串,用于上報(bào)到云平臺(tái)或其他系統(tǒng)
*/
static int generate_sensor_json(char *json_buf, uint16_t buf_len)
{
// 參數(shù)校驗(yàn):緩沖區(qū)為空或長(zhǎng)度不足(最小需256字節(jié),確保能容納JSON結(jié)構(gòu))
if (json_buf == NULL || buf_len < 256)
return 0;
sprintf(json_buf,
"{"id":"123","version":"1.0","params":{"
""light":{"value":%d},"
""induct":{"value":%s},"
""LED":{"value":%s},"
""Mode_switch":{"value":%s},"
""light_threshold":{"value":%d},"
""Brightness_set":{"value":%d}"
"}}",
g_light_Intensity, // 光照強(qiáng)度值(全局變量)
g_is_Person_Detected ? "true" : "false", // 人體檢測(cè)狀態(tài)(全局變量)
g_pwm_DutyCycle ? "true" : "false", // LED狀態(tài)(通過(guò)PWM占空比判斷)
g_Modes_witch ? "true" : "false", // 工作模式(全局變量)
g_light_thres_low, // 光感閾值(全局變量)
g_Brightness_set // 亮度設(shè)置(全局變量)
);
return 1; // 生成成功
}
6.3 Infraed.c分析
該文件實(shí)現(xiàn)紅外傳感器的紅外感應(yīng)功能,核心如下:
初始化:配置開發(fā)板的PA3引腳為上拉輸入模式。
數(shù)據(jù)讀?。鹤x取經(jīng)ADC轉(zhuǎn)換濾波之后的數(shù)據(jù)。
功能:實(shí)時(shí)監(jiān)測(cè)是否有人員及車輛經(jīng)過(guò)。
#include "adc.h"
#include "bsp_uart.h"
#include "infrared.h"
#include "w55mh32_gpio.h"
#include "w55mh32_rcc.h"
#include < stdbool.h >
#include < stdio.h >
#include < string.h >
/**
* @brief 初始化紅外傳感器(配置PA3為模擬輸入模式)
* @note 紅外傳感器連接至PA3,復(fù)用為ADC輸入通道3
*/
void infrared_init(void) {
GPIO_InitTypeDef gpio_init_structure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA時(shí)鐘
// 配置PA3為模擬輸入(用于讀取紅外傳感器的模擬信號(hào))
gpio_init_structure.GPIO_Pin = GPIO_Pin_3;
gpio_init_structure.GPIO_Mode = GPIO_Mode_AIN; // 模擬輸入模式
GPIO_Init(GPIOA, &gpio_init_structure);
}
/**
* @brief 獲取紅外傳感器檢測(cè)結(jié)果(基于濾波后的AD值)
* @return 1-檢測(cè)到物體(AD值< 1500),0-未檢測(cè)到物體(AD值≥1500)
* @note 依賴ADC模塊的濾波功能(AD_FilterProcess),需先初始化ADC
*/
uint16_t infrared_get_data(void) {
uint16_t temp_data;
uint16_t temp;
ad_filter_process(); // 執(zhí)行AD濾波,獲取穩(wěn)定值
temp = ad_filtered_value[0]; // 紅外傳感器對(duì)應(yīng)ADC通道0的濾波后值
// 根據(jù)閾值判斷是否檢測(cè)到物體
if (temp < 1500) {
temp_data = 1; // 檢測(cè)到物體
} else {
temp_data = 0; // 未檢測(cè)到物體
}
return temp_data;
}
/**
* @brief 讀取紅外傳感器原始AD值(未經(jīng)過(guò)濾波)
* @return 原始AD采樣值(直接取自ADC原始緩沖區(qū))
*/
uint16_t infrared_read_raw(void) {
return ad_value[0]; // 紅外傳感器對(duì)應(yīng)ADC通道0的原始值
}
6.4 light.c分析
該文件實(shí)現(xiàn)光照傳感器的數(shù)據(jù)采集及燈光處理功能,核心如下:
初始化配置:使能GPIOA,將 PA4配置為模擬輸入模式。
數(shù)據(jù)讀取與轉(zhuǎn)換:函數(shù)讀取經(jīng)ADC轉(zhuǎn)換濾波之后的數(shù)值,通過(guò)取倒數(shù)并乘以500000的方式,轉(zhuǎn)換為一個(gè)與光照強(qiáng)度成正比的浮點(diǎn)數(shù),能為系統(tǒng)提供實(shí)時(shí)光照強(qiáng)度數(shù)據(jù)。
功能實(shí)現(xiàn):自動(dòng)模式下當(dāng)光照強(qiáng)度低于設(shè)定的光照閾值時(shí)自動(dòng)開啟LED照明,初始亮度設(shè)定為20%(初始亮度可通過(guò)網(wǎng)頁(yè)端調(diào)節(jié));當(dāng)紅外傳感器監(jiān)測(cè)到行人或車輛經(jīng)過(guò)時(shí),LED照明亮度提升至100%,人離開后恢復(fù)至20%(10秒后恢復(fù)至低亮度),有效實(shí)現(xiàn)按需照明并避免資源浪費(fèi)。在手動(dòng)控制模式下,網(wǎng)頁(yè)可直接設(shè)置LED的開關(guān)狀態(tài)及亮度。亮度調(diào)節(jié)由網(wǎng)頁(yè)端直接下發(fā)亮度值指令,無(wú)需在設(shè)備端中進(jìn)行額外處理。
#include "PWM.h"
#include "Timer.h"
#include "adc.h"
#include "infrared.h"
#include "light.h"
#include "w55mh32_adc.h"
#include "w55mh32_gpio.h"
#include "w55mh32_rcc.h"
#include < stdbool.h >
#include < stdio.h >
// 燈光控制參數(shù)
#define FULL_BRIGHTNESS 100 // 全亮
#define LIGHT_OFF 0 // 關(guān)閉燈
/**
* 全局變量(加g_前綴,注明功能和取值范圍)
*/
uint16_t g_light_intensity; // 全局光照強(qiáng)度
bool g_is_person_detected = false; // 紅外傳感器檢測(cè)狀態(tài)(true=檢測(cè)到人員)
uint16_t g_pwm_duty_cycle = 0; // PWM占空比(0-100,控制LED亮度)
uint16_t g_mode_switch = 1; // 模式選擇(0=手動(dòng)模式,1=自動(dòng)模式)
extern uint16_t g_low_bright; // 自動(dòng)模式下LED低亮度設(shè)置(0-100)
extern uint16_t g_light_thres_low; // 光照閾值下限(用于自動(dòng)模式判斷)
/**
* 靜態(tài)變量(加s_前綴,注明功能)
*/
static bool s_prev_person_state =
false; // 上一次人體檢測(cè)狀態(tài)(用于狀態(tài)變化判斷)
static bool s_delay_active = false; // 延遲狀態(tài)標(biāo)志(true=處于延遲階段)
static uint32_t s_delay_timer = 0; // 延遲計(jì)時(shí)器(單位:ms,用于10秒延遲邏輯)
/**
* @brief 初始化光照傳感器(配置PA4為模擬輸入模式)
*/
void light_init(void) {
GPIO_InitTypeDef gpio_init_structure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
gpio_init_structure.GPIO_Pin = GPIO_Pin_4;
gpio_init_structure.GPIO_Mode = GPIO_Mode_AIN; // 模擬輸入模式(用于ADC采樣)
GPIO_Init(GPIOA, &gpio_init_structure);
}
/**
* @brief 讀取光照強(qiáng)度(將AD值轉(zhuǎn)換為物理量)
* @return 光照強(qiáng)度值(通過(guò)AD濾波值計(jì)算得到)
*/
float read_light_intensity(void) {
ad_filter_process(); // 獲取濾波后的AD值
uint16_t raw = ad_filtered_value[1]; // 取通道1的濾波后值
if (raw == 0) {
raw = 1; // 避免除零錯(cuò)誤
}
return 500000.0f / (float)raw; // 轉(zhuǎn)換為物理量(公式取決于傳感器特性)
}
/**
* @brief 讀取光照傳感器原始AD值(未濾波)
* @return 原始AD值(通道1的實(shí)時(shí)采樣值)
*/
uint16_t light_read_raw(void) {
return ad_value[1]; // 直接返回通道1的原始AD值
}
/**
* @brief 智能燈光控制邏輯
* @note 自動(dòng)模式邏輯:
* 1. 低光照:
* - 有人→全亮;無(wú)人→延遲10秒后變?yōu)槲⒐?微光亮度可調(diào))
* 2. 高光照→關(guān)燈
* 3. 其他情況→保持當(dāng)前亮度
* 手動(dòng)模式:通過(guò)外部指令直接控制,本函數(shù)不額外處理
*/
void light_control(void) {
g_light_intensity = (int)read_light_intensity(); // 更新光照強(qiáng)度
g_is_person_detected = infrared_get_data(); // 更新人體檢測(cè)狀態(tài)
uint16_t light_thres_high = g_light_thres_low + 50; // 光照閾值上限
if (g_mode_switch) // 自動(dòng)模式
{
// 人離開(從有到無(wú)):激活延遲
if (s_prev_person_state && !g_is_person_detected) {
s_delay_active = true;
s_delay_timer = 10000; // 10秒延遲
}
// 人到來(lái)(從無(wú)到有):取消延遲
if (!s_prev_person_state && g_is_person_detected) {
s_delay_active = false;
}
// 燈光邏輯處理
if (g_light_intensity <= g_light_thres_low) {
if (g_is_person_detected) {
g_pwm_duty_cycle = FULL_BRIGHTNESS; // 有人→全亮
} else if (s_delay_active) {
g_pwm_duty_cycle = FULL_BRIGHTNESS; // 延遲期間→保持全亮
} else {
g_pwm_duty_cycle = g_low_bright; // 延遲結(jié)束→微光
}
} else if (g_light_intensity >= light_thres_high && !g_is_person_detected) {
s_delay_active = false;
g_pwm_duty_cycle = LIGHT_OFF; // 高光照且無(wú)人→關(guān)燈
}
// 其他情況保持當(dāng)前亮度
}
// 手動(dòng)模式:通過(guò)外部指令控制,無(wú)需處理
s_prev_person_state = g_is_person_detected; // 更新上一次狀態(tài)
pwm_set_compare1(g_pwm_duty_cycle); // 應(yīng)用PWM占空比
}
/**
* @brief TIM2中斷服務(wù)函數(shù)(處理延遲計(jì)時(shí))
* @note 每1ms觸發(fā)一次,減少延遲計(jì)時(shí)器,為0時(shí)結(jié)束延遲
*/
void TIM2_IRQHandler(void) {
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {
if (s_delay_active && s_delay_timer > 0) {
s_delay_timer--;
if (s_delay_timer == 0) {
s_delay_active = false; // 延遲結(jié)束
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中斷標(biāo)志
}
}
6.5 PWM.C分析
初始化配置完成之后可通過(guò)pwm_set_compare1函數(shù)動(dòng)態(tài)修改占空比 ,當(dāng)compare=0時(shí),LED完全熄滅;compare=100時(shí),LED最亮。
#include "w55mh32_adc.h"
#include "w55mh32_gpio.h"
#include "w55mh32_rcc.h"
/**
* @brief 初始化PWM模塊(TIM5定時(shí)器+PA0引腳)
* @note 配置步驟:
* 1. 使能TIM5和GPIOA時(shí)鐘
* 2. 配置PA0為復(fù)用推挽輸出(PWM信號(hào)輸出)
* 3. 初始化TIM5:向上計(jì)數(shù),周期100(0-99),分頻2160(生成100kHz時(shí)鐘)
* 4. 配置TIM5通道1為PWM1模式,初始占空比0
* 5. 使能TIM5定時(shí)器
*/
void pwm_init(void) {
// 使能TIM5和GPIOA時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA0為復(fù)用推挽輸出(PWM輸出)
GPIO_InitTypeDef gpio_init_structure;
gpio_init_structure.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_init_structure.GPIO_Pin = GPIO_Pin_0;
gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_init_structure);
// 配置TIM5內(nèi)部時(shí)鐘
TIM_InternalClockConfig(TIM5);
// 初始化TIM5時(shí)基參數(shù)
TIM_TimeBaseInitTypeDef tim_time_base_init_structure;
tim_time_base_init_structure.TIM_ClockDivision = TIM_CKD_DIV1;
tim_time_base_init_structure.TIM_CounterMode = TIM_CounterMode_Up;
tim_time_base_init_structure.TIM_Period = 100 - 1; // 周期100(0-99)
tim_time_base_init_structure.TIM_Prescaler =
2160 - 1; // 分頻2180(216MHz/2160=100kHz)
tim_time_base_init_structure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM5, &tim_time_base_init_structure);
// 配置TIM5通道1為PWM模式
TIM_OCInitTypeDef tim_oc_init_structure;
TIM_OCStructInit(&tim_oc_init_structure); // 初始化默認(rèn)參數(shù)
tim_oc_init_structure.TIM_OCMode =
TIM_OCMode_PWM1; // PWM1模式(計(jì)數(shù)器< 比較值時(shí)輸出有效)
tim_oc_init_structure.TIM_OCPolarity = TIM_OCPolarity_High; // 有效電平為高
tim_oc_init_structure.TIM_OutputState = TIM_OutputState_Enable; // 使能輸出
tim_oc_init_structure.TIM_Pulse = 0; // 初始占空比0
TIM_OC1Init(TIM5, &tim_oc_init_structure);
// 使能TIM5定時(shí)器
TIM_Cmd(TIM5, ENABLE);
}
/**
* @brief 設(shè)置TIM5通道1的PWM占空比
* @param compare:占空比數(shù)值(0-100,對(duì)應(yīng)0%-100%)
* @note 直接修改比較寄存器值,實(shí)時(shí)更新PWM輸出
*/
void pwm_set_compare1(uint16_t compare){
TIM_SetCompare1(TIM5, compare);
}
7 功能驗(yàn)證
程序燒錄完畢,硬件連接完成如下圖

1.硬件連接完畢,上電通過(guò)串口助手打印如下信息:

2.通過(guò)串口每5S采集一次數(shù)據(jù)發(fā)送到云平臺(tái),自動(dòng)模式下當(dāng)我們遮擋光照傳感器時(shí),光照強(qiáng)度數(shù)值越來(lái)越小。當(dāng)光照強(qiáng)度小于設(shè)定閾值時(shí)LED燈點(diǎn)亮。移除遮擋光照強(qiáng)度大于設(shè)定閾值時(shí)LED燈熄滅。手動(dòng)模式下,我們可通過(guò)網(wǎng)頁(yè)端手動(dòng)控制LED燈的開關(guān)狀態(tài)及亮度。
3.自動(dòng)模式下當(dāng)光照強(qiáng)度低于設(shè)定的光照閾值時(shí),LED 燈自動(dòng)點(diǎn)亮。此時(shí)紅外傳感器檢測(cè)到遮擋信號(hào)后,LED 燈亮度提升至 100%;移除遮擋后,系統(tǒng) 10 秒后恢復(fù)亮度至低亮模式,該模式下 LED 燈亮度可通過(guò)網(wǎng)頁(yè)端調(diào)節(jié)。
完整演示視頻鏈接:[https://www.bilibili.com/video/BV1gJtqzVEtD]
8 總結(jié)
本系統(tǒng)以 W55MH32Q 開發(fā)板為核心控制中樞,集成紅外傳感器、光照傳感器及 LED 照明模塊,通過(guò) MQTT 協(xié)議與 OneNET 云平臺(tái)構(gòu)建完整物聯(lián)網(wǎng)通信鏈路,最終實(shí)現(xiàn)了動(dòng)態(tài)模式切換、遠(yuǎn)程控制的智能LED燈控制系統(tǒng)。后續(xù)將會(huì)依據(jù)W55MH32Q芯片制作智能路燈系統(tǒng)的PCB板及其公模外殼,制作完成后我會(huì)繼續(xù)更新,希望大家捧場(chǎng),同時(shí)感謝大家閱讀,如果有疑問(wèn)可以在評(píng)論區(qū)留言,我會(huì)進(jìn)行解答,為你的開發(fā)提供幫助。
審核編輯 黃宇
-
開源
+關(guān)注
關(guān)注
3文章
4151瀏覽量
45824 -
智能路燈
+關(guān)注
關(guān)注
7文章
107瀏覽量
23542 -
OneNET
+關(guān)注
關(guān)注
1文章
53瀏覽量
13878
發(fā)布評(píng)論請(qǐng)先 登錄
單片機(jī)軟硬件聯(lián)合仿真解決方案
基于SoPC的狀態(tài)監(jiān)測(cè)裝置的嵌入式軟硬件協(xié)同設(shè)計(jì)
【OneNET麒麟座試用申請(qǐng)】基于OneNET平臺(tái)的智慧照明控制系統(tǒng)
機(jī)友分享 | 機(jī)智云小程序啟蒙:WebSocket網(wǎng)頁(yè)控制
基于onenet云平臺(tái)MQTT協(xié)議數(shù)據(jù)采集以及遠(yuǎn)程控制的個(gè)人總結(jié)資料
詳細(xì)分析stm32f10x.h
請(qǐng)問(wèn)一下怎樣對(duì)stm32的啟動(dòng)代碼進(jìn)行詳細(xì)分析呢
OpenHarmony輕量系統(tǒng)開發(fā)【12】OneNET云接入
如何對(duì)SOA進(jìn)行軟硬件部署
單片機(jī)測(cè)控系統(tǒng)的軟硬件平臺(tái)技術(shù)
智能家居系統(tǒng)的軟硬件設(shè)計(jì)
機(jī)房托管費(fèi)詳細(xì)分析
智能農(nóng)業(yè)監(jiān)控系統(tǒng):MQTT阿里云平臺(tái)監(jiān)測(cè)+內(nèi)置Web網(wǎng)頁(yè)控制+代碼解析
軟硬件開源項(xiàng)目-智能路燈系統(tǒng):OneNET云平臺(tái)監(jiān)測(cè)+Web網(wǎng)頁(yè)控制+代碼詳細(xì)分析
評(píng)論