1. 项目概述
这个智能台灯项目是我去年为一个创客空间设计的教学案例,初衷是想让学员通过一个完整的物联网项目掌握STM32开发全流程。没想到成品出来后,连我自己都爱不释手地用了大半年——它能根据环境光线自动调节亮度,通过手势切换模式,还能用手机远程控制,比市面上千元级的智能台灯还要顺手。
核心硬件采用STM32F103C8T6最小系统板,成本不到30元却实现了三大核心功能:BH1750光照传感器采集环境亮度,APDS-9960手势识别模块实现非接触控制,ESP8266模块完成WiFi联网。软件层面移植了FreeRTOS实现多任务调度,通过自定义协议与手机App通信。
2. 硬件设计与选型
2.1 主控芯片选择
对比STM32F1系列的几款芯片后,最终选定STM32F103C8T6(俗称"蓝莓派"):
- 72MHz主频足够处理传感器数据+网络通信
- 64KB Flash/20KB RAM满足FreeRTOS需求
- 丰富的GPIO和PWM输出(驱动LED需要)
- 成本仅8-12元,远低于F4/F7系列
注意:市场上存在翻新芯片,建议选择正规渠道。我曾买到过无法正常烧录的二手芯片,后来用STM32CubeProgrammer的芯片擦除功能才识别出来。
2.2 传感器模块选型
光照传感器对比测试:
| 型号 | 量程(lux) | 接口 | 实测误差 | 单价 |
|---|---|---|---|---|
| BH1750 | 1-65535 | I2C | ±10% | 3.5 |
| TSL2561 | 0.1-40000 | I2C | ±5% | 12 |
| 光敏电阻 | 10-1000 | ADC | ±30% | 0.2 |
最终选择BH1750,虽然精度不是最高,但量程和性价比最符合台灯需求。实际使用中发现两个坑:
- 需要每500ms读取一次,连续读取会导致数据异常
- 模块上的电容会影响I2C时序,建议去掉或减小到0.1uF
手势识别方案:
APDS-9960是唯一支持4方向手势+接近检测的集成模块(价格约15元)。调试时发现:
- 必须严格按文档要求安装(距离灯罩3-5cm)
- 需要定期校准环境光补偿
- 手势识别延迟约200ms,不适合快速切换场景
2.3 无线通信方案
测试了三种WiFi方案后选择ESP-01S:
- 直接使用STM32+WiFi模块(如RN171):成本高且开发复杂
- STM32+蓝牙HC-05:距离受限(实测<5米)
- ESP8266透传模式:成本仅8元,通过AT指令与STM32串口通信
关键配置参数:
c复制// ESP8266初始化命令
const char* wifi_cmds[] = {
"AT+CWMODE=3", // 双模式
"AT+CWJAP=\"SSID\",\"PWD\"", // 连接WiFi
"AT+CIPSTART=\"TCP\",\"192.168.1.100\",8080", // 连接服务器
"AT+CIPMODE=1", // 透传模式
"AT+CIPSEND" // 开始传输
};
3. 软件架构实现
3.1 实时操作系统移植
使用FreeRTOS创建三个核心任务:
- 传感器采集任务(优先级3)
- 每100ms读取光照强度
- 每50ms检测手势状态
- 网络通信任务(优先级2)
- 处理MQTT消息订阅/发布
- 维持心跳连接
- 灯光控制任务(优先级1)
- PWM输出调节亮度
- 执行模式切换逻辑
任务间通过消息队列通信:
c复制typedef struct {
uint8_t cmd_type; // 1=亮度 2=模式 3=开关
uint16_t value; // 参数值
} light_msg_t;
xQueueHandle light_queue = xQueueCreate(10, sizeof(light_msg_t));
3.2 灯光控制算法
采用增量式PID算法实现平滑调光:
c复制// PID参数(实测调优值)
#define KP 0.8
#define KI 0.05
#define KD 0.1
int pid_control(int target, int current) {
static int last_error = 0;
static int integral = 0;
int error = target - current;
integral += error;
int derivative = error - last_error;
last_error = error;
return KP*error + KI*integral + KD*derivative;
}
实测发现两个优化点:
- 需要限制积分项累积(防止"积分饱和")
- 当亮度差值<50lux时改用线性调节
3.3 手机端通信协议
自定义的轻量级协议格式:
code复制[HEAD][LEN][CMD][DATA][CRC]
0x55 0x06 0xA1 0x64 0xXX
- HEAD: 固定0x55
- LEN: 数据长度(不含头和CRC)
- CMD: 指令码(如0xA1=设置亮度)
- DATA: 参数值(如亮度值0-100)
- CRC: 校验和(累加和取反)
Android端关键代码:
java复制void sendBrightness(int value) {
byte[] cmd = new byte[5];
cmd[0] = (byte)0x55; // HEAD
cmd[1] = 0x03; // LEN
cmd[2] = (byte)0xA1; // CMD
cmd[3] = (byte)value; // DATA
cmd[4] = checkSum(cmd); // CRC
mSocket.write(cmd);
}
4. 制作与调试要点
4.1 PCB设计注意事项
-
布局规划:
- 传感器模块远离MCU(防止热干扰)
- WiFi天线周边留出15mm净空区
- 电源走线宽度≥0.5mm
-
实测遇到的EMC问题:
- PWM频率超过1kHz会导致WiFi丢包(最终设为800Hz)
- 未加磁珠时I2C受电机干扰(添加120Ω电阻解决)
4.2 结构设计技巧
使用3D打印灯罩时要注意:
- 壁厚≥2mm(防止透光不均)
- 顶部开孔直径3mm(散热与光线扩散平衡)
- 手势传感器窗口加磨砂膜(提升识别率)
我的改进方案:
diff复制- 直筒型灯罩(有眩光)
+ 45度斜切开口(光线更柔和)
4.3 生产测试流程
建议的测试顺序:
- 电源测试(空载电压/带载压降)
- 烧录测试(连续烧写10次验证稳定性)
- 功能测试(按此检查表):
- [ ] 上电默认亮度50%
- [ ] 手势识别响应时间<300ms
- [ ] WiFi重连时间<15秒
- [ ] 最大亮度功耗<5W
5. 常见问题排查
5.1 手势识别不灵敏
可能原因及解决方案:
- 环境光干扰 → 重新校准传感器
- 安装位置偏移 → 调整模块与灯罩距离
- 供电不足 → 在VCC引脚并联100uF电容
5.2 WiFi频繁断开
通过AT指令获取诊断信息:
code复制AT+CWJAP? // 查看信号强度(应>-70dBm)
AT+CIPSTATUS // 检查连接状态
AT+PING="www.baidu.com" // 测试外网
典型解决方案:
- 修改路由器信道(避开拥挤的6/11信道)
- 降低ESP8266发射功率(AT+RFPOWER=15)
- 添加TCP keepalive(AT+CIPKEEP=1,60,5)
5.3 PWM调光闪烁
调试步骤:
- 用示波器查看PWM波形(应稳定无抖动)
- 检查LED驱动电路:
- MOSFET栅极电阻建议10-100Ω
- 续流二极管选型(如1N5819)
- 测试不同频率下的表现:
- 100Hz以下肉眼可见闪烁
- 1kHz以上可能干扰无线
这个项目最让我惊喜的是手势控制的实用性——现在晚上起床只需在灯前挥挥手就能获得恰到好处的亮度,再也不用摸黑找开关了。最近正尝试加入语音识别功能,用STM32的有限资源实现离线指令识别会是个有趣的挑战。