1. 项目概述:为什么选择STM32打造智能窗帘
去年帮朋友改造老房子时,发现传统窗帘的机械定时器经常卡死,这促使我开始研究用STM32实现智能窗帘的方案。相比ESP8266等物联网模块,STM32F103C8T6这类芯片具有更可靠的外设控制能力,特别适合需要精确电机控制的场景。
市面上的智能窗帘产品普遍存在两个痛点:一是云端依赖严重,断网就变"智障";二是功能同质化,缺乏个性化交互。我们这个项目要实现:
- 本地化自动控制(光感+定时)
- 手势识别开关窗帘
- 手机蓝牙直连控制
- 电机运行状态监测
关键选型建议:选用带硬件PWM的STM32F1系列,价格控制在20元以内,性能足够驱动42步进电机。
2. 硬件设计要点解析
2.1 核心器件选型对比
| 器件类型 | 推荐型号 | 参数要点 | 成本 |
|---|---|---|---|
| 主控芯片 | STM32F103C8T6 | 72MHz主频,3路硬件PWM | ¥18 |
| 光感模块 | BH1750 | 0-65535lx量程,I2C接口 | ¥5 |
| 手势传感器 | APDS-9960 | 支持4方向识别,集成距离检测 | ¥25 |
| 电机驱动 | TB6600 | 最大4A电流,64细分 | ¥35 |
| 蓝牙模块 | HC-05 | 经典蓝牙,兼容安卓/iOS | ¥22 |
2.2 电路设计避坑指南
电源部分最容易出问题,实测中发现:
- 电机启动瞬间会导致电压跌落,建议采用1000μF电解电容+0.1μF陶瓷电容组合
- 光感模块对电源噪声敏感,需单独LDO供电
- PWM信号线要加100Ω电阻防止振铃
电机接线有个细节:TB6600的ENA端必须接STM32的GPIO,不能直接接地。我曾因此烧毁过两个驱动芯片,后来发现是使能信号未正确初始化导致电机堵转。
3. 固件开发关键实现
3.1 电机控制算法优化
普通梯形加减速算法在窗帘场景下会有明显顿挫感,改进方案:
c复制// 基于S型曲线的速度规划
void set_motor_speed(uint16_t target) {
static uint16_t current_speed = 0;
float k = 0.2; // 平滑系数
current_speed = (uint16_t)(k*target + (1-k)*current_speed);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, current_speed);
}
实测显示,当k=0.2时,电机启停最为平顺,窗帘布料不会出现剧烈抖动。
3.2 多传感器数据融合
环境光检测需要做滑动平均滤波:
c复制#define FILTER_LEN 10
uint16_t light_filter() {
static uint16_t buf[FILTER_LEN] = {0};
static uint8_t idx = 0;
uint32_t sum = 0;
buf[idx++] = BH1750_Read();
if(idx >= FILTER_LEN) idx = 0;
for(int i=0; i<FILTER_LEN; i++) {
sum += buf[i];
}
return sum/FILTER_LEN;
}
手势识别有个实用技巧:在APDS-9960初始化后,先做5次空手势检测丢弃初始噪声数据,能显著提升识别准确率。
4. 结构设计与安装要点
4.1 3D打印件设计参数
导轨支架的关键尺寸:
- 咬合齿距:2mm(适配常见窗帘轨道)
- 壁厚:≥2.5mm(PLA材料)
- 电机安装孔:M3螺丝孔,预埋螺母
测试过多种材料后,发现PETG的耐候性最好,在阳台环境下不易变形。打印时建议:
- 层高0.2mm
- 填充率30%
- 开启支撑(悬挑部分)
4.2 现场安装避坑记录
- 轨道水平度检测:用手机APP"水平仪"测量,偏差应<1°
- 电机安装后要做空载测试:手动拉动窗帘应无明显阻力
- 光感模块避免阳光直射,最佳安装位置是窗帘内侧上方10cm处
遇到过最棘手的问题是窗帘卡顿,后来发现是打印件的齿距有0.3mm误差。现在都会先用游标卡尺测量实际轨道尺寸再调整模型。
5. 手机APP交互设计
5.1 蓝牙通信协议设计
自定义的简协议格式:
code复制[头字节0xAA][命令字][数据长度][数据][校验和]
典型命令示例:
- 开窗帘:AA 01 00 01 AB
- 设置定时:AA 02 04 08 30 17 00 E3(8:30开,23:00关)
调试技巧:用串口助手模拟手机发送命令,可以快速验证协议解析逻辑
5.2 安卓端关键代码
连接状态监听是个重点:
java复制private final BroadcastReceiver btStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
if(state == BluetoothAdapter.STATE_OFF) {
showToast("请打开蓝牙");
}
}
};
实测发现很多用户会误关蓝牙,现在APP启动时会自动检测并提示,减少了30%的售后咨询。
6. 常见问题解决方案
6.1 电机异常排查表
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 电机振动不转 | 相位接错 | 交换A+ A-或B+ B- |
| 运行时异响 | 电流设置过小 | 调节驱动板电位器 |
| 偶尔失步 | 电源功率不足 | 更换≥3A的适配器 |
| 发热严重 | 细分设置过高 | 改为16或32细分 |
6.2 其他典型问题
-
手势识别不灵敏:
- 检查传感器是否被遮挡
- 调整APDS-9960的LED电流(寄存器0x8F)
-
蓝牙连接频繁断开:
- 避免模块与手机距离超过5米
- 检查天线是否完好(HC-05的陶瓷天线易损)
-
光感数据异常:
- 测量VCC电压是否稳定
- 检查I2C上拉电阻(通常4.7kΩ)
这个项目最让我意外的是用户对"装X功能"的喜爱程度——手势控制的使用频率比预想的高出3倍。现在迭代版本增加了挥动暂停功能,当检测到手在窗帘前停留时自动暂停电机,这个小改进让产品显得更智能。
