一、系统概述与核心功能
1. 系统定位
基于STM32 Nucleo-L476RG开发板的智能灯系统,充分利用板载资源(LED、按钮、Arduino接口)和CubeMX图形化配置工具,实现一款低成本、低功耗、可扩展的智能照明系统。系统支持PWM调光、呼吸灯效、环境光自适应、人体感应等功能,通过板载按钮和扩展传感器实现智能控制。
2. 核心功能模块
| 模块 |
功能描述 |
技术指标 |
| 主控核心 |
STM32L476RG(Nucleo-L476RG),80MHz Cortex-M4,超低功耗,1MB Flash |
动态功耗<100μA/MHz |
| 灯光控制 |
板载绿色LED(LD2)PWM调光,支持0-100%亮度调节 |
PWM频率1kHz,分辨率12位 |
| 人机交互 |
板载蓝色用户按钮(B1)切换模式,LD2状态指示 |
按钮支持短按/长按识别 |
| 环境感知 |
扩展光敏电阻(Arduino A0)检测环境光,自动调节亮度 |
光敏电阻10kΩ,ADC 12位采样 |
| 人体感应 |
扩展HC-SR501 PIR传感器,实现人来灯亮、人走灯灭 |
探测距离7m,延时可调 |
| 低功耗设计 |
无操作时进入STOP2模式,功耗<5μA,按钮中断唤醒 |
电池供电续航>30天 |
二、硬件设计方案
1. Nucleo-L476RG资源分配
| 外设 |
引脚 |
功能 |
CubeMX配置 |
| LED_LD2 |
PA5 |
板载绿色LED,PWM调光 |
TIM2_CH1,Alternate Function |
| 按钮_B1 |
PC13 |
用户按钮,模式切换 |
GPIO_Input,Pull-up |
| 光敏电阻 |
PA0 (A0) |
环境光检测 |
ADC1_IN5,Analog mode |
| PIR传感器 |
PA1 (A1) |
人体感应输入 |
GPIO_Input,External Interrupt |
| PWM输出 |
PA6 (D12) |
扩展LED调光输出 |
TIM3_CH1,Alternate Function |
| I2C接口 |
PB8/PB9 |
扩展OLED显示 |
I2C1,Standard mode |
| UART通信 |
PA2/PA3 |
串口调试/蓝牙控制 |
USART2,Asynchronous |
2. 扩展电路设计
复制代码
Nucleo-L476RG Arduino接口:
┌─────────────────────────────┐
│ A0 (PA0) ──[光敏电阻]── GND │ 环境光检测
│ A1 (PA1) ──[PIR OUT]────── │ 人体感应输入
│ D12 (PA6) ─[220Ω]──[LED+] │ 扩展LED调光
│ D13 (PA5) ──[板载LED]──── │ 板载LED控制
│ 5V ────────[PIR VCC]───── │ PIR供电
│ 3.3V ──────[OLED VCC]──── │ OLED供电
└─────────────────────────────┘
3. 电源与低功耗设计
- 电源选择:USB供电(5V)或锂电池(3.7V)→ LDO稳压至3.3V
- 低功耗策略:无操作时进入STOP2模式,按钮/PIR中断唤醒
- 外设电源管理:不使用时关闭OLED、PIR传感器电源
三、CubeMX配置步骤
1. 工程创建与MCU选择
- 打开CubeMX → File → New Project → 搜索 Nucleo-L476RG
- Project Manager 选项卡:
- Project Name:
Nucleo_SmartLight
- Toolchain/IDE:
STM32CubeIDE
- 勾选 Generate peripheral initialization as a pair of .c/.h files per peripheral
2. 时钟树配置(Clock Configuration)
- HSE :选择
Crystal/Ceramic Resonator(Nucleo板载8MHz晶振)
- PLL Source Mux :
HSE
- PLLMul :
x20(8MHz × 20 = 160MHz)
- System Clock Mux :
PLLCLK
- SYSCLK:80MHz(分频器设置)
- APB1/APB2 Prescaler :
/1(80MHz)
3. 外设参数配置(Pinout & Configuration)
3.1 TIM2 PWM配置(板载LED调光)
| 参数 |
设置值 |
说明 |
| TIM2 Mode |
PWM Generation CH1 |
PA5 = TIM2_CH1 |
| Prescaler (PSC) |
79 |
80MHz/(79+1)=1MHz |
| Counter Period (ARR) |
999 |
PWM周期1ms,频率1kHz |
| Pulse (CCR1) |
0 |
初始占空比0% |
| CH Polarity |
High |
高电平LED亮 |
3.2 ADC配置(光敏电阻)
| 参数 |
设置值 |
说明 |
| ADC1 Mode |
Independent mode |
独立模式 |
| Resolution |
12-bit |
12位分辨率 |
| Scan Conversion Mode |
Disabled |
单次转换 |
| Continuous Conversion Mode |
Enabled |
连续转换 |
| Sampling Time |
15 Cycles |
采样时间 |
3.3 GPIO配置
| 引脚 |
模式 |
Pull-up/Pull-down |
Label |
| PC13 |
Input mode |
Pull-up |
USER_BUTTON |
| PA1 |
Input mode |
No pull-up/pull-down |
PIR_INPUT |
| PB8/PB9 |
Alternate Function |
Open-drain |
I2C1_SCL/SDA |
3.4 中断配置
| 中断源 |
优先级 |
触发方式 |
| EXTI Line[1] (PA1) |
Priority 1 |
Rising edge |
| EXTI Line[13] (PC13) |
Priority 2 |
Falling edge |
4. 低功耗配置
- RCC:禁用HSE和LSI,使用HSI16(16MHz内部RC)
- PWR:启用Ultra-low-power mode,选择STOP2模式
- GPIO:未使用的引脚设置为Analog mode(最低功耗)
四、软件设计与核心代码
1. 系统架构(前后台系统)
- 后台中断 :
- EXTI1_IRQHandler:PIR传感器中断,唤醒系统并开启灯光
- EXTI15_10_IRQHandler:用户按钮中断,切换工作模式
- TIM2_IRQHandler:PWM更新中断,实现呼吸灯效果
- 前台主循环 :
- 读取光敏电阻值,计算环境光强度
- 根据模式和光照自动调节LED亮度
- 无操作时进入低功耗模式
2. 核心代码实现(基于HAL库)
2.1 系统状态定义(main.h)
c
复制代码
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32l4xx_hal.h"
// 工作模式定义
typedef enum {
MODE_OFF = 0, // 关闭
MODE_ON, // 常亮
MODE_BREATH, // 呼吸灯
MODE_AUTO, // 自动感光
MODE_PIR // 人体感应
} WorkMode_t;
// 系统状态结构体
typedef struct {
WorkMode_t current_mode; // 当前模式
uint8_t brightness; // 亮度值(0-100)
uint8_t target_brightness; // 目标亮度
uint8_t ambient_light; // 环境光强度(0-100)
uint8_t pir_detected; // PIR检测标志
uint32_t last_activity; // 最后活动时间
} SystemState_t;
extern SystemState_t sys_state;
#endif
2.2 PWM调光控制(main.c)
c
复制代码
#include "main.h"
SystemState_t sys_state = {
.current_mode = MODE_OFF,
.brightness = 0,
.target_brightness = 0,
.ambient_light = 50,
.pir_detected = 0,
.last_activity = 0
};
// 设置LED亮度(0-100%)
void Set_LED_Brightness(uint8_t brightness) {
if (brightness > 100) brightness = 100;
// 计算PWM占空比(ARR=999,对应0-100%)
uint32_t pulse = (brightness * 999) / 100;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pulse);
sys_state.brightness = brightness;
}
// 呼吸灯效果(在TIM2中断中调用)
void Breath_Effect(void) {
static uint8_t breath_dir = 0; // 0=渐亮,1=渐暗
static uint8_t current_brightness = 0;
if (breath_dir == 0) {
current_brightness++;
if (current_brightness >= 100) {
breath_dir = 1;
}
} else {
current_brightness--;
if (current_brightness == 0) {
breath_dir = 0;
}
}
Set_LED_Brightness(current_brightness);
}
// TIM2中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
if (sys_state.current_mode == MODE_BREATH) {
Breath_Effect();
}
}
}
2.3 光敏电阻采样与环境光计算
c
复制代码
// 读取光敏电阻值并计算环境光强度
void Update_Ambient_Light(void) {
uint32_t adc_value;
uint8_t light_intensity;
// 启动ADC转换
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) {
adc_value = HAL_ADC_GetValue(&hadc1);
// 转换为百分比(光敏电阻:光照越强,电阻越小,ADC值越小)
// 假设:黑暗时ADC≈4000,强光时ADC≈500
if (adc_value > 4000) adc_value = 4000;
if (adc_value < 500) adc_value = 500;
light_intensity = 100 - ((adc_value - 500) * 100) / 3500;
sys_state.ambient_light = light_intensity;
}
HAL_ADC_Stop(&hadc1);
}
2.4 自动模式亮度调节
c
复制代码
// 自动模式:根据环境光调节亮度
void Auto_Brightness_Control(void) {
uint8_t target_brightness;
// 环境光越暗,LED亮度越高
if (sys_state.ambient_light < 20) {
target_brightness = 100; // 黑暗环境,全亮
} else if (sys_state.ambient_light < 50) {
target_brightness = 70; // 较暗环境,70%亮度
} else if (sys_state.ambient_light < 80) {
target_brightness = 40; // 中等光照,40%亮度
} else {
target_brightness = 10; // 明亮环境,10%亮度
}
// 平滑过渡
if (sys_state.brightness < target_brightness) {
sys_state.brightness++;
} else if (sys_state.brightness > target_brightness) {
sys_state.brightness--;
}
Set_LED_Brightness(sys_state.brightness);
}
2.5 按钮与PIR中断处理
c
复制代码
// 按钮中断回调
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) { // 用户按钮PC13
sys_state.last_activity = HAL_GetTick();
// 切换模式
sys_state.current_mode = (sys_state.current_mode + 1) % 5;
// 模式切换反馈
for (int i = 0; i <= sys_state.current_mode; i++) {
Set_LED_Brightness(100);
HAL_Delay(100);
Set_LED_Brightness(0);
HAL_Delay(100);
}
}
if (GPIO_Pin == GPIO_PIN_1) { // PIR传感器PA1
sys_state.pir_detected = 1;
sys_state.last_activity = HAL_GetTick();
if (sys_state.current_mode == MODE_PIR) {
Set_LED_Brightness(100); // 检测到人体,全亮
}
}
}
2.6 低功耗管理
c
复制代码
// 进入低功耗模式
void Enter_LowPower_Mode(void) {
// 关闭不必要的外设
__HAL_TIM_DISABLE(&htim2);
HAL_ADC_Stop(&hadc1);
// 配置所有GPIO为模拟模式(最低功耗)
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
// 进入STOP2模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新配置系统时钟
SystemClock_Config();
MX_TIM2_Init();
MX_ADC1_Init();
}
2.7 主函数逻辑
c
复制代码
int main(void) {
HAL_Init();
SystemClock_Config();
// CubeMX生成的初始化
MX_GPIO_Init();
MX_TIM2_Init();
MX_ADC1_Init();
MX_I2C1_Init();
// 启动PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
// 初始化OLED显示(如果连接)
OLED_Init();
OLED_ShowString(0, 0, "Smart Light");
OLED_ShowString(0, 2, "Mode: OFF");
while (1) {
// 更新环境光数据
Update_Ambient_Light();
// 根据当前模式执行相应控制
switch (sys_state.current_mode) {
case MODE_OFF:
Set_LED_Brightness(0);
break;
case MODE_ON:
Set_LED_Brightness(80); // 常亮80%
break;
case MODE_BREATH:
// 呼吸灯效果在TIM2中断中处理
break;
case MODE_AUTO:
Auto_Brightness_Control();
break;
case MODE_PIR:
if (sys_state.pir_detected) {
// 检测到人体,保持亮灯30秒
if (HAL_GetTick() - sys_state.last_activity > 30000) {
sys_state.pir_detected = 0;
Set_LED_Brightness(0);
}
}
break;
}
// 更新OLED显示
char display_str[20];
sprintf(display_str, "Mode: %d", sys_state.current_mode);
OLED_ShowString(0, 2, display_str);
sprintf(display_str, "Light: %d%%", sys_state.brightness);
OLED_ShowString(0, 4, display_str);
sprintf(display_str, "Ambient: %d%%", sys_state.ambient_light);
OLED_ShowString(0, 6, display_str);
// 检查是否需要进入低功耗模式
if (HAL_GetTick() - sys_state.last_activity > 60000) { // 1分钟无活动
OLED_Clear();
Enter_LowPower_Mode();
sys_state.last_activity = HAL_GetTick(); // 唤醒后重置活动时间
}
HAL_Delay(100); // 100ms主循环
}
}
参考代码 基于stm32 nucleo_L476的智能灯(操作说明+源码) www.youwenfan.com/contentcst/123463.html
五、系统调试与扩展
1. 调试步骤
| 阶段 |
操作 |
工具 |
预期结果 |
| 硬件检查 |
测量3.3V供电,检查LED是否正常点亮 |
万用表 |
电压稳定在3.3V |
| PWM验证 |
用示波器观察PA5引脚波形 |
示波器 |
1kHz PWM,占空比可调 |
| 按钮测试 |
短按/长按按钮,观察LED反馈 |
肉眼观察 |
模式正确切换 |
| 光敏测试 |
用手遮挡/移开,观察亮度变化 |
OLED显示 |
亮度随环境光变化 |
| 低功耗测试 |
测量STOP模式电流消耗 |
万用表(串联) |
电流<10μA |
2. 扩展功能(CubeMX新增配置)
| 扩展功能 |
CubeMX配置 |
实现效果 |
| OLED显示 |
I2C1启用,PB8/PB9 |
实时显示模式、亮度、环境光 |
| 蓝牙控制 |
USART1启用,PA9/PA10 |
手机APP远程控制开关/调光 |
| 温湿度监测 |
I2C1添加SHT30 |
显示环境温湿度信息 |
| 多LED控制 |
TIM3_CH2/3/4启用 |
RGB全彩灯光效果 |
3. 性能优化建议
- PWM频率优化:将PWM频率提高到20kHz以上,避免LED可见闪烁
- ADC采样优化:使用DMA传输ADC数据,减少CPU干预
- 低功耗优化:使用RTC定时唤醒,实现定时开关灯功能
- 抗干扰优化:在光敏电阻电路中加入RC滤波,减少环境光波动影响
六、总结
基于STM32 Nucleo-L476RG的智能灯系统充分利用了CubeMX图形化配置的优势,实现了从简单到复杂的智能照明功能。系统具有以下特点:
核心优势:
- 低成本:利用Nucleo板载资源,无需额外购买主控板
- 低功耗:STOP2模式下功耗<5μA,电池供电可使用数月
- 易扩展:Arduino接口方便添加各种传感器模块
- 开发快捷:CubeMX自动生成初始化代码,专注应用逻辑开发
应用场景:
- 智能家居夜灯、走廊灯
- 书桌护眼灯、阅读灯
- 仓库/车库人体感应灯
- 教学实验平台、创客项目