1. 项目概述:基于STM32的远程健康监测系统设计
这个项目是我去年为社区养老机构开发的一套老人健康监测系统,核心功能是通过STM32单片机实时采集心率、体温和位置信息,再通过SIM800C模块上传到云端服务器。在实际部署中,这套系统成功将老人意外事件的响应时间从平均30分钟缩短到5分钟以内,护理人员通过手机App就能实时查看所有老人的状态。
系统硬件架构采用模块化设计,主控使用STM32F103ZET6这款性价比极高的Cortex-M3内核单片机。选择它的原因主要有三点:首先,72MHz主频足够处理多传感器数据;其次,内置的512KB Flash和64KB RAM能满足程序存储和运行时需求;最重要的是,它拥有多达5个串口,可以同时连接GPS模块、SIM800C模块和调试终端。
2. 硬件设计与选型要点
2.1 核心控制器电路设计
STM32最小系统电路设计有几个关键细节需要注意:
- 复位电路采用10kΩ上拉电阻+100nF电容的组合,实测下来这种配置在复杂电磁环境下依然稳定
- 晶振电路选用8MHz无源晶振,负载电容匹配22pF,PCB布局时要尽量靠近芯片的OSC_IN和OSC_OUT引脚
- 在每对VDD和VSS引脚附近放置0.1μF去耦电容,我的经验是至少要比芯片手册推荐的多加20%的电容余量
特别提醒:STM32的NRST引脚不能直接悬空,否则可能因为静电积累导致意外复位。我在初期测试时就遇到过这个问题,后来加了10kΩ下拉电阻才解决。
2.2 传感器接口电路
2.2.1 DS18B20温度传感器电路
这个单总线温度传感器电路看似简单,但有几个坑我踩过:
- 上拉电阻选用4.7kΩ比常用的10kΩ更可靠,特别是在长导线传输时
- 在室外应用时,一定要在数据线对地加TVS二极管防止雷击感应浪涌
- 实际测量中发现,当电源电压低于3.0V时,传感器可能无法正常工作
典型读取时序代码如下:
c复制float DS18B20_ReadTemp(void) {
uint8_t tempL, tempH;
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // Skip ROM
DS18B20_WriteByte(0x44); // Convert T
delay_ms(750); // 12bit精度需要750ms
DS18B20_Reset();
DS18B20_WriteByte(0xCC);
DS18B20_WriteByte(0xBE); // Read Scratchpad
tempL = DS18B20_ReadByte();
tempH = DS18B20_ReadByte();
return ((tempH<<8)|tempL) * 0.0625; // 转换为摄氏度
}
2.2.2 心率传感器电路
采用PulseSensor光电心率传感器,电路设计要点:
- 信号放大电路增益设置为100倍左右比较合适
- 在运放输出端加RC低通滤波(截止频率约5Hz)
- 使用STM32的TIM2输入捕获功能测量脉冲间隔
实际使用中发现,运动干扰是最大挑战。我的解决方案是:
- 采用滑动窗口均值滤波(窗口大小取8个周期)
- 设置合理阈值(<40或>180的心率值自动丢弃)
- 加入信号质量检测算法(通过波形幅度和规律性判断)
2.3 通信模块设计
2.3.1 SIM800C模块电路
这个GPRS模块的电源设计最为关键:
- 必须使用能提供2A峰值电流的LDO(如LM2940)
- 在VBAT引脚就近放置1000μF+0.1μF的电容组合
- 天线接口要预留π型匹配电路便于调试
模块初始化流程:
c复制void SIM800C_Init(void) {
USART3_Init(115200); // SIM800C默认波特率
SendATCommand("ATE0\r\n", 500); // 关闭回显
SendATCommand("AT+CFUN=1\r\n",1000); // 全功能模式
SendATCommand("AT+CPIN?\r\n",500); // 检查SIM卡
SendATCommand("AT+CREG?\r\n",500); // 检查网络注册
SendATCommand("AT+CGATT=1\r\n",3000); // 附着GPRS
}
2.3.2 GPS模块接口
选用NEO-7N模块的几点考虑:
- 相比更便宜的NEO-6M,7N的冷启动时间更短(实测约25秒)
- 支持GLONASS双模定位,在城市峡谷环境下精度更高
- 功耗更低,适合电池供电设备
数据解析关键代码:
c复制void GPS_Parse(char* buf) {
if(strstr(buf, "$GPRMC")) {
sscanf(buf, "$GPRMC,%*f,%*c,%f,%*c,%f,%*c,%*f,%*f,%*d",
&latitude, &longitude);
// 度分格式转换为十进制
latitude = (int)(latitude/100) + fmod(latitude,100)/60;
longitude = (int)(longitude/100) + fmod(longitude,100)/60;
}
}
3. 软件架构设计
3.1 系统任务调度设计
采用时间片轮询架构,关键任务及其优先级如下:
| 任务名称 | 执行周期 | 最大允许耗时 | 功能描述 |
|---|---|---|---|
| 心率采集 | 20ms | 2ms | 外部中断检测+滤波 |
| 温度采集 | 10s | 500ms | DS18B20读取转换 |
| GPS处理 | 1s | 100ms | NMEA解析 |
| 数据上传 | 30s | 3s | MQTT协议打包发送 |
| 状态监测 | 60s | 50ms | 系统健康检查 |
任务调度器实现:
c复制void TaskScheduler(void) {
static uint32_t tick = 0;
tick++;
if(tick % 5 == 0) HeartRate_Task(); // 20ms (5*4ms)
if(tick % 2500 == 0) Temp_Task(); // 10s
if(tick % 250 == 0) GPS_Task(); // 1s
// ...其他任务
}
3.2 数据协议设计
3.2.1 本地数据格式
定义统一的数据结构体:
c复制#pragma pack(1)
typedef struct {
uint8_t devID[8]; // 设备唯一标识
uint32_t timestamp; // UNIX时间戳
float latitude; // 纬度(十进制)
float longitude; // 经度(十进制)
uint8_t heartRate; // 心率(bpm)
float temperature; // 温度(℃)
uint8_t battery; // 电池电量(%)
} SensorData_t;
#pragma pack()
3.2.2 MQTT通信协议
与OneNET平台对接的关键参数:
- 产品ID:在平台创建产品后获得
- 设备鉴权信息:DeviceName和AuthCode
- 发布主题:$sys/{PID}/{DeviceName}/dp/post/json
数据上传示例:
json复制{
"id": 123,
"dp": {
"temperature": [{"v": 36.5}],
"heartRate": [{"v": 72}],
"location": [{
"v": {
"lon": 116.404,
"lat": 39.915
}
}]
}
}
3.3 低功耗优化策略
通过实测发现系统主要耗电点在:
- SIM800C模块(连续工作约80mA)
- GPS模块(约45mA)
- STM32本身(约20mA)
采取的优化措施:
- 启用STM32的Stop模式,在任务间隙进入低功耗
- 动态控制GPS工作周期(静止状态每5分钟定位一次)
- SIM800C使用PSM模式(功耗可降至1mA以下)
具体实现:
c复制void Enter_LowPowerMode(void) {
// 关闭外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
// 配置唤醒源(这里用RTC每1秒唤醒)
RTC_SetAlarm(RTC_GetCounter()+1);
// 进入Stop模式
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
// 唤醒后重新初始化时钟
SystemInit();
}
4. 关键问题与解决方案
4.1 SIM800C网络不稳定的处理
在实际部署中遇到的主要问题是:
- 网络信号波动导致TCP连接频繁断开
- 某些地区2G网络覆盖差
- 模块有时会无响应
我的解决方案是三级恢复机制:
- 软件看门狗:每5秒发送AT指令检测模块状态
- 硬件复位电路:使用STM32的GPIO控制模块的PWRKEY引脚
- 备用数据缓存:在网络不可用时将数据暂存Flash
网络检测代码:
c复制uint8_t Check_SIM800C(void) {
if(SendATCommand("AT\r\n", 500) != 0) {
// 第一次失败尝试复位
SIM800C_HardReset();
delay_ms(5000);
if(SendATCommand("AT\r\n", 500) != 0) {
// 仍然失败进入错误处理
Save_ErrorLog(MODULE_SIM800C, ERR_NO_RESPONSE);
return 0;
}
}
return 1;
}
4.2 多传感器数据同步问题
当需要同时获取位置、心率和温度数据时,可能会因为采集时间差导致数据不匹配。我的处理方法是:
- 在数据结构中加入精确到毫秒的时间戳
- 采用数据快照机制:在每次上传前统一采集所有传感器数据
- 对心率数据采用预测算法补偿采集延迟
数据同步实现:
c复制void Take_SensorSnapshot(SensorData_t* data) {
uint32_t timestamp = RTC_GetCounter();
data->timestamp = timestamp;
data->heartRate = Predict_HeartRate(timestamp);
data->temperature = DS18B20_GetTemp();
GPS_GetLatest(&data->latitude, &data->longitude);
}
4.3 室外环境下的可靠性保障
经过半年实地测试,总结出以下经验:
- 防水处理:电路板喷涂三防漆,接口处用热熔胶密封
- 温度补偿:在-20℃环境下,DS18B20读数需要增加0.5℃偏移量
- 天线优化:GPS天线要远离金属物体,SIM800C天线要平行于地面
5. 系统测试与性能指标
5.1 实验室测试数据
| 测试项目 | 测试条件 | 指标要求 | 实测结果 |
|---|---|---|---|
| 定位精度 | 开阔环境 | <5m | 2.3m |
| 温度精度 | 20-40℃ | ±0.5℃ | ±0.2℃ |
| 心率误差 | 静坐状态 | ±3bpm | ±1bpm |
| 数据延迟 | 4G网络 | <10s | 平均3.2s |
| 待机时间 | 2000mAh电池 | >72h | 82小时 |
5.2 实际场景优化建议
根据养老院使用反馈,建议:
- 增加跌倒检测算法(通过加速度传感器)
- 优化报警策略(连续3次异常才触发报警)
- 加入电子围栏功能(超出设定区域自动报警)
- 改进穿戴舒适度(减小设备体积和重量)
6. 项目改进方向
6.1 硬件升级方案
下一代产品考虑:
- 主控升级到STM32L4系列,功耗降低60%
- 通信模块改用NB-IoT,解决2G退网问题
- 加入BLE接口,方便与手机直连
6.2 软件功能扩展
计划增加的功能:
- OTA远程升级(通过差分压缩技术)
- 本地语音提示(使用WT588D语音芯片)
- 运动轨迹回放(在服务器端实现)
6.3 生产优化建议
批量生产时需要:
- 设计专用测试工装(自动校准传感器)
- 优化天线匹配电路(减少人工调试)
- 建立老化测试流程(48小时连续运行测试)
这个项目从原型到量产走过了完整的产品开发流程,最大的体会是:在嵌入式系统设计中,可靠性比功能丰富更重要。特别是在医疗健康领域,任何数据错误都可能导致严重后果。因此我在软件中加入了多重校验机制,硬件上也做了充分的冗余设计。