1. 项目概述
这个智能台灯项目源于一个常见的家庭痛点——我们经常忘记关台灯。作为一名电子工程师,我曾在凌晨三点被书桌上亮着的台灯惊醒,这种经历促使我思考如何用技术解决这个问题。传统声控方案在家庭环境中并不理想,邻居家的狗叫声、楼下的汽车鸣笛都可能误触发开关。而基于STM32单片机设计的这款智能台灯,通过热释电红外传感器(PIR)检测人体存在,配合环境光传感器实现智能调光,从根本上解决了误触发和能源浪费问题。
核心功能设计上,这台灯实现了三重智能控制:首先通过HC-SR501人体红外模块检测使用者存在状态,其次利用光敏电阻实时监测环境光照强度,最后通过PWM脉宽调制技术无级调节LED亮度。特别加入的坐姿检测功能,当使用者头部距离桌面小于30cm时会触发蜂鸣器提醒,这对预防青少年近视非常有实用价值。整个系统采用模块化设计,主控使用性价比极高的STM32F103C8T6,外围电路包含OLED显示屏、DS1302时钟模块和按键控制,构建了一个完整的嵌入式应用实例。
2. 硬件系统设计
2.1 核心控制器选型
选择STM32F103C8T6作为主控芯片主要基于三点考量:首先,这款Cortex-M3内核的MCU具有72MHz主频和20KB RAM,完全满足实时处理多传感器数据的需求;其次,芯片内置12位ADC和高级定时器,可直接用于光敏电阻采样和PWM生成,无需外接专用芯片;最后,其丰富的GPIO口(37个I/O)为外围设备连接提供了充足接口。实际测试中,即使在同时处理红外传感、AD转换和OLED刷新时,CPU负载仍能保持在60%以下。
提示:对于初次接触STM32的开发者,建议使用STM32CubeMX工具进行引脚分配和初始化代码生成,可避免硬件冲突并大幅缩短开发周期。
2.2 传感器模块详解
人体检测采用HC-SR501热释电红外传感器,其核心元件是双元探头BISS0001。这个模块有三个关键参数需要特别注意:探测距离(本设计设置为3米可调)、延时时间(调整为10秒)和触发方式(选择可重复触发模式)。模块输出高电平信号时,会伴随一个约0.3-2秒的脉冲,这个信号通过PC13引脚接入STM32的外部中断接口。
光照检测使用GL5528光敏电阻配合10kΩ分压电阻构成简单电压 divider电路。实测表明,在室内灯光下(约300lux)输出电压为1.8V,完全黑暗时为3.3V,日光环境下(>1000lux)降至0.5V以下。这个模拟信号连接到PA0引脚,通过STM32内置ADC1通道0进行采样,采样速率设置为1kHz。
2.3 调光电路设计
LED驱动采用MOSFET(IRLZ44N)作为开关元件,由TIM3_CH1(PB4)产生PWM信号控制。PWM频率设置为1kHz(周期=1ms),这个频率既高于人眼可察觉的闪烁范围(>200Hz),又不会导致MOSFET过热。亮度调节分为256级,对应占空比从0%-100%。实际测试显示,当占空比低于5%时LED会出现明显闪烁,因此程序中设置了最小亮度阈值。
坐姿检测使用E18-D80NK红外光电开关,安装在灯罩下方30cm处。当检测到障碍物时输出低电平,通过PC14引脚触发中断。这个距离经过多次验证,能有效区分正常坐姿(>40cm)和低头状态(<30cm)。
3. 软件架构实现
3.1 主程序流程图
系统上电后首先初始化各硬件模块:配置RCC时钟树、GPIO端口、ADC模块、定时器和中断控制器。然后进入主循环,依次执行以下任务:
- 读取ADC值并计算环境光照强度
- 检测红外传感器状态
- 刷新OLED显示
- 检查按键输入
- 处理定时提醒功能
c复制while(1) {
light_level = ADC_GetValue() / 40; // 将0-4095转换为0-100
if(PIR_Detected() && light_level < 50) {
PWM_SetDuty(100 - light_level * 2); // 自动调光算法
}
OLED_Refresh();
Key_Scan();
Check_Reminder();
}
3.2 关键算法解析
自动调光采用动态补偿算法:当环境光强为L(0-100)时,PWM占空比D=100-L×K,其中K为补偿系数(本设计取2)。这意味着在完全黑暗环境(L=0)时灯光明亮(D=100%),在较亮环境(L=50)时灯光减半(D=0%),实现舒适阅读光照。
坐姿检测使用状态机机制:当光电开关持续触发超过500ms(通过定时器计数)才确认为不良坐姿,避免瞬时动作误报。触发后蜂鸣器以2kHz频率鸣响,直到坐姿恢复正常或手动按键关闭。
c复制// 坐姿检测状态机
typedef enum {
POSTURE_NORMAL,
POSTURE_WARNING,
POSTURE_ALERT
} PostureState;
PostureState currentState = POSTURE_NORMAL;
uint32_t alertTimer = 0;
void Posture_Handler(void) {
switch(currentState) {
case POSTURE_NORMAL:
if(PhotoInterrupt_Read() == 0) {
alertTimer = HAL_GetTick();
currentState = POSTURE_WARNING;
}
break;
case POSTURE_WARNING:
if(HAL_GetTick() - alertTimer > 500) {
Buzzer_On(2000);
currentState = POSTURE_ALERT;
}
break;
case POSTURE_ALERT:
if(PhotoInterrupt_Read() == 1) {
Buzzer_Off();
currentState = POSTURE_NORMAL;
}
break;
}
}
3.3 中断处理设计
系统配置了三个关键中断:
- 外部中断(PC13):响应人体红外传感器的上升沿触发,立即唤醒处于低功耗模式的MCU
- 定时器中断(TIM2):每1ms产生一次,用于PWM占空比更新和计时
- ADC中断:完成光照采样后触发,进行数字滤波处理
中断优先级设置为:外部中断 > 定时器中断 > ADC中断,确保人体检测的实时性。在中断服务例程中,仅设置标志位,具体处理放在主循环中执行,避免长时间占用中断。
4. 制作与调试要点
4.1 PCB布局建议
电源部分应远离模拟信号线路,特别是光敏电阻的走线要尽量短,必要时增加屏蔽层。我的第一版设计中将5V电源线与ADC走线平行布置,导致光照读数有约10%的波动。改进后采用星型接地布局,噪声明显降低。
OLED显示屏建议通过4线SPI接口连接而非I2C,虽然多用两个IO口,但刷新率可从30fps提升到60fps,显示效果更流畅。实测显示SPI模式下整屏刷新仅需2ms,而I2C需要15ms。
4.2 常见问题排查
问题1:人体检测响应延迟
- 检查HC-SR501的延时调节电位器,应顺时针旋转减小延时
- 确认STM32外部中断配置为上升沿触发
- 测量传感器供电电压,低于4.5V会导致灵敏度下降
问题2:PWM调光出现闪烁
- 用示波器检查PWM频率,确保稳定在1kHz
- MOSFET栅极串联10Ω电阻消除振荡
- LED串连的限流电阻功率需足够(建议1W以上)
问题3:坐姿检测误触发
- 调整光电开关灵敏度电位器
- 在软件中增加去抖动延时(建议50-100ms)
- 检查安装角度,确保只检测垂直方向
4.3 性能优化技巧
-
低功耗设计:当无人状态持续5分钟后,STM32进入STOP模式,电流从25mA降至150μA。通过红外传感器的输出信号唤醒,响应时间在20ms内,用户无感知。
-
ADC采样优化:采用过采样技术,将12位ADC提升到14位有效分辨率。具体实现是对同一通道连续采样16次取平均,使光照检测更精确。
-
温度补偿:在ADC采样时同时读取芯片内部温度传感器值,对光敏电阻的温漂进行补偿。实测显示,温度每升高10℃,GL5528阻值下降约5%。
5. 功能扩展方向
现有系统可通过以下方式升级:
- 增加Wi-Fi模块(ESP-01S),实现手机APP控制
- 接入语音识别模块(LD3320),支持声控指令
- 添加环境温湿度检测(SHT30),用于舒适度评估
- 升级为RGB LED,实现色温可调
一个实用的改进是在灯座集成USB充电接口,利用STM32的USB OTG功能。我在原型机上测试时,通过修改CubeMX配置,成功实现了5V/1A的充电输出,这对桌面设备非常实用。
电源管理方面,可以考虑改用锂电池供电,配合TP4056充电管理芯片和升压电路。实测显示,2000mAh电池在典型使用场景下可续航约72小时,适合作为应急台灯使用。