
简介《基于STM32设计的独居老人居家监护系统》是一份面向嵌入式物联网开发者与高年级学生的完整项目方案PDF以独居老人实时健康监护为切入点覆盖了从需求分析、硬件选型到云端联动、异常报警的完整流程。该文档仅1个PDF文件包体大小52.65MB内容分为项目介绍、硬件模块组成、设计思路和模块原理几大部分重点剖析STM32F103RCT6主控与60GHz毫米波雷达在非接触式心率、呼吸检测和跌倒识别中的应用并配合MLX90614红外测温、DHT11温湿度、MQ7一氧化碳传感器综合监测老人体温与居住环境。文档还给出了WiFi模组接入腾讯物联云平台、微信小程序远程显示、阈值预警推送、蜂鸣器报警及1.44寸TFT LCD本地展示等关键环节的实现思路图文结合便于理解系统架构和信号流程可直接用于毕业设计、课程项目或相关产品预研。目前已有281人学习下载是一份值得参考的智慧养老方向嵌入式方案。 一句话点明核心这套系统就是“STM32做主控采集健康数据微信小程序做远程查看和报警”。没有高大上的新技术但把硬件、无线通信、云端、小程序这四块串起来之后就是一个能实际落地、能随时看数据、关键时刻能救命的完整产品原型。做这套系统核心既要解决“采集准不准”的硬件问题更要解决“全家人都能方便看到”的软件问题。我见过不少类似方案有的纯做硬件串口屏数据只能在家看有的只做App硬件端却过于简陋。这套方案的好处在于微信小程序是所有人都能接受、能快速上手的最短路径老人子女不习惯装专业App但微信人人都有。整个系统的价值就在于把“监测”真正变成“守护”让数据流从传感器一直流到远在千里之外的子女手机上。不管你准备拿它当毕设、课程设计还是家里有老人想自己搞一套这个项目的核心思路都值得参考。接下来我会从方案选型、硬件电路、WiFi通信、小程序开发到联调测试一条线走一遍把我们做的时候的思路、踩过的坑、最终的代码逻辑都拆开来看。1. 内容整体设计与思路拆解1.1 为什么选STM32而不是ESP32或Arduino很多人在知乎上问“做物联网项目是不是用ESP32更简单”确实ESP32自带WiFi和蓝牙代码也更简洁。但这个项目的关键点在“监护系统”四个字稳定性和低功耗才是第一优先级而不是开发速度快。STM32F103C8T6即所谓“蓝板”作为主控的好处非常明显外设资源丰富ADC、I2C、USART、定时器都齐全挂载多个传感器时不用挤接口工业级可靠性远强于Arduino长时间7x24小时运行时不容易出莫名其妙的死机问题生态成熟Keil、HAL库的资料非常多真遇到问题搜解决方案很快。对比下来ESP32适合Demo演示STM32适合真正的产品雏形。说句公道话ESP32本身也没问题但作为“基于STM32的毕业设计/课程设计”这个定位来说STM32方案在答辩时也更“能打”——因为可以有丰富的底层原理去讲从寄存器配置到中断优先级都能展开评委不容易问倒你。1.2 端-云-小程序三层架构拆解整套系统的数据流向是这样传感器心率/血氧/体温/姿态→ STM32采集与算法判断→ ESP8266WiFi透传→ MQTT云服务器 → 微信小程序实时显示与告警这个三层架构是当前IoT应用最常见的“三段式”感知层硬件端、传输层WiFiMQTT、应用层小程序。每层各司其职层与层之间通过标准协议衔接好处是后续换任何一层都不影响其他层。感知层选了四个核心传感器MAX30102心率血氧、DS18B20体温、MPU6050姿态/跌倒检测、DHT11温湿度监测老人居住环境。前三个是健康指标的“刚需”DHT11是锦上添花能顺带看看家里是否过于闷热或潮湿。传输层用的是ESP8266串口WiFi模块走MQTT协议接入云服务器。这里没有去选最新的ESP32-C3或者4G Cat.1模块原因很简单ESP8266模块成本只要十几块钱资料遍地都是作为传输任务完全够用。数据上报格式用JSON方便小程序端直接解析。应用层是微信小程序原生开发不用uni-app的原因主要是这个项目里小程序只需要做几件事——展示数据、接收告警、绑定设备、查看历史没有跨端需求原生开发更轻量、工具链更简单。2. 硬件端核心实现传感器选型与数据采集2.1 核心传感器详细参数与接口设计先从电路设计开始。这套系统里STM32F103C8T6的引脚分配是我们反复调整过的最终定稿如下外设通信接口STM32引脚说明MAX30102I2C1PB6(SCL)、PB7(SDA)心率血氧采集地址0x57MPU6050I2C1PB6(SCL)、PB7(SDA)复用六轴姿态地址0x68DS18B20单总线PB1体温采集需4.7k上拉DHT11单总线PB0环境温湿度需5k上拉ESP8266USART2PA2(TX)、PA3(RX)WiFi透传波特率115200OLEDI2C1PB6(SCL)、PB7(SDA)复用本地显示地址0x3C蜂鸣器GPIOPA8异常报警高电平触发按键GPIOPA0取消误报、切换显示页面这里有个很关键的设计细节MAX30102、MPU6050和OLED共用同一路I2C总线。I2C本身就是总线型协议从设备通过地址区分所以只要每个器件的7位地址不冲突时序满足要求就能挂在同一条总线上。实际测试下来三个器件地址分别为0x57、0x68、0x3C没有冲突I2C速率设置为400kHz快速模式时通讯都很稳定。单总线的DS18B20和DHT11分别占用了两个引脚没有复用原因是这两款器件对时序非常敏感串扰会导致读取失败。DHT11在之前的项目中经常出现偶发读不到数据的情况检查发现就是因为它和DS18B20共用引脚、时序互相干扰。这次干脆分开彻底解决。2.2 健康数据采集的关键技术细节MAX30102的血氧计算是整套系统里技术含量最高的部分。这款传感器内置红光和红外光两个LED利用血氧饱和度不同时氧合血红蛋白和还原血红蛋白对两种光的吸收率不同这一原理计算出SpO2值。硬件I2C读取原始FIFO数据后还需要做滤波和比值计算核心公式R (AC_red / DC_red) / (AC_ir / DC_ir) SpO2 110 - 25 * RAC分量交流成分对应脉搏波动引起的吸光度变化DC分量直流成分对应组织吸收的基线。实际代码里还要做滑动平均滤波去掉工频干扰和运动伪迹。我们使用的滑动窗口是15个采样点超过窗口期后自动更新这样心率数值不会剧烈跳变显示在界面上观感更平滑。心率计算方式是在时域里检测脉搏波的峰值间隔两个R波峰之间的时间间隔的倒数乘以60就是每分钟心率。用STM32的定时器计时精度可以达到微秒级实际测下来静坐状态误差在正负3次/分以内运动状态误差会大一些但作为监护用途足够。DS18B20就简单直接单总线读出来的12位温度数据分辨率为0.0625摄氏度。需要注意单总线的时序要求极其严格最好关掉中断再操作否则会被系统中断干扰导致读回FF传感器未响应。我在代码里专门加了一个临界区保护实测连续读1000次没有一次失败。2.3 跌倒检测算法与误报抑制跌倒检测是这个系统最核心的“救命功能”算法思路其实不难难在怎么降低误报率。MPU6050输出的三轴加速度值我们先计算合成加速度mag sqrt(ax^2 ay^2 az^2)正常静止时mag接近1g约9.8m/s²人的活动时在1到2g之间波动。跌倒过程有一个非常明显的特征先出现短暂失重mag骤降到0.4g以下紧接着出现剧烈撞击mag猛增到2.5g到4g以上之后人躺在地上合成加速度回到接近1g并且人体姿态角度与跌倒前有显著变化。算法上做三级判断合成加速度小于0.4g持续200ms以上判定进入“失重状态”失重状态结束后的500ms内合成加速度超过3g判定为“撞击状态”撞击后2秒内Z轴加速度分量占比小于0.5即人体基本水平判定为跌倒三个条件缺一不可否则就可能是弯腰捡东西、坐下猛了点、或者拍打震动只满足其中一两个条件不能触发报警。实测下来正常走路、上下楼、坐下起身的误报率控制在一天一到两次以内这些误报前端老人端会通过“按按键取消”的方式来规避。一旦判定为跌倒STM32立刻做三件事本地蜂鸣器响起音量约80dB能传到隔壁房间、OLED屏幕弹出“检测到跌倒”提示、通过ESP8266发布一条告警消息到MQTT主题同时在主题里带上老人的定位信息。这样即使老人已经没法操作手机子女端也能第一时间收到推送。3. ESP8266通信链路与MQTT对接3.1 AT指令透传与数据格式设计ESP8266在这里承担“网桥”角色STM32通过串口发AT指令ESP8266连接WiFi、建立TCP连接、发布/订阅MQTT消息。如果不想使用AT指令也可以用SDK直接二次开发ESP8266但那样会占用额外的工作量而且AT指令已经足够稳定完全没必要把事情复杂化。实际项目里最核心的AT指令事件序列ATRST // 复位模块 ATCWMODE1 // Station模式连外部路由 ATCWJAPWiFi名称,WiFi密码 // 连接无线路由 ATMQTTUSERCFG0,1,client_id,user,pass // 配置MQTT用户名密码1表示使能 ATMQTTCONN0,broker地址,1883,1 // 建MQTT连接 ATMQTTSUB0,topic/data/设备id,1 // 订阅下发消息 ATMQTTPUB0,topic/data/设备id,payload,1,0 // 发布数据QoS1这套指令看起来多但建立连接只要3秒左右。为了提高上报频率和稳定性我们专门写了一个MQTT状态机启动时连接WiFi然后连MQTT如果中途通信失败先自动重连MQTT再不行就重新连WiFi每30秒检查一次链路状态。3.2 心跳保活与断线自动重连WiFi模块最忌讳的一点就是“悄悄掉线”。ESP8266在长时间通信后偶尔会死掉为了及时感知并及时恢复我这里做了三个层面的保障第一层是STM32每5秒通过串口向ESP8266发送一次“ATMQTTSTAT0”查询MQTT连接状态如果返回“MQTTSTAT:0,CONNECTED”说明正常第二层是MQTT协议层的Keep Alive机制每60秒发一次心跳包服务器超过120秒未收到心跳就断开连接此时ESP8266会返回“ERROR”或者“MQTTDISCONNECTED”消息触发STM32侧的重连逻辑第三层就是最终兜底方案——如果连续3次查询都没有响应STM32会重启ESP8266模块通过控制ESP8266的EN引脚拉低再拉高实现硬件复位然后自动重走一遍AT指令流程。实时数据上报的心跳内容用JSON格式封装{device_id:A001,heart_rate:72,spo2:98,temperature:36.5,fall_detected:0,time:1735107200}这个格式兼顾了可读性和解析效率小程序端拿到后直接用JSON.parse就能取值。数据里的时间戳是Unix时间戳格式由ESP8266从NTP服务器同步这样小程序端不需要重新对时。3.3 数据上行与下行告警消息推送告警消息链路的优先级和处理方式是整个项目里我总结出来最关键的地方。正常心跳数据5秒一条走QoS 0最多一次丢了也就丢了下一轮还能采上来。但跌倒告警这种“生死攸关”的消息必须走QoS 1至少一次确保服务端能收到同时小程序端在收到告警后会主动发给手机通知栏。MQTT发布告警消息的格式{type:fall_alarm,device_id:A001,time:1735107290,location:客厅}小程序端通过WebSocket接入MQTT收到type为fall_alarm的消息后立刻调起微信订阅消息推送来电话/弹窗提醒、跳出红色告警页面、连续震动手机。这一步用户体验我们反复打磨过但告警听了必须响起来而且是那种打断了也要响——从技术上保证即使把小程序退到后台告警也能通过“订阅消息”通道触达用户。4. 微信小程序端开发实战4.1 小程序架构与页面设计微信小程序端我使用原生框架开发WXMLWXSSJS整体分四个Tab页页面功能首页实时显示心率、血氧、体温、环境温湿度、跌倒状态设备绑定新设备、查看设备在线状态、修改设备备注名历史按时间范围展示健康数据曲线、查询告警记录我的老人个人信息、紧急联系人、消息通知设置首页设计的原则是“一眼看清状态”所有核心指标用大号数字显示正常时背景为白色告警时整个页面背景瞬间变为红色同时心跳数字放大闪烁让人即使隔两米远也能注意到异常。历史数据曲线用的是小程序原生组件ec-charts封装的echarts从微信官方市场插件引入。echarts体积比较大小程序包体有限制主包2MB所以必须按需引入组件我们只引用了折线图组件包体控制在700KB左右完全没问题。实时数据展示有两条路径主动拉取和被动订阅。在小程序被切到后台超过30秒之后MQTT连接会被微信回收这时候打开小程序要重新建立连接。我们处理办法是首页onShow时检测WebSocket状态断开则重连重连成功后主动发一条“get_latest_data”消息给设备端设备端收到后立刻回传最新的传感器数据保证用户打开小程序看到的一定是此刻最新的状态而不是重新连接期间的空白。4.2 蓝牙配对与设备绑定逻辑备选方案原方案里设备绑定是通过WiFi模块直接上报设备ID来完成的但很多实际使用场景里家里根本没路由器或者WiFi信号不稳。为了鲁棒性我们还加了一条“蓝牙配置设备绑定”的备选链路。STM32端增加HC-05蓝牙模块串口透传9600波特率小程序通过微信蓝牙API搜索附近的HC-05进行配对然后把WiFi的SSID和密码写进STM32的Flash中。相当于把“配网”这个动作从电脑上搬到了手机里老人子女到家里打开小程序扫码蓝牙自动连接配置WiFi设备重启后自动上网。这一套流程大概两分钟搞定不需要任何电脑操作。绑定逻辑核心代码如下逻辑wx.openBluetoothAdapter({ success: function(res) { wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false, success: function(res) { // 扫描到目标设备后 wx.createBLEConnection({ deviceId: deviceId, success: function(res) { // 写入WiFi配置数据到STM32的写特征 writeDataToDevice(wifiSSID ; wifiPassword) } }) } }) } })因为STM32的USART2同一时间只给一个外设用要么ESP8266、要么HC-05代码里通过一个标志位来切换未配网模式串口2自动接管HC-05接收蓝牙数据配网完成后自动把串口2切回ESP8266。这个小技巧帮我省掉了硬件上的一套模拟开关。4.3 告警订阅消息与多方通知实现微信小程序的“订阅消息”能力是告警功能落地的关键。这里的坑在于订阅消息是一次性的用户订阅一次只能接收一条各有各的限制。最稳妥的办法是在用户正常使用小程序时主动引导点击“允许告警通知”一次性订阅多次“总是保持以上选择不再询问”的开关否则当真正发生跌倒告警时小程序就推送不出去了。订阅消息代码模板wx.requestSubscribeMessage({ tmplIds: [告警模板ID_主告警, 告警模板ID_低电量], success: function(res) { // 用户点同意后 console.log(订阅成功) } })这里需要注意requestSubscribeMessage必须在用户点击行为tap的回调里调用不能在页面加载时直接调用这是微信的限制。我们把“开启告警”做成一个按钮用户点击后触发订阅弹窗用户同意后就不管了。当MQTT收到fall_alarm消息时小程序端调用云函数通过微信服务端接口发送订阅消息给“紧急联系人”。紧急联系人可以绑定多位比如老人的儿子和女儿同时接收。云函数代码如下const cloud require(wx-server-sdk) cloud.init() exports.main async (event, context) { const { openid, data } event try { const result await cloud.openapi.subscribeMessage.send({ touser: openid, templateId: 告警模板ID_主告警, page: pages/index/index, data: { thing1: { value: 老人疑似跌倒 }, time2: { value: new Date().toLocaleString() }, thing3: { value: 请立即确认 } } }) return result } catch (err) { return err } }云函数用微信官方的云开发能力直接在小程序开发者工具里写就行不需要自己买服务器。5. 联调测试与常见问题排查实录5.1 通信链路与数据准确性验证整个系统做完后联调阶段是最磨人的。这里记录几个我们实测中遇到的典型问题和解决方案问题1STM32与MAX30102通信失败I2C读取返回0xFF排查思路MAX30102是1.8V逻辑电平芯片但STM32的I2C引脚是3.3V电平直接连接会读不到数据甚至可能烧坏传感器。解决方法是加一个I2C电平转换模块如PCA9306或者选用带电平转换的MAX30102模块大多数销售模块都会自带电平转换和大的上拉电阻但便宜模块可能会偷工减料。我们实际用的模块是自带3.3V稳压和电平转换的那种买的时候留意一下就OK。问题2ESP8266频繁掉线MQTT连不上这个问题的元凶往往只有一个电源电流不够。ESP8266在WiFi发射瞬间电流峰值可达300-500mA如果和STM32共用同一个LDO稳压芯片常见的是AMS1117-3.3最大输出电流1A但实际长时间工作到800mA就会发热电压跌落会导致WiFi模块重启。解决方案STM32和ESP8266分开供电ESP8266用独立的AMS1117-3.3输入5V由USB提供同时并联一个470uF的电解电容做储能缓冲。改完之后掉线频率从每小时几次降到了几乎为零。问题3小程序端收不到实时数据排查后发现原因很简单微信小程序不支持直接解析MQTT over TCP因为微信的网络API只支持HTTP和WebSocket所以我们是把“MQTT代理”部署在云函数或者使用云开发自带的实时数据推送能力。简单方案硬件端发布到MQTT Broker云函数通过MQTT.js订阅同一个主题收到消息后写入云数据库的“实时状态”集合小程序端用云开发数据watch监听这个集合的变化一旦有新数据前端自动刷新。这样绕开了小程序不支持裸TCP的问题可靠性也没有打折扣。5.2 低功耗优化与续航测试如果监护设备用的是电池供电比如老人腰挂式设备功耗就是绕不开的话题。STM32F103C8T6正常工作电流约20-30mAMAX30102约10-20mAMPU6050约4mAESP8266平均约70mA峰值300mAOLED约20mA。全部开启的情况下系统总电流约120-150mA如果使用18650锂电池容量2600mAh满打满算只能跑17-20小时完全不够。实测后我们通过三招把平均功耗降低到约30mA左右18650电池可以撑3天以上如果用两节并联可以到一周。第一招是“间歇采集”心率血氧每一分钟采集一次每次采集10秒得到稳定值后立刻关掉MAX30102的LED而不是7x24小时全速运转。MPU6050保持常开用于跌倒检测但它电流只有4mA可接受。第二招是“OLED定时关闭”平时默认不亮屏只有按键按下或者发生告警时才点亮20秒。第三招是“ESP8266睡眠”STM32通过GPIO控制ESP8266的RST引脚只在需要上报数据时才给ESP8266上电。具体做法是每次上报前让ESP8266掉电5秒再上电连接WiFi和MQTT再上报整个过程约3秒相比一直在线电流消耗大幅下降。代价是“实时在线率”没那么高了如果数据每隔一分钟上报一次完全够用。5.3 告警消息可靠性与误报处理告警是救命功能宁可多报也不能漏报但每天误报十几次老人子女会把手机调成静音的。我们实测时误报率最高的场景就是老人弯腰捡东西、猛然坐下、或者拍打床板。针对这些场景调整了算法参数失重阈值从0.4g提高到0.35g失重持续时间从200ms提高到300ms进一步过滤掉弯腰这类失重时间较短的动作加入“跌倒后5秒内角度几乎不再变化”的条件确保是摔倒后“躺平”了才报如果老人摔倒后立刻自己站起来就不算最终确认在确认报警前给老人10秒的“取消窗口”设备端发出“滴滴”警示音老人如果没摔倒可以按键取消这个窗口比直接推送给子女要人性化得多。即使到了“三重判断取消窗口”的程度还是会有少量误报进入小程序端。所以小程序端增加了一个“误报反馈”按钮子女端收到告警后可以点“不是跌倒标记误报”这个反馈会通过MQTT回传给STM32有效的继续学习更好的优化本地侧报警策略形成正向循环。6. 项目复盘与后期扩展方向这套系统从画板子、调传感器到小程序上线前后花了大概三周时间核心代码量加起来不到两千行。最大的收获不是功能本身而是打通了“硬件-IoT-小程序”这条完整链路里面任何一个环节单独拿出去都能在工程领域派上用场。如果你打算复制这个项目我的建议是按“最小可用系统”来规划第一步先不考虑低功耗不考虑外观直接把传感器、主控、WiFi、小程序的最小链路调通哪怕数据是乱的也行。链路通了再加算法、加优化、加外观成功率会高很多。另外说句心里话这类系统最大的价值在于真正长期稳定运行的能力而不是Demo效果。我这边已经连续运行了几个月偶尔仍然会有传感器偶发读不到、ESP8266掉线等小问题。所以如果做到产品级建议把传感器从MAX30102换成工业级的方案网络端从WiFi换到Cat.14G LTE-M板子走正规Layout、加外壳、过EMC测试这些就是另一个维度的事情了但基本构架不会变。如果你也对硬件IoT和微信小程序开发的结合感兴趣建议从这套方案入手把技术链路吃透之后再按自己需求扩展比如增加服药提醒、语音交互、睡眠监测都不会太难。周末在家跑通第一版的时候那种“数据真的从传感器里一路蹦到我手机屏幕上”的成就感确实很值得体验一次。本文还有配套的精品资源点击获取