1. 项目概述:用STM32打造会思考的窗帘
去年装修新房时,我发现传统窗帘存在一个尴尬问题:早上阳光刺眼时窗帘不会自动拉开,阴雨天却可能完全遮挡本就不足的自然光。作为嵌入式开发者,我决定用STM32F103为主控芯片,搭配光敏电阻和环境传感器,开发一套能根据光照强度自动调节的智能窗帘系统。
这个项目的核心在于让窗帘具备环境感知能力。通过光敏电阻实时采集光照数据,STM32F103进行阈值判断后驱动步进电机,实现窗帘开合度的精准控制。整套系统成本控制在200元以内,比市面同类产品便宜60%以上,且支持手动/自动模式切换,夜间还可设置为完全闭合状态提升隐私性。
2. 硬件设计与选型解析
2.1 主控芯片:为什么选择STM32F103C8T6
在对比了Arduino、ESP8266等多款控制器后,最终选定STM32F103C8T6作为主控,主要基于三点考量:
- ADC精度需求:需要12位ADC精确采集光敏电阻的模拟信号(其他芯片多为10位ADC)
- PWM输出能力:要同时控制步进电机和1602液晶屏背光,需至少3路PWM
- 成本控制:核心板价格仅15-20元,远低于带WiFi功能的ESP32
实测发现:使用CubeMX配置时需特别注意ADC的采样周期设置,过短的采样时间会导致光照数据波动剧烈。推荐将ADC时钟分频设为PCLK2/8,采样周期设为239.5周期。
2.2 环境感知模块设计
光照检测采用GL5528光敏电阻,其特性曲线非常适合室内环境:
- 10Lux时电阻约8-12KΩ
- 100Lux时降至1-2KΩ
- 配合10KΩ分压电阻,形成适合STM32ADC检测的电压范围
为消除瞬时干扰,在软件层面实现了三重滤波:
- 硬件RC滤波(100Ω+0.1uF)
- 滑动窗口均值滤波(窗口大小15)
- 变化率限幅(ΔLux/min ≤ 500)
2.3 驱动电路设计要点
步进电机选用28BYJ-48+ULN2003驱动板组合,关键参数配置:
c复制// 步进电机参数
#define STEPS_PER_REV 2048 // 单圈步数
#define SPEED 10 // RPM值
#define ACCEL 1000 // 加速度步数/秒²
实际测试发现两个易错点:
- 电机供电必须与MCU共地,否则会出现随机失步
- 窗帘导轨阻力较大时,需降低加速度至500以下
3. 软件架构与核心算法
3.1 光照-开合度映射算法
通过实验采集了不同时段的光照数据,建立分段线性转换模型:
c复制uint8_t light_to_position(uint16_t lux) {
if(lux < 50) return 100; // 全闭合
if(lux < 200) return map(lux, 50,200, 100,70);
if(lux < 500) return map(lux, 200,500, 70,40);
if(lux < 1000) return map(lux, 500,1000, 40,10);
return 0; // 全开
}
其中map()函数实现线性映射,实测发现加入5%的滞后区间可避免频繁调节。
3.2 状态机设计
系统采用有限状态机模式管理运行状态:
mermaid复制stateDiagram
[*] --> Idle
Idle --> Auto: 长按按键
Auto --> Manual: 单按按键
Manual --> Idle: 双击按键
Auto --> Calibrating: 三击按键
状态切换通过外部中断实现,关键代码片段:
c复制void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
static uint32_t last_tick = 0;
uint32_t now = HAL_GetTick();
if(GPIO_Pin == BTN_Pin) {
if(now - last_tick > 1000) { // 长按
fsm_transition(AUTO_MODE);
}
else if(now - last_tick > 300) { // 单击
fsm_transition(MANUAL_MODE);
}
last_tick = now;
}
}
3.3 低功耗优化技巧
为延长电池供电时的使用时间,采取以下措施:
- ADC采样间隔从默认的1秒改为10秒(光照变化较慢)
- 步进电机停顿时切断驱动板电源(节省约80mA电流)
- 液晶屏背光PWM调至30%亮度(仍可清晰阅读)
实测表明,采用2000mAh锂电池时可连续工作约3周。
4. 组装与调试实录
4.1 机械结构搭建
窗帘导轨改装需注意:
- 步进电机输出轴加装3D打印的减速齿轮(淘宝有现成套件)
- 导轨滑块添加硅油润滑减少阻力
- 限位开关采用磁簧管+磁铁方案(比机械开关更可靠)
4.2 系统校准流程
首次安装必须执行校准:
- 将窗帘手动拉到完全闭合位置
- 长按校准键5秒进入模式
- 按开/关键记录两个极限位置
- 保存EEPROM后重启
常见校准失败原因:
- 导轨阻力不均匀导致步数计算偏差
- 限位开关安装位置偏移
- EEPROM写入未加延时导致数据损坏
4.3 1602液晶屏的实用改造
标准1602屏在强光下可视性差,通过以下改进提升体验:
- 更换高对比度负显屏(蓝底白字)
- 背光串联5Ω电阻降低亮度
- 自定义字符显示开合度百分比符号:
c复制uint8_t customChar[8] = {0x00,0x0E,0x11,0x11,0x11,0x0E,0x00,0x00};
LCD_CreateChar(0, customChar); // 注册为0号字符
5. 典型问题排查指南
5.1 电机失步问题排查
| 现象描述 | 可能原因 | 解决方案 |
|---|---|---|
| 单向失步 | 导轨单侧阻力过大 | 加装辅助滑轮 |
| 随机失步 | 电源功率不足 | 更换2A以上适配器 |
| 启动时失步 | 加速度设置过高 | 将accel参数减半 |
5.2 光照数据异常处理
遇到光照值跳变时,按此流程排查:
- 测量光敏电阻两端电压是否稳定
- 检查ADC基准电压(应接3.3V)
- 确认没有其他光源直射光敏元件
- 尝试屏蔽周围可能的电磁干扰源
5.3 系统死机恢复方案
当出现死机时,可通过以下方式恢复:
- 硬件看门狗复位(需预先启用IWDG)
- 按住按键10秒强制重启
- 使用串口发送恢复命令(需预留调试接口)
我在实际部署中发现,死机多发生在强电磁干扰环境下,给MCU电源加装磁环可有效预防。
6. 项目优化方向
这套系统后续可扩展以下功能:
- 增加温湿度传感器,实现根据室内外温差自动调节
- 添加蓝牙模块,用手机APP调整控制参数
- 引入太阳能板为锂电池充电
- 开发基于霍尔传感器的非接触式位置检测
经过三个月的实际使用,窗帘自动开合准确率达到98%以上。最让我满意的是清晨时分,窗帘会随着日出缓慢拉开,让自然光逐渐唤醒家人,这种体验是传统窗帘无法提供的。所有代码和电路图已开源在GitHub,搜索"STM32-Smart-Curtain"即可获取完整工程文件。