1. 为什么选择STM32F103C8T6做智能手环
第一次接触STM32F103C8T6是在五年前的一个智能家居项目上,当时就被它强大的性能和亲民的价格惊艳到了。这款芯片简直就是为智能穿戴设备量身定做的——72MHz的主频跑健康监测算法绰绰有余,64KB的Flash装下我们所有功能代码还有富余,最关键是它的功耗控制做得特别好,实测待机电流只有0.5mA左右。
记得当时对比过好几款MCU,比如ESP32虽然自带WiFi但功耗太高,nRF52系列蓝牙性能好但外设资源有限。而STM32F103C8T6就像个全能选手:12位ADC能直接读取模拟传感器,I2C/SPI/UART接口一应俱全,甚至还能用USB做数据传输。最让我惊喜的是它的中断响应速度,配合MAX30102传感器做心率监测时,能精准捕捉到每个脉搏波形的上升沿。
2. 硬件设计实战经验分享
2.1 传感器选型踩坑记
MAX30102心率血氧模块的选择真是血泪史。最早试过便宜的PDM传感器,结果运动干扰大到没法用。后来换MAX30102发现不同厂家的模块差异巨大:有的LED驱动电流不稳,有的I2C上拉电阻缺失。建议直接买带FIFO的版本,采样时能减轻MCU负担。
ADXL345加速度计要注意焊接温度。有次批量生产时发现20%的模块计步不准,排查发现是回流焊温度过高导致传感器偏移。现在我们都先在开发板上用以下代码测试三轴数据:
void ADXL345_Test() { int16_t x,y,z; ADXL345_Read_Data(&x,&y,&z); printf("X=%d Y=%d Z=%d\n",x,y,z); if(abs(x)>300 || abs(y)>300 || abs(z)>300) LED_Alert(); // 数值异常报警 }2.2 低功耗设计关键点
智能手环最怕续航短,我们的方案是:
- 使用AMS1117-3.3V低压差稳压器
- 所有传感器都通过MOS管控制供电
- STM32平时工作在Sleep模式,通过RTC每秒钟唤醒一次
实测下来,这种设计让200mAh的电池能用7天以上。关键代码如下:
void Enter_LowPower() { // 关闭传感器电源 GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 配置RTC唤醒 RTC_SetWakeUpCounter(RTC_WAKEUPCLOCK_CK_SPRE_16BITS, 0x1FFF); // 进入停止模式 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); }3. 软件架构设计心得
3.1 分层架构实践
我们把系统分为三层:
- 硬件抽象层:封装所有传感器驱动
- 算法处理层:实现计步、心率计算等
- 应用层:处理用户交互和蓝牙通信
这种结构最大的好处是移植方便。上次客户要换OLED屏幕,我们只花了半天就适配了新驱动。关键的头文件定义如下:
// hal_oled.h typedef struct { void (*Init)(void); void (*ShowData)(HealthData data); } OLED_Driver; // app_main.c extern OLED_Driver oled; oled.ShowData(current_data);3.2 蓝牙协议优化技巧
HC-05模块最头疼的是数据传输不稳定。我们通过以下措施提升可靠性:
- 自定义数据帧格式:头字节+长度+CRC校验
- 重要数据采用应答重传机制
- 手机端做数据缓存
实测传输成功率从80%提升到99.5%。数据包结构示例:
[0xAA][0x05][HR][SpO2][STEP_H][STEP_L][TEMP][CRC]4. 算法优化实战记录
4.1 动态阈值计步算法
传统计步算法在慢走时容易漏检,我们改进的方案是:
- 动态调整加速度阈值
- 结合三轴向量变化率判断
- 加入步频连续性检测
算法核心逻辑:
uint16_t Count_Steps(float accel[3]) { static float threshold = 1.2f; // 初始阈值 float magnitude = sqrt(accel[0]*accel[0] + accel[1]*accel[1] + accel[2]*accel[2]); if(magnitude > threshold && !peak_detected) { steps++; threshold = 0.3*magnitude + 0.7*threshold; // 动态调整 peak_detected = 1; } else if(magnitude < threshold*0.8) { peak_detected = 0; } return steps; }4.2 心率信号滤波方案
MAX30102原始信号包含大量噪声,我们采用:
- 硬件端:调整LED电流和采样率
- 软件端:IIR低通滤波+移动平均
- 运动状态下启用加速度补偿
滤波实现代码:
float Filter_HeartRate(float raw_data) { static float buffer[5] = {0}; static uint8_t index = 0; // 移出旧数据 for(int i=0; i<4; i++) buffer[i] = buffer[i+1]; // IIR滤波 buffer[4] = 0.2*raw_data + 0.8*buffer[3]; // 移动平均 float sum = 0; for(int i=0; i<5; i++) sum += buffer[i]; return sum/5; }5. 生产测试方案
5.1 自动化测试架设计
我们自制了测试工装,包含:
- 可编程模拟手指(测试MAX30102)
- 三轴震动平台(测试ADXL345)
- 温控金属块(测试DS18B20)
测试流程全自动化,通过Python脚本控制:
import serial def test_heart_rate(): arduino = serial.Serial('COM3', 115200) arduino.write(b'START_HR_TEST') result = arduino.readline().decode() assert 'HR=75±3' in result5.2 功耗测试方法
用Joulescope精密电流计记录不同模式下的功耗:
- 静止模式:应<1mA
- 数据传输模式:应<15mA
- 报警模式:应<20mA
测试时发现OLED背光是耗电大户,后来改用PWM动态调节亮度,省电30%。
6. 用户体验优化细节
6.1 佩戴舒适度改进
第三代产品我们重点优化了:
- 腕带材质改用医用级硅胶
- 传感器凸起高度控制在0.5mm以内
- 增加皮肤接触检测功能
接触检测电路很简单但很实用:
bool Check_Wearing_Status(void) { GPIO_SetBits(GPIOA, GPIO_Pin_1); // 发出检测信号 delay_us(10); return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2); // 检测反馈 }6.2 手机APP交互设计
总结出三个黄金原则:
- 重要数据优先显示
- 异常值自动高亮
- 历史趋势可视化
蓝牙协议中特别增加了紧急告警标志位:
[0x55][ALARM_TYPE][DATA_LEN][...DATA...][CRC]7. 常见问题解决方案
7.1 信号干扰处理
遇到最诡异的问题是地铁上心率监测失灵,最终解决方案:
- 给所有传感器加磁珠滤波
- PCB增加屏蔽层
- 软件增加抗干扰算法
7.2 固件升级方案
采用IAP技术实现无线升级,关键步骤:
- 将Flash分为Bootloader和APP区
- 通过蓝牙接收新固件
- 校验通过后跳转更新
Bootloader部分核心代码:
void JumpToApp(void) { if(((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000) == 0x20000000) { JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4); Jump_To_Application = (pFunction)JumpAddress; __set_MSP(*(__IO uint32_t*)APP_ADDRESS); Jump_To_Application(); } }8. 成本控制经验
8.1 元器件选型技巧
经过多次迭代,现在的BOM成本控制在$15以内:
- STM32F103C8T6:$2.5
- MAX30102模块:$3.8
- ADXL345:$1.2
- OLED屏:$2.0
8.2 生产测试优化
采用以下措施降低质检成本:
- 开发自动化测试脚本
- 关键参数SPC统计控制
- 故障模式分析(FMEA)
最近一次量产的不良率从5%降到了0.8%。