1. 项目背景与核心功能解析
去年冬天在B站偶然刷到一个开源智能手表项目,作为嵌入式开发老鸟,我立刻被这个基于STM32的方案吸引了。这个项目完美融合了我最感兴趣的几个技术点:低功耗MCU开发、传感器集成和微型人机交互设计。经过两周的复刻调试,最终成品不仅实现了基础功能,还加入了一些个人优化。下面就把这个完整过程分享给大家。
这款手表的核心控制器选用的是STM32F103C8T6,也就是我们常说的"蓝莓派"。选择它主要考虑三点:首先是性价比,20元左右的价位就能获得72MHz主频的Cortex-M3内核;其次是生态完善,标准库和HAL库资料丰富;最重要的是其低功耗特性,配合TP4056充电管理芯片,实测待机电流可以控制在5mA以下。
显示部分采用1.3寸OLED,分辨率128x64。相比LCD,OLED的自发光特性更适合穿戴设备,显示对比度高且更省电。运动检测由MPU6050六轴传感器负责,这个芯片虽然老但性能稳定,通过I2C接口与主控通信,可以获取三轴加速度和陀螺仪数据。
2. 硬件设计与PCB制作要点
2.1 核心电路设计解析
原理图设计有几个关键点需要注意:
- STM32的VBAT引脚必须接备用电池,否则RTC时钟无法保持
- MPU6050的AD0引脚需要下拉,I2C地址才能设为0x68
- OLED的复位电路要加100nF电容消抖
- TP4056充电芯片的PROG引脚需接2K电阻设置充电电流
PCB布局时特别注意:
- 晶振要尽量靠近MCU,走线长度不超过10mm
- 模拟和数字地之间用0Ω电阻单点连接
- 电池接口附近预留足够宽的电源走线
- 所有按键信号线都加上0.1μF滤波电容
2.2 嘉立创打板实战经验
使用嘉立创EDA导入工程文件时,有几点实用技巧:
- 每月2次免费打板券要在下单页面手动勾选
- 板厚建议选1.6mm,太薄容易变形
- 阻焊颜色选黑色更显高级感
- 下单前一定要用DRC检查最小线距
有个坑我踩过:第一次打板忘记勾选"板边倒角",结果PCB边缘非常锋利,戴手上会刮皮肤。建议新手务必勾选这个选项,虽然要多加5块钱但很值。
3. 元器件采购与焊接技巧
3.1 物料清单优化方案
原项目的BOM表有几个可以优化的地方:
- STM32可以买拆机件,价格能便宜一半
- 0402封装的电阻电容买带装更划算
- 振动电机可以选用8mm直径的,震感更明显
- 表带建议买22mm宽的通用款,后期更换方便
我的采购清单总成本控制在120元左右,其中最贵的三个部件是:
- OLED屏幕(35元)
- MPU6050模块(18元)
- STM32F103C8T6(22元)
3.2 QFN封装焊接实战
MPU6050采用的QFN-24封装确实是个挑战。我的焊接步骤是:
- 先用焊台给PCB焊盘上锡
- 涂少量助焊膏在芯片底部
- 用镊子对准位置后热风枪300℃吹10秒
- 最后用放大镜检查各引脚有无桥接
关键技巧:
- 风枪要画小圈移动,避免局部过热
- 可以用Kapton胶带固定芯片四角
- 焊完后用洗板水清洁残留助焊剂
如果出现连锡,我的处理方法是:
- 用吸锡带吸除多余焊锡
- 补涂助焊膏后重新加热
- 必要时用手术刀片轻轻分离引脚
4. 软件调试与功能实现
4.1 开发环境搭建
我使用的是Keil MDK 5.38 + STM32CubeMX组合:
- 用CubeMX生成时钟和GPIO初始化代码
- 移植OLED的SSD1306驱动
- 添加MPU6050的DMP库处理姿态数据
- 实现FreeRTOS任务调度框架
时钟配置要点:
- HSE 8MHz -> PLL -> 72MHz系统时钟
- APB1总线不超过36MHz
- 启用RTC时钟源(LSE)
4.2 关键功能代码解析
时间显示实现:
c复制void RTC_DisplayTask(void *pvParameters) {
RTC_TimeTypeDef sTime;
while(1) {
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
OLED_ShowNum(30, 2, sTime.Hours, 2);
OLED_ShowNum(54, 2, sTime.Minutes, 2);
vTaskDelay(500);
}
}
水平仪算法:
c复制float getPitchAngle() {
float accelZ = mpu6050.accelZ / 16384.0f;
float accelY = mpu6050.accelY / 16384.0f;
return atan2(accelY, accelZ) * 180 / PI;
}
游戏控制逻辑:
c复制void DinoGame_Task() {
if(KEY_Read(KEY1) && !dino.isJumping) {
dino.velocity = JUMP_FORCE;
dino.isJumping = 1;
}
// 碰撞检测
if(cactus.x < DINO_X + DINO_WIDTH &&
cactus.x + CACTUS_WIDTH > DINO_X) {
gameOver = 1;
}
}
5. 常见问题排查指南
5.1 按键失灵问题分析
我遇到的K1按键问题很典型:硬件测量有电平变化但软件检测不到。通过逻辑分析仪抓取波形发现:
- 按键按下时出现20ms抖动
- CPU引脚配置为上拉输入模式
- 实际电路缺少硬件消抖电容
解决方案:
- 在按键两端并联104电容
- 软件添加去抖延时:
c复制uint8_t KEY_Read(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {
if(HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == 0) {
HAL_Delay(20);
if(HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == 0)
return 1;
}
return 0;
}
5.2 MPU6050初始化失败
现象:I2C通信正常但DMP初始化失败。通过以下步骤排查:
- 检查供电电压是否稳定(3.3V±5%)
- 确认I2C上拉电阻(4.7K)已正确连接
- 读取WHO_AM_I寄存器返回值应为0x68
- 校准加速度计和陀螺仪偏移量
最终发现是焊接时温度过高导致芯片内部损伤,更换新芯片后解决。
6. 功能扩展与优化方向
6.1 电源管理优化
当前版本待机时间约48小时,可以通过以下方式改进:
- 启用STM32的Stop模式,将功耗降至1.5mA
- 添加光感传感器自动调节屏幕亮度
- 实现运动唤醒功能(利用MPU6050中断)
- 优化FreeRTOS的空闲任务处理
6.2 扩展模块设计
正在开发的V2版本计划加入:
- AHT20温湿度传感器
- MAX9814麦克风模块
- 震动马达驱动电路
- 蓝牙4.0通信模块
特别提醒:添加新功能时要考虑PCB尺寸限制,建议先用洞洞板验证电路再集成。
这个项目最让我惊喜的是开源社区的强大力量。从PCB设计到代码实现,每一个环节都能找到现成的参考方案。建议新手可以先完整复刻一版,理解整体架构后再进行个性化修改。我在调试过程中积累的笔记和修改后的工程文件都放在了GitHub上,需要的话可以私信获取链接。
