基于STM32 Nucleo-L476RG的智能灯设计(纯CubeMX开发)
一、系统概述与核心功能
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
- Project Name:
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)
#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)
#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 光敏电阻采样与环境光计算
// 读取光敏电阻值并计算环境光强度
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 自动模式亮度调节
// 自动模式:根据环境光调节亮度
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中断处理
// 按钮中断回调
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 低功耗管理
// 进入低功耗模式
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 主函数逻辑
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/contentcnt/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自动生成初始化代码,专注应用逻辑开发
应用场景:
- 智能家居夜灯、走廊灯
- 书桌护眼灯、阅读灯
- 仓库/车库人体感应灯
- 教学实验平台、创客项目