1. STM32智能垃圾桶项目概述
去年夏天帮朋友改造办公室时,发现传统垃圾桶存在三个痛点:需要手动开盖容易交叉感染、垃圾满溢后才清理、无法分类投放。这促使我用STM32设计了一款能自动开盖、满溢预警和语音分类提示的智能垃圾桶。选择STM32F103C8T6作为主控,不仅因为其72MHz主频足够处理传感器数据,更看重其丰富的外设接口和成熟的生态支持。
这个项目涉及STM32基础外设(GPIO、定时器、ADC)、传感器数据融合(超声波+红外)、电机控制和简单的语音提示系统。最让我惊喜的是,通过合理利用STM32的低功耗模式,两节18650电池可以稳定工作三个月以上。下面分享从硬件选型到代码调试的全过程经验,特别是几个关键参数的调试技巧。
2. 硬件设计与核心器件选型
2.1 主控芯片选择考量
对比STM32F1、F4系列后,最终选用20元左右的STM32F103C8T6(蓝色pill开发板),主要基于三点考虑:
- 成本敏感:作为消费级产品需控制BOM成本
- 外设需求:需要4个PWM通道(2个电机+2个舵机)、1个ADC(监测电池电压)、2个USART(调试+语音模块)
- 开发效率:标准库和HAL库资料丰富,缩短开发周期
注意:购买时认准"正品丝印",市场上存在打磨重印的假冒芯片,会导致ADC精度不达标。我曾在某宝买到假货,表现为超声波测距数据跳变严重。
2.2 传感器方案对比测试
测试了三种测距方案后,确定最终配置:
| 传感器类型 | 型号 | 测距范围 | 功耗 | 安装位置 | 优缺点分析 |
|---|---|---|---|---|---|
| 超声波 | HC-SR04 | 2-400cm | 15mA | 桶盖顶部 | 成本低但易受温度影响 |
| 红外对管 | E18-D80NK | 3-80cm | 25mA | 桶身两侧 | 抗干扰强但需要精确对准 |
| TOF激光 | VL53L0X | 0-200cm | 10mA | (未采用) | 精度高但成本超预算3倍 |
实际采用"超声波+红外"双保险方案:超声波负责检测人手接近触发开盖(响应时间<200ms),红外对管监测垃圾高度(精度±1cm)。当垃圾达到预设高度(如桶深的80%),触发蜂鸣器报警。
2.3 驱动电路设计要点
电机驱动选用L298N模块时踩过坑:直接驱动12V减速电机会导致STM32复位。解决方案是:
- 添加光耦隔离电路(PC817)
- 电机电源与MCU完全分离
- 在电机两端并联1N5819续流二极管
关键参数计算:
- 舵机扭矩需求:桶盖重量150g,力臂15cm → 需要扭矩≥150gf·cm
- 电池容量:系统待机电流2mA,工作峰值300mA → 2000mAh电池可满足:
[
\frac{2000}{2 + 300 \times 0.1} \approx 60天
]
(假设每天激活10%时间)
3. 软件架构与关键代码实现
3.1 开发环境搭建
放弃Keil选择VSCode+PlatformIO的组合,配置步骤如下:
- 安装Python3.8+并添加PATH
- VSCode安装PlatformIO IDE插件
- 新建STM32F103C8T6项目,选择框架为
ststm32 - 修改platformio.ini:
ini复制[env:bluepill_f103c8] platform = ststm32 board = bluepill_f103c8 framework = stm32cube upload_protocol = stlink build_flags = -D HAL_UART_MODULE_ENABLED
3.2 多任务调度设计
由于需要同时处理传感器数据、电机控制和用户交互,采用时间片轮询架构而非RTOS:
c复制void main() {
HAL_Init();
SystemClock_Config();
while(1) {
static uint32_t tick = 0;
if(HAL_GetTick() - tick > 10) { // 10ms周期
tick = HAL_GetTick();
Task_SensorUpdate(); // 传感器数据采集
Task_MotorControl(); // 电机PID控制
Task_UserInterface(); // LED/蜂鸣器反馈
Task_PowerManage(); // 低功耗管理
}
}
}
关键技巧:
- 使用HAL库的HAL_GetTick()而非直接操作SysTick
- 每个任务必须保证执行时间<2ms
- 共享变量用__IO修饰确保volatile特性
3.3 超声波测距算法优化
原始HC-SR04库存在15%的误测率,改进方案:
- 采用中值滤波:连续采样5次去掉最高最低值
- 温度补偿:通过DS18B20获取环境温度,修正声速
[
v = 331.4 + 0.6 \times T_{℃}
] - 动态阈值:根据历史数据自动调整触发距离
实现代码片段:
c复制float Get_Distance() {
float temp = DS18B20_Read();
float velocity = 331.4 + 0.6 * temp;
uint32_t buf[5];
for(int i=0; i<5; i++) {
buf[i] = HC_SR04_Measure();
HAL_Delay(2);
}
qsort(buf, 5, sizeof(uint32_t), compare);
return (buf[1]+buf[2]+buf[3])/3 * velocity / 2 / 10000;
}
4. 低功耗设计与实测数据
4.1 电源管理模式
通过STM32的STOP模式实现超低功耗:
c复制void Enter_STOP_Mode() {
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
HAL_PWREx_EnableUltraLowPower();
HAL_PWREx_EnableFastWakeUp();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后需要重新配置时钟
SystemClock_Config();
}
唤醒源配置:
- PA0引脚(红外中断唤醒)
- RTC闹钟(每2小时强制唤醒检查状态)
4.2 实测功耗数据
不同模式下的电流消耗:
| 工作模式 | 配置措施 | 平均电流 | 持续时间占比 |
|---|---|---|---|
| 正常运行 | 所有外设使能 | 38mA | 5% |
| 轻量休眠 | 关闭电机电源 | 5mA | 65% |
| 深度休眠 | STOP模式+外设断电 | 0.2mA | 30% |
| 极限模式 | 关闭所有非必要外设 | 80μA | (测试用) |
实测表明,采用动态功耗管理后,2500mAh电池可续航83天(每日开盖约50次)。
5. 生产调试与问题排查
5.1 常见故障速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 桶盖误触发 | 超声波回波干扰 | 加装橡胶吸波材料 |
| 电机启动时MCU复位 | 电源瞬态跌落 | 增加2200μF电解电容 |
| 测距数据跳变 | 电源纹波过大 | 更换LDO为TPS7A系列 |
| RTC时间不准 | 未配置LSE晶振 | 在CubeMX中启用LSE |
| 唤醒延迟 | 未启用快速唤醒 | 调用HAL_PWREx_EnableFastWakeUp |
5.2 烧录避坑指南
使用ST-Link时遇到的两个典型问题:
- 无法识别芯片:检查BOOT0引脚必须下拉,SWD接口的NRST线需正确连接
- Flash校验失败:降低烧录速度到200kHz,在CubeProgrammer中勾选"Reset after programming"
建议的烧录步骤:
bash复制openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "program build/firmware.elf verify reset exit"
6. 项目优化方向
当前版本仍有改进空间:
- 增加WiFi模块(ESP-01S)实现远程满溢报警
- 改用FOC无刷电机降低噪音
- 添加电容触摸开关替代物理按键
- 引入TinyML实现手势控制
最近测试发现,将PWM频率从1kHz提升到20kHz可明显降低电机啸叫,但要注意:
- 需要重新计算PID参数
- 检查MOS管是否支持高频开关
- 可能增加驱动芯片发热量
