基于STM32WL与LoRa的远程患者监护系统:硬件设计、算法实现与嵌入式开发全解析
1. 项目概述:一个基于LoRa的远程患者监护原型
最近我完成了一个很有意思的硬件原型项目:一个基于LoRa无线通信的可穿戴式患者监护设备。这个项目的核心想法,是解决那些身处偏远地区、或者需要居家康复的患者的远程生理指标监测问题。想象一下,如果患者能佩戴一个轻便的设备,医护人员就能在几公里甚至更远的指挥中心,实时看到他们的心率、血氧、体温和活动状态,这不仅能提升医疗服务的可及性,也能让患者的生活质量得到改善。
这个原型设备集成了脉搏血氧传感器、六轴惯性测量单元和温度传感器,通过STM32WL系列微控制器进行数据采集和初步处理,然后利用其内置的Sub-GHz射频模块,以LoRa方式将数据发送出去。LoRa技术的特点是低功耗和远距离通信,非常适合这种需要长时间佩戴、且通信基础设施可能不完善的场景。我在这个项目中,不仅完成了硬件搭建和嵌入式软件开发,还深入研究了从原始光电容积脉搏波信号中提取心率和血氧饱和度值的算法,整个过程充满了挑战和乐趣。
接下来,我会把这个项目的完整实现过程拆解开来,从硬件选型、电路连接,到软件架构、信号处理算法,再到最后的LoRa通信配置和实测效果,毫无保留地分享给大家。无论你是嵌入式开发者、物联网爱好者,还是对医疗电子感兴趣的朋友,相信都能从中获得一些实用的参考。
2. 硬件设计与核心器件选型解析
2.1 主控平台:为什么选择STM32WL55JC?
这个项目的核心大脑是ST Microelectronics的NUCLEO-WL55JC1开发板。选择它,主要基于三个关键考量:
高度集成,节省空间与功耗:STM32WL55JC这颗MCU最大的亮点,是单芯片集成了Cortex-M4内核和一个Sub-GHz的LoRa射频收发器。对于可穿戴设备来说,这意味着我们不需要再外挂一个独立的LoRa模块,极大地简化了PCB布局,减少了整体尺寸,并且由于芯片内部互联,通信功耗也更低。这对于追求小型化和长续航的可穿戴设备来说是决定性优势。
丰富的生态与开发便利性:NUCLEO开发板提供了完整的调试接口和Arduino兼容接口,极大降低了前期原型开发的难度。ST的CubeMX和HAL库使得外设(如I2C、SPI、定时器)的初始化变得可视化且高效,让我能把更多精力集中在应用逻辑和算法上。
符合项目需求的计算能力:M4内核带FPU,足以胜任实时的信号滤波、移动平均计算、以及心率和血氧的初级算法(边缘计算)。我们不需要把原始数据一股脑全发到云端,可以在本地先进行预处理和特征提取,只上传关键指标和异常警报,这既节省了无线通信的能耗,也降低了对云端算力的依赖。
注意:STM32WL系列有多个子型号,主要区别在于内存大小和射频功率。WL55JC的256KB Flash和64KB RAM对于这个原型应用绰绰有余。如果你的应用需要更复杂的算法或存储更多历史数据,可以考虑WL55JCU6(带512KB Flash)。
2.2 传感器套件:生理数据的来源
传感器的选型直接决定了数据的质量。我选择了市场上成熟且易于获取的模块化方案。
MAX30102 脉搏血氧与心率传感器:这是项目的核心传感器。它内部集成了红光(660nm)和红外光(880nm)LED、光电探测器、环境光消除电路以及ADC。其原理是光电容积脉搏波描记法:血液对红光和红外光的吸收率会随着心脏搏动引起的血容量变化而变化。通过分析这两种光信号的交直流分量,就能推算出心率和血氧饱和度。选择它的原因在于其集成度高,提供了完整的I2C数字接口,无需自己设计复杂的光路和模拟前端电路。
WSEN-ISDS 六轴IMU:我选用的是Würth Elektronik的这款三轴加速度计+三轴陀螺仪。它的作用有两个:一是监测患者的身体活动(静止、行走、跌倒),二是辅助计算呼吸率。胸部或腹部的起伏会带来特定的加速度变化模式,可以通过算法从中提取呼吸频率。这款传感器同样通过I2C通信,功耗极低,非常适合可穿戴设备。
其他外围器件:
- OLED显示屏:一块128x64的单色OLED,用于本地显示关键生理参数,让佩戴者或身边的护理人员能直观看到数据。它通过I2C驱动,节省IO口。
- 压电蜂鸣器:用于本地声音警报,例如当检测到心率异常或设备脱落时。我使用MCU的一个定时器通道产生4kHz的PWM方波来驱动它。
- 电压调节:由于开发板只提供3.3V和5V的有限输出能力,为了给所有外设稳定供电,我在面包板上额外使用了LDO线性稳压芯片,将输入电压(如USB的5V)分别稳压至5.0V和3.3V,确保各器件工作电压准确。
2.3 硬件连接与供电设计
所有传感器和显示屏都挂载在同一个I2C总线上,这大大简化了布线。STM32WL55的I2C3接口(PB13: SCL, PB14: SDA)被用于此目的。每个I2C设备都有唯一的地址,在软件中通过地址进行区分。
具体的引脚连接如下表所示:
| NUCLEO-WL55JC1 连接器/引脚 | MCU 引脚 | 外设 | 信号/功能 |
|---|---|---|---|
| CN7 Pin 16 | VDD | 电源分配 | +3.3V 输出 |
| CN7 Pin 18 | - | 电源分配 | +5.0V 输入(来自USB或外部) |
| CN7 Pin 20, 22 | VSS | 电源分配 | GND |
| CN7 Pin 28 | PB1 | OLED RESET | 显示屏复位控制 |
| CN7 Pin 36 | PB14 | I2C3 SDA | I2C 数据线 |
| CN7 Pin 38 | PB13 | I2C3 SCL | I2C 时钟线 |
| CN10 Pin 16 | PA8 | 压电蜂鸣器 | TIM1_CH1 PWM 输出 |
实操心得:在面包板上搭建复杂系统时,电源去耦至关重要。我在每个传感器的VCC和GND引脚附近都放置了0.1uF的陶瓷电容,以滤除高频噪声,这对MAX30102这种模拟-数字混合的传感器尤其重要,能显著提高信号稳定性。同时,为I2C总线的SDA和SCL线加上拉电阻(通常4.7kΩ到10kΩ)是必须的,否则通信会失败。
3. 嵌入式软件架构与核心模块实现
3.1 分层软件架构设计
为了保持代码的清晰、可维护和可移植性,我采用了分层的软件架构。每一层只与相邻的上下层进行交互,降低了模块间的耦合度。
硬件抽象层:这一层直接操作STM32的HAL库函数,封装了最底层的硬件操作,例如初始化I2C、读取特定寄存器、配置定时器产生PWM等。它为上层提供了统一的硬件访问接口。
驱动程序层:在这一层,我为每个外设编写了独立的驱动文件。例如max30102.c/.h,wsent_isds.c/.h,oled.c/.h。这些驱动文件基于硬件抽象层提供的接口,实现了传感器特定的功能,如配置MAX30102的采样率、LED电流,读取WSEN-ISDS的加速度原始值,或在OLED上绘制字符和图形。
应用逻辑层:这是业务逻辑的核心。它调用驱动程序层获取原始数据,然后运行信号处理算法(如计算心率、血氧),实现状态机管理(如设备启动、测量、休眠、报警等状态),并决定何时、以何种格式通过LoRa发送数据。
通信协议层:专门处理LoRa无线通信的配置、数据打包、发送和接收。它依赖于STM32WL的Sub-GHz射频库,将应用层整理好的数据封装成特定的帧格式,通过无线电波发送出去。
这种分层结构的好处是,如果未来需要更换传感器(比如换用MAX86150),我只需要替换对应的驱动层文件,应用层和通信层的代码几乎不需要改动。同样,如果更换通信方式(比如增加蓝牙),也只需在通信层进行扩展。
3.2 Sub-GHz射频模块的配置难点与解决方案
让STM32WL55的内置LoRa射频模块正常工作,是整个项目中最具挑战性的部分之一。ST官方提供的CubeMX示例大多基于一个复杂的调度器框架,理解和使用起来门槛较高,而且通常需要两块开发板进行对等通信。
为了简化,我决定采用低层驱动程序直接配置射频模块。核心步骤基于Semtech SX126x系列芯片的驱动(STM32WL55集成的是SX126x的IP核)。关键配置如下:
射频参数设定:这些参数直接决定了通信距离、速率和抗干扰能力。经过测试,我选择了以下一组平衡性能与可靠性的配置:
- 频率:915 MHz(根据所在地区的无线电法规选择,例如欧洲是868 MHz)。
- 扩频因子:11。较高的扩频因子能提升接收灵敏度(传得更远),但会降低数据速率。对于每秒仅发送几十字节的生理数据,SF11是个好选择。
- 带宽:500 kHz。带宽越宽,数据速率越高,但接收灵敏度会略有下降。500kHz在SF11下提供了不错的速率。
- 编码率:4/8。前向纠错编码率,4/8提供了较强的纠错能力,适合可能受干扰的环境。
- 前导码长度:12个符号。足够让接收机可靠地检测到信号。
数据包格式:我自定义了一个简单的数据帧结构,包含帧头、设备ID、各种传感器数据(心率、血氧、温度、加速度值)、CRC校验和帧尾。CRC校验对于无线通信的可靠性至关重要。
发送流程:应用层需要发送数据时,会触发一个中断或标志。通信层将数据打包,然后通过HAL库函数将数据加载到射频模块的发送缓冲区,设置发射功率(例如+14 dBm),最后启动发送。发送完成后,射频模块会产生中断通知MCU。
踩坑记录:最初调试时,接收端完全收不到数据。排查后发现,STM32WL的射频部分和MCU内核共用一些资源(如SPI),配置时序非常关键。必须严格按照数据手册的步骤:先让射频模块进入待机模式,然后进行参数配置,再切换到发送或接收模式。直接操作而忽略状态切换是常见错误。另外,天线匹配电路对性能影响巨大,在最终产品中需要根据PCB布局进行精细调试。
3.3 数据采集与传感器驱动
所有传感器都通过I2C总线轮询。为了不阻塞主循环,我使用了定时器中断来触发数据采集周期。例如,设置一个1ms的定时器中断,在中断服务例程中维护一个时间戳,每满33ms(约30Hz)就置位一个“采集标志”。主循环中检测到这个标志,就依次读取MAX30102和WSEN-ISDS的最新数据。
MAX30102驱动关键点:该传感器有多个FIFO缓冲区。我将其配置为SPO2模式,使红光和红外光LED交替点亮,并将采样数据存入一个深度为32的FIFO。我的驱动会定期(如1ms)检查FIFO中有多少新数据,一旦有足够的数据(比如4个样本),就一次性读出,这样可以减少I2C通信次数,提高效率。
WSEN-ISDS驱动关键点:需要正确配置量程(例如加速度±4g,陀螺仪±500 dps)和输出数据速率。为了降低噪声,我启用了传感器内部的低通滤波器。
4. 核心算法:从原始信号到生理参数
这是整个项目技术含量最高的部分,即将MAX30102采集到的原始光信号,转化为有意义的心率和血氧饱和度数值。
4.1 信号预处理与滤波
原始的红光和红外光信号包含有用的脉搏波成分(AC)和由组织、骨骼等静态组织吸收产生的直流分量(DC),还混杂着运动伪影和环境光噪声。
直流分量移除:首先,我需要分离AC和DC。我使用了一个长度为N(例如50,对应约1.5秒数据)的环形缓冲区来计算每个信号的移动平均,这个移动平均值就近似为DC分量。将原始信号减去其对应的DC分量,就得到了纯净的AC脉搏波信号。
AC_red = Raw_red - DC_red,AC_ir = Raw_ir - DC_ir带通滤波:脉搏波信号频率通常在0.5 Hz到4 Hz之间(对应心率30到240 BPM)。我设计了一个数字带通滤波器(例如二阶巴特沃斯滤波器)来滤除高频噪声(如肌肉颤动)和极低频漂移。在嵌入式端,我采用了直接II型转置结构的滤波器,计算效率较高。
4.2 心率计算原理与实现
心率检测的本质是寻找脉搏波信号的峰值或特征点。我采用了基于导数的方法,因为它对波形幅度的变化不敏感,更稳定。
计算微分:对滤波后的红光AC信号(通常红光信号更强)计算离散微分,即
diff[n] = signal[n] - signal[n-1]。这得到了信号的变化率。寻找心跳点:观察发现,在心电图的R波对应脉搏波的快速上升沿,其微分会有一个显著的负向尖峰(因为上升沿的末端斜率由正变负)。我设置一个动态阈值,当微分信号超过(更负于)这个阈值时,就认为检测到一个心跳。
计算心率:记录连续两个心跳点之间的时间间隔(ΔT)。心率(HR)计算公式为:
HR = 60 / ΔT(单位:bpm,每分钟心跳次数)。为了结果平滑,我同样使用了一个环形缓冲区来存储最近几次计算出的心率值,然后取平均作为最终输出。
4.3 血氧饱和度计算原理与实现
血氧饱和度(SpO2)的计算基于一个关键的生理现象:含氧血红蛋白和脱氧血红蛋白对红光和红外光的吸收率不同。
计算“比值之比”:首先,需要计算红光和红外光AC分量与DC分量的比值。这个比值反映了脉搏波引起的吸光度变化。
R = (AC_red / DC_red) / (AC_ir / DC_ir)这个R被称为“比值之比”。线性回归模型:研究表明,在一定的饱和度范围内(通常70%-100%),SpO2与
R存在近似的线性关系:SpO2 = A - B * R。其中A和B是常数,需要通过校准确定。校准与实现:Maxim和TI的应用笔记提供了典型的A、B值作为起点。在我的实现中,我使用了一个商业指夹式脉搏血氧计作为参考,同步采集数据,通过线性回归拟合出我当前硬件配置(LED亮度、传感器贴附程度等)下的A和B值。在代码中,我持续计算红光和红外光信号的AC有效值(RMS)作为AC分量,DC分量则用移动平均,然后实时计算R值并代入公式得到SpO2估算值。
重要提示:这里计算出的SpO2是估算值。医用级设备需要进行严格的临床校准,补偿皮肤颜色、组织厚度、灌注指数等多种因素。本原型机的算法是高度简化的,绝对不可用于任何医疗诊断,其价值在于演示原理和可行性。
4.4 呼吸率与活动状态估算
利用WSEN-ISDS的加速度计数据,可以粗略估算呼吸率。当传感器放置在胸部时,呼吸运动会在垂直于胸壁的加速度轴上产生周期性的低频信号(约0.1-0.5 Hz)。通过对该轴加速度数据进行带通滤波(例如0.1-0.5 Hz),然后进行峰值检测,即可估算呼吸频率。
活动状态则通过分析三轴加速度的合向量大小和方差来判断。静止时,合向量大小约等于1g(重力加速度),且方差小;行走或活动时,合向量会波动,方差增大。通过设定阈值,可以简单区分“静止”、“行走”、“可能跌倒”等状态。
5. 系统集成、测试与性能评估
5.1 原型机整合与工作流程
将所有模块整合后,设备的工作流程如下:
- 上电初始化:显示启动画面,初始化所有传感器、OLED、LoRa射频模块。
- 主循环: a.数据采集:定时从MAX30102和WSEN-ISDS读取原始数据。 b.信号处理:运行滤波、心率/血氧/呼吸率计算算法。 c.本地显示与警报:将关键指标刷新到OLED屏幕上。如果某项指标超出预设的安全范围(如心率<50或>120),则触发蜂鸣器报警。 d.数据上传:每秒将处理后的数据(心率、血氧、温度、活动状态)打包,通过LoRa无线发送一次。 e.串口调试:通过USB虚拟串口,以30Hz的速率输出所有传感器的原始数据,供PC端的上位机软件(如串口绘图器)进行可视化调试。
5.2 LoRa接收端的搭建
为了验证发射端,我搭建了一个简单的LoRa接收机。它由以下部分组成:
- 核心板:一块常见的“Blue Pill”(STM32F103C6最小系统板),成本低廉。
- LoRa模块:采用基于Semtech SX1276芯片的模块(如RFM95),工作在915MHz。
- 连接逻辑:STM32F103通过SPI接口与SX1276通信,并将接收到的数据通过UART发送到FTDI USB转串口模块,最终在PC的串口助手上显示。
接收端的软件基于开源的arduino-LoRa-STM32库修改,主要修改了射频参数(频率、扩频因子、带宽等),使其与发射端(STM32WL55)的配置完全匹配。
5.3 性能测试与结果分析
为了评估原型的性能,我进行了一项关键对比测试:将我的设备和一个经过认证的商业指夹式脉搏血氧计,同时戴在同一根手指的不同指节上,进行同步测量。
测试方法:让测试者静坐,记录两分钟内的数据。我的设备每秒记录一次计算出的心率和SpO2值,商业设备则观察其稳定后的读数。
结果:如下图所示,横轴为时间,纵轴分别为心率和血氧值。蓝色圆点代表我的原型机数据,橙色虚线代表商业设备的读数。 (此处为描述,实际报告中应插入对比图表) 从趋势上看,两者在心率变化上表现出良好的一致性,在静息状态下误差通常在±3 BPM以内。血氧饱和度值也呈现出相似的稳定性和变化趋势,尽管绝对值上可能存在几个百分点的系统偏差。
分析:
- 心率:算法检测到的R-R间期与商业设备的心跳触发点高度相关,证明基于导数的心跳检测算法是有效的。
- 血氧:存在的系统偏差可能源于多个因素:1) 算法中使用的线性回归系数A、B未经个性化校准;2) 传感器贴附压力、环境光的影响;3) 商业设备使用了更复杂的算法和校准曲线。但这证明了从PPG信号中提取SpO2的可行性。
局限性:
- 测试仅在静息状态下进行。运动伪影会严重干扰PPG信号,导致算法失效,这是所有此类设备面临的共同挑战,需要更先进的运动补偿算法。
- 体温和呼吸率算法仅做了初步验证,需要更严谨的实验设计来评估其准确性。
- LoRa通信的实时性受网络拥堵和距离影响,在关键医疗警报场景中,需要设计重传和确认机制。
6. 项目总结、反思与未来展望
回顾整个项目,从构思、硬件选型、焊接调试、到嵌入式编程、算法实现、无线通信,完成了一个完整的物联网医疗设备原型闭环。最大的收获不仅仅是技术点的突破,更是对系统级产品开发的深刻体会:它要求硬件、软件、算法、通信乃至用户体验的综合考量。
几个关键的实操心得:
- 电源完整性是基石:在早期调试中,许多莫名其妙的传感器读数跳动或通信失败,最终都追溯到电源噪声。给每个IC的电源引脚添加足够的去耦电容(0.1uF + 10uF),并确保地线回路低阻抗,能解决一大半的“玄学”问题。
- 分而治之的调试策略:不要试图一次性集成所有功能。我的步骤是:先让每个传感器通过I2C单独工作,打印出正确的数据;然后实现基本的信号采集和显示;接着单独调试LoRa发射和接收,确保空口通信畅通;最后才整合算法和状态机。每步都稳扎稳打。
- 充分利用可视化工具:像
Serial Plotter或x-io Technologies的串口示波器这类工具,对于调试传感器信号和算法中间变量是无价之宝。图形化的数据流比单纯的数字打印直观无数倍,能帮你快速发现信号异常、滤波器效果不佳等问题。 - 理解数据手册胜过盲目搜索:在配置STM32WL的射频部分时,一度陷入困境。最终静下心来仔细阅读SX1262的数据手册和STM32WL的参考手册中关于射频控制的部分,才理清了正确的配置序列和寄存器操作,这比在网上漫无目的地搜索例程有效得多。
如果这个项目要继续演进,我会从以下几个方向深入:
- 低功耗优化:目前原型为方便调试,未做深度功耗优化。实际产品需要引入低功耗模式:MCU和传感器大部分时间处于睡眠状态,定时唤醒采集数据,LoRa模块也仅在发送时工作。目标是使用小容量电池实现数天甚至数周的续航。
- 加入LoRaWAN网络:目前是点对点通信。集成LoRaWAN协议栈,让设备可以接入公共或私有的LoRaWAN网络,通过网关将数据上传至真正的云平台(如TTN、ChirpStack),实现大规模设备管理。
- 算法增强:引入更鲁棒的运动伪影消除算法,如基于IMU数据的自适应滤波。探索更先进的SpO2计算模型,甚至尝试用机器学习模型在MCU端进行简单的异常模式识别(边缘AI)。
- 外壳与穿戴设计:设计3D打印外壳,将电路板、电池集成进去,做成真正的腕带或贴片形式,考虑佩戴舒适性和传感器接触的稳定性。
这个原型只是一个起点,它展示了利用现有成熟的半导体技术和开源生态,快速构建一个功能丰富的远程监护设备的可能性。希望我的分享能为你自己的物联网或嵌入式项目带来一些启发。
