1. 项目概述
这个智能台灯控制系统是我去年为一个创客空间设计的教学项目,核心目标是让学员通过STM32F103这款经典MCU掌握嵌入式开发全流程。不同于普通台灯,我们实现了亮度记忆、人体感应、环境光自适应三大核心功能,整套硬件成本控制在50元以内,特别适合作为电子类专业学生的毕业设计选题。
在实际教学中发现,很多初学者容易卡在PWM调光算法、传感器数据融合这些关键环节。本文将详细拆解从电路设计到代码实现的完整过程,重点分享我在调试过程中总结的"寄存器操作避坑指南"和"低功耗优化技巧"。这个项目虽然看着简单,但完整做下来能掌握STM32的GPIO、ADC、定时器、中断等核心外设的实战用法。
2. 硬件设计详解
2.1 核心器件选型
主控选择STM32F103C8T6最小系统板(俗称"蓝莓板"),主要考虑:
- 内置3个通用定时器,满足PWM调光需求
- 12位ADC可精准采集光敏电阻值
- 价格仅8-10元,烧写不心疼
传感器部分采用模块化设计:
- 人体感应:HC-SR501红外模块(注意要选可重复触发版本)
- 环境光检测:GL5528光敏电阻+10kΩ分压电阻
- 亮度调节:5mm暖光LED灯珠(3.3V/20mA)配合S8050三极管驱动
关键经验:LED驱动一定要加基极限流电阻!我第一批样板就因直接连接IO口烧毁了3个MCU引脚。
2.2 电路设计要点
原理图设计特别注意三点:
- 光敏电阻分压电路要并联104电容滤除高频干扰
- PWM驱动电路采用共射极接法,β值取100时基极电阻计算公式:
code复制Rb = (Vio - Vbe) × β / Iled = (3.3V - 0.7V) × 100 / 20mA = 13kΩ (实际选用10kΩ+2.2kΩ串联) - 所有数字信号线串联100Ω电阻抑制振铃
PCB布局遵循"传感器-主控-驱动"分区原则,光敏电阻要远离LED光源避免干扰。实测证明,当两者距离小于3cm时环境光检测误差会超过30%。
3. 软件实现关键
3.1 开发环境搭建
使用Keil MDK+ST-Link V2调试器,需要特别注意:
- 在Options for Target→Target选项卡中设置正确的晶振频率(8MHz)
- 勾选"Use MicroLIB"以减小代码体积
- 在Debug选项卡启用"Reset and Run"避免每次手动复位
推荐安装STMCubeMX生成初始化代码,但不要完全依赖它生成的应用层代码。我遇到过Cube生成的PWM初始化代码占空比计算有误的情况。
3.2 核心算法实现
自适应调光算法采用PID控制:
c复制#define KP 0.8
#define KI 0.2
#define KD 0.1
uint16_t AutoBrightness(uint16_t target_lux) {
static float err_sum = 0, last_err = 0;
float err = target_lux - GetCurrentLux();
err_sum += err;
float output = KP*err + KI*err_sum + KD*(err-last_err);
last_err = err;
return (uint16_t)constrain(output, 0, 1000); // PWM范围0-1000
}
人体感应逻辑采用状态机设计:
c复制typedef enum {
STATE_OFF,
STATE_TURNING_ON,
STATE_ON,
STATE_TURNING_OFF
} LampState;
void HandlePIR() {
static uint32_t off_timer = 0;
switch(current_state) {
case STATE_OFF:
if(PIR_Detected()) {
SetBrightness(last_brightness);
current_state = STATE_TURNING_ON;
}
break;
case STATE_ON:
if(!PIR_Detected()) {
off_timer = HAL_GetTick();
current_state = STATE_TURNING_OFF;
}
break;
// 其他状态处理省略...
}
}
4. 调试经验实录
4.1 PWM调光常见问题
问题现象:LED出现肉眼可见的闪烁
- 检查点1:PWM频率是否低于100Hz(建议200-1kHz)
- 检查点2:定时器时钟分频配置是否正确
- 检查点3:GPIO是否配置为复用推挽输出
问题现象:亮度调节非线性
- 解决方案:采用gamma校正表,实测效果:
code复制原始PWM值 | 校正后值 --------|--------- 100 | 12 200 | 46 500 | 180 800 | 510
4.2 低功耗优化技巧
-
在无人状态时:
- 关闭ADC时钟
- 将系统时钟降至8MHz
- 设置GPIO为模拟输入模式
-
使用停机模式+RTC唤醒:
c复制HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后需要重新初始化时钟 SystemClock_Config(); -
实测功耗对比:
- 正常模式:12mA
- 停机模式:0.8mA
- 待机模式:2μA(但会丢失RAM数据)
5. 功能扩展方向
基于现有硬件可进一步实现:
-
蓝牙控制:添加HC-05模块,通过手机APP调节色温
- 注意:需要修改串口中断优先级避免影响PWM时序
-
学习模式:记录用户使用习惯自动生成调光方案
- 需要外接EEPROM存储数据
-
能耗统计:利用STM32内部温度传感器监测灯具工作状态
- 计算公式:功耗(mW)=Vcc×(ADC值×3.3/4096)/采样电阻
这个项目最让我惊喜的是STM32F103的性价比——用不到一杯奶茶的钱就能实现商业台灯80%的功能。建议初学者重点关注定时器和中断系统的灵活运用,这是嵌入式开发的核心基本功。最后分享一个冷知识:人体感应模块的检测角度可以通过调整透镜位置来改变,我的实测数据是原始110°可调整到60-150°范围。