1. 项目概述
这个智能台灯项目是我最近完成的一个嵌入式系统实践,核心功能是通过STM32微控制器实现环境光照检测和自动亮度调节。相比传统台灯,它最大的特点是能够感知周围光线变化并自动调整亮度,还能通过语音模块播报当前光照状态,使用体验相当智能。
项目硬件部分主要包含STM32最小系统板、光敏电阻传感器、LED驱动电路和语音模块。软件层面则实现了三种工作模式切换(自动/手动/语音)、ADC采样、PWM调光和串口通信等功能。整个系统功耗控制在5W以内,非常适合作为桌面照明设备长期使用。
2. 硬件设计与选型
2.1 核心控制器选择
我选用了STM32F103C8T6作为主控芯片,这款ARM Cortex-M3内核的MCU具有以下优势:
- 72MHz主频满足实时性要求
- 内置12位ADC可用于光照采样
- 多达4个定时器支持PWM输出
- 丰富的外设接口(USART、I2C、SPI)
- 64KB Flash和20KB SRAM的存储空间
- 价格亲民(约10元/片)
注意:实际采购时建议选择正品芯片,市场上存在不少翻新货。我曾在某宝买到过重新打标的芯片,ADC精度明显不达标。
2.2 光敏传感器电路
光照检测使用GL5528光敏电阻,其特性如下:
- 亮电阻(10Lux):8-20KΩ
- 暗电阻(0Lux):1-2MΩ
- 响应时间:约20ms
- 光谱峰值:540nm
传感器电路采用分压式设计:
code复制VCC ──┬── [10KΩ固定电阻] ──┬── ADC输入
│ │
└── [光敏电阻] ─────┘── GND
这个经典电路将光敏电阻值变化转换为电压变化,经STM32的ADC1通道1(PA1)采样。
2.3 LED驱动设计
台灯光源选用5730贴片LED(6串3并),驱动方案如下:
- 使用MOSFET IRF540N作为开关器件
- STM32的TIM3_CH1(PB4)输出PWM信号
- 恒流驱动设计,最大电流300mA
- 添加散热片防止过热
PWM频率设为1kHz,占空比调节范围0-100%,对应亮度0-100%。实测发现人眼对亮度变化感知非线性,后续在代码中做了gamma校正。
3. 软件实现细节
3.1 系统初始化
系统上电后需初始化各外设:
c复制void Hardware_Init(void)
{
RCC_Configuration(); // 时钟配置
GPIO_Configuration(); // GPIO初始化
ADC1_Init(); // ADC初始化
TIM3_PWM_Init(); // PWM定时器初始化
USART1_Init(9600); // 串口初始化(语音模块)
NVIC_Configuration(); // 中断配置
// 默认进入自动模式
current_mode = AUTO_MODE;
}
3.2 ADC采样与数据处理
光照采样采用均值滤波算法:
c复制#define SAMPLE_TIMES 10
uint16_t Get_Light_Level(void)
{
uint32_t sum = 0;
for(uint8_t i=0; i<SAMPLE_TIMES; i++){
sum += Get_ADC_Value();
Delay_ms(5);
}
uint16_t average = sum / SAMPLE_TIMES;
// 非线性补偿
if(average < 50) return 0;
if(average > 4000) return 4095;
return (uint16_t)(pow((double)average/4095.0, 1.5)*4095);
}
采样值经过以下处理:
- 10次采样取平均
- 去除极端值干扰
- gamma校正(γ=1.5)
- 映射到0-100%亮度范围
3.3 自动调光算法
核心调光逻辑采用分段线性调节:
c复制void Auto_Adjust_Light(uint16_t adc_val)
{
uint8_t brightness;
if(adc_val < 500){ // 很暗
brightness = 100;
}
else if(adc_val < 1500){ // 较暗
brightness = map(adc_val, 500,1500, 100,70);
}
else if(adc_val < 3000){ // 适中
brightness = map(adc_val, 1500,3000, 70,40);
}
else{ // 很亮
brightness = 30;
}
Set_PWM_Duty(brightness);
}
其中map函数实现线性映射:
c复制uint8_t map(uint16_t x, uint16_t in_min, uint16_t in_max, uint8_t out_min, uint8_t out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
3.4 语音播报实现
使用SYN6288中文语音模块,通过USART发送GB2312编码的文本:
c复制void Voice_Report(uint16_t light_level)
{
uint8_t cmd[20];
if(light_level < 500){
sprintf((char*)cmd, "[v0][m3]当前光照很暗");
}
else if(light_level < 1500){
sprintf((char*)cmd, "[v0][m3]当前光照较暗");
}
// ...其他条件判断
USART_SendData(USART1, 0xFD);
USART_SendData(USART1, strlen((char*)cmd)+2);
USART_SendData(USART1, 0x00);
for(uint8_t i=0; i<strlen((char*)cmd); i++){
USART_SendData(USART1, cmd[i]);
}
}
4. 系统优化与问题解决
4.1 光敏电阻响应延迟问题
初期测试发现光照突变时响应延迟明显,通过以下措施改善:
- 将采样间隔从100ms缩短到50ms
- 添加滑动平均滤波:
c复制#define FILTER_LEN 5
uint16_t filter_buf[FILTER_LEN];
uint8_t filter_index = 0;
uint16_t Moving_Average_Filter(uint16_t new_val)
{
filter_buf[filter_index] = new_val;
filter_index = (filter_index + 1) % FILTER_LEN;
uint32_t sum = 0;
for(uint8_t i=0; i<FILTER_LEN; i++){
sum += filter_buf[i];
}
return sum / FILTER_LEN;
}
4.2 PWM调光闪烁问题
当PWM频率低于200Hz时,人眼会感知到闪烁。解决方案:
- 将TIM3 PWM频率提高到1kHz
- 使用硬件PWM输出模式
- 添加RC滤波电路(10KΩ+0.1μF)
4.3 语音模块干扰问题
语音模块工作时导致ADC采样异常,采取以下对策:
- 为语音模块单独供电
- ADC采样期间暂停语音通信
- 在电源端添加100μF电解电容
5. 完整系统测试
5.1 功能测试用例
| 测试项 | 测试方法 | 预期结果 | 实际结果 |
|---|---|---|---|
| 自动模式 | 用手电筒照射光敏电阻 | 灯光自动变暗 | 符合 |
| 手动模式 | 旋转编码器 | 亮度可调 | 符合 |
| 语音模式 | 说出"打开台灯" | 灯光开启并语音回应 | 符合 |
| 过载保护 | 短路LED输出 | 系统自动断电 | 符合 |
5.2 性能参数实测
| 参数 | 指标 | 实测值 |
|---|---|---|
| 亮度调节范围 | 0-100% | 5-100% |
| 响应时间 | <0.5s | 0.3s |
| 待机功耗 | <0.5W | 0.3W |
| 最大亮度功耗 | <5W | 4.8W |
| 工作温度 | -10~50℃ | 25℃(室温) |
6. 项目扩展方向
这个基础版本完成后,还可以考虑以下增强功能:
- 添加WiFi模块实现手机APP控制
- 增加人体感应自动开关
- 实现定时开关和情景模式
- 加入环境温湿度监测
- 设计3D打印外壳
我在实际开发中发现,STM32的硬件资源只使用了约60%,完全有空间实现更多功能。比如可以利用剩下的定时器实现呼吸灯效果,或者用I2C接口连接OLED显示屏显示实时参数。