深夜起床开灯太刺眼?传统小夜灯要么太亮要么太暗?今天我们用STM32F103C8T6(俗称"蓝莓派")搭配BH1750光照传感器,教你做一个会思考的智能夜灯。这个不到50元的小项目,不仅能自动适应环境光线,还能通过PWM实现亮度无级调节,比市面大多数成品灯更懂你的需求。
智能照明系统的核心在于"感知-决策-执行"闭环。我们的光感小夜灯工作流程如下:
硬件选型考量:
提示:GY-302模块已集成上拉电阻,直接连接STM32即可,无需额外电路
| 模块 | STM32引脚 | 说明 | 备注 |
|---|---|---|---|
| BH1750 SCL | PB6 | I2C1时钟线 | 需配置为开漏输出 |
| BH1750 SDA | PB7 | I2C1数据线 | 需配置为开漏输出 |
| LED+ | PA6 | TIM3_CH1 PWM输出 | 接MOS管栅极 |
| LED- | GND | 灯带负极 | 建议加100Ω限流电阻 |
PWM驱动电路:
cpp复制// MOSFET选型建议:
// - 逻辑电平MOS(如IRLZ44N)
// - Vgs(th) < 3V
// - Id > 1A(根据灯带功率调整)
[LED+] ----[MOS管 Drain]
|
[Gate] ----| PA6
|
[Source] --[GND]
电源方案:
注意:长距离连接传感器时,建议在SCL/SDA线上加100nF电容滤波
mermaid复制graph TD
A[系统初始化] --> B[外设初始化]
B --> C[BH1750连续测量模式]
C --> D{光照数据就绪?}
D -- 是 --> E[读取并滤波]
E --> F[计算PWM占空比]
F --> G[更新TIM3->CCR1]
G --> C
D -- 否 --> C
光照数据采集(I2C版本):
c复制// bh1750.c
#define BH1750_ADDR 0x23 << 1 // 7位地址左移1位
uint16_t BH1750_ReadLux(void) {
uint8_t data[2];
HAL_I2C_Master_Receive(&hi2c1, BH1750_ADDR|0x01, data, 2, 100);
return (data[0]<<8)|data[1];
}
PWM动态调节算法:
c复制// pwm_controller.c
void Update_PWM_Duty(uint16_t lux) {
// 非线性映射:低光区更敏感
uint16_t duty = 0;
if(lux < 10) duty = 1000; // 最大亮度
else if(lux < 50) duty = 800 - (lux*10);
else if(lux < 100) duty = 300 - (lux-50)*2;
else duty = 0; // 环境足够亮时关闭
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
}
主循环逻辑优化:
c复制// main.c
while(1) {
static uint32_t last_tick = 0;
if(HAL_GetTick() - last_tick >= 200) { // 200ms采样周期
uint16_t lux = SmoothFilter(BH1750_ReadLux()); // 滑动平均滤波
Update_PWM_Duty(lux);
last_tick = HAL_GetTick();
}
HAL_Delay(10); // 降低CPU占用
}
通过修改映射算法,可以实现不同的调光风格:
c复制// 示例:S形曲线过渡(更平滑)
float Sigmoid_Map(uint16_t lux) {
float x = (lux - 30) / 20.0; // 中心点在30lx
return 1000 / (1 + expf(x)); // 1000为PWM最大值
}
当检测到环境光持续超过阈值时,可进入STOP模式:
c复制void Enter_LowPower_Mode(void) {
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
HAL_I2C_DeInit(&hi2c1);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
SystemClock_Config(); // 唤醒后需重新配置时钟
}
问题1:I2C通信失败
问题2:PWM输出不稳定
cpp复制// 定时器配置关键参数:
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71; // 72MHz/72 = 1MHz
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 999; // 1MHz/1000 = 1kHz PWM
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
问题3:光照响应迟滞
这个项目最让我惊喜的是PWM调光时的细腻过渡——当你在黑暗房间慢慢拉开窗帘,能看到LED灯带如同有生命般逐渐暗淡,整个过程没有跳变和闪烁。建议用WS2812灯带替代普通LED,通过PWM控制颜色温度,会获得更舒适的夜间体验。