一、作品概述
这是是一台不外加 MCU 的指尖脉搏监测终端。EC800M-CN 在模组内部完成滤波、峰值检测与血氧解算,0.5 秒内在 OLED 上给出心率、血氧、HRV 与信号质量;抬手瞬间切换到"本次测量"统计页,同时通过 4G 把波形与数值以 MQTT 推送到微信小程序,实现远程查看与历史留存。
整机仅有一颗主控芯片(通信模组本身),没有额外的单片机、没有屏幕驱动 IC。两小时连续演示的移动数据流量不足 2 MB。
指标 | 数值 |
心率范围 / 误差 | 35~200 BPM / 离线回放 ≤1 BPM |
血氧范围 | 70~100%(低于 70% 判为不可信) |
采样率 | 100 sps 寄存器值,单通道 50 Hz |
界面刷新 | 5 fps( 400 kHz I2C_Standard) |
首次出数 | 放指后约 3~5 秒 |
抬手响应 | < 0.5 秒回到待机 |
上行包长 / 频率 | 约 170 B / 测量中 1 Hz,待机 10 s |
流量 | 2 小时演示 < 2 MB |
二、设计背景
家用的指夹血氧仪、智能手环普及率已经很高,但存在三个结构性缺口:
数据是孤岛。测量结果只停在设备屏幕上,子女、社区医生、随访平台都看不到,慢病人群的长期趋势无法沉淀。
联网方案成本高。传统做法是"传感器 + MCU + Wi-Fi/蓝牙模组 + 云平台",四颗芯片、两套固件、一个服务器,个人开发者和小团队很难做完整。
蓝牙方案受距离限制。手机必须在 10 米内,老人不会用、也不常带着手机。
Cat.1 模组给了另一种可能:模组本身就是一台带 4G、带文件系统、能跑 Python 的计算机。把采集、算法、显示、联网全部塞进模组,硬件只剩"传感器 + 屏幕 + 电源",软件只有一份 Python 工程,云端可以直接用公共 MQTT Broker 零成本起步。
该项目就是这条路径的一次完整验证。
三、系统架构
┌──────────────┐ I2C0 1.8V 400kHz
│ MAX30102 ├──────────────┐
│ 0x57 │ │ ┌────────────────────────┐
└──────────────┘ ├────────┤ EC800M-CN │
│ │ QuecPython │
┌──────────────┐ │ │ │
│ SSD1306 ├──────────────┘ │ ① 100sps FIFO 采样 │
│ 0x3C 128×64 │ I2C │ ② 直流跟踪 + 带通 │
└──────────────┘ │ ③ 自适应峰值检测 │
│ ④ 血氧比值解算 │
│ ⑤ 自动增益 AGC │
│ ⑥ 三态界面 │
│ ⑦ MQTT 上报 │
└───────────┬────────────┘
│ 4G(SIM1)
┌───────────┴────────────┐
│ broker.emqx.io │
└───────────┬────────────┘
│ wss 8084/mqtt
┌───────────┴────────────┐
│ 微信小程序 │
│ 实时 / 历史 / 设置 │
└────────────────────────┘数据流:传感器 FIFO(每样本 6 字节,RED + IR 各 18 bit)→ 每 100 ms 批量读出 → 直流跟踪与带通滤波 → 峰值检测得到心搏间期 → 心率 / 血氧 / HRV / 信号质量 → ① 绘入 128×64 帧缓冲并推屏 ② 每秒打包 24 个波形点与全部指标上行 → 小程序解析
四、硬件设计
本作品的核心创新在软件与系统集成,硬件追求最小化,以下为设计要点。
4.1 主控:EC800M-CN
特性 | 意义 |
LTE Cat 1 bis,下行 10 Mbps / 上行 5 Mbps | 传心率数据带宽充足,余量留给固件升级 |
QuecPython 二次开发 | 直接用 Python 算法,无需搭建交叉编译链 |
内置 I2C、UART、USB 2.0 | 一颗芯片同时驱动传感器、屏幕、调试口 |
17.7 × 15.8 × 2.4 mm LCC | 体积接近一枚硬币,适合可穿戴形态 |
工作温度 −35~+75 ℃ | 室内外均可 |
选型说明:该模组不含蓝牙与 GNSS,因此本作品放弃了"手机近场直连"的路线,改用 4G 直连云端的架构。该取舍换来无距离限制与零服务器成本(公共 Broker),对"远程看护"这一目标反而更贴合。
4.2 传感与显示
MAX30102:红光 660 nm + 红外 880 nm 双 LED,18 bit ADC,内置 32 样本 FIFO 与 I2C 接口。VDD 1.8 V、VDDB 3.3 V(LED 驱动),与模组的 1.8 V I/O 域天然匹配。
SSD1306 128×64:I2C 接口,仅需 4 线(VCC/GND/SDA/SCL)
两者共用一路 I2C,地址 0x57 与 0x3C 不冲突;总线上加 4.7 kΩ 上拉到 1.8 V。
4.3 接口与供电
接口 | 用途 |
I2C(2 线) | 传感器 + 屏幕 |
USB 2.0 | 烧录固件、REPL 调试 |
DBG UART | 日志与故障定位测试点 |
SIM1 | 4G 数据(单卡) |
主天线 | LTE |
ADC0 | 电池电压检测(1/2 分压) |
供电为单节锂电 3.4~4.3 V,模块 VBAT 端并 220 µF 低 ESR 电容吸收 Cat.1 发射瞬时电流。
五、软件设计
5.1 分层结构
应用层 main.py 状态机 / 调度 / 会话统计 / AGC 决策
界面层 ui.py gfx.py 三态界面、8×8 字模、页面刷新
算法层 pulse.py 直流跟踪、带通、峰值检测、血氧、HRV
驱动层 max30102.py ssd1306.py board.py
链路层 mqtt_link.py 连接、重连请求、主密钥
配置 config.py 全部可调参数可集中配置全部为纯 Python,无第三方依赖,不依赖 framebuf(自绘图形库),因此不受固件版本差异影响。
5.2 采样时序
单通道 50 Hz,主循环 20 ms 一拍:
周期 | 动作 |
100 ms | 读 FIFO(约 5 个样本)→ 逐样本算法处理 |
200 ms | 刷新 OLED |
1 s | 打包上报(测量中);待机改为 10 s |
3 s | AGC 评估一次 |
30 s | 读 CSQ (与电池电压) |
5.3 信号链
IR ──► EMA 直流跟踪 (τ=2s) ──► AC = IR − DC ──► 2 阶带通 1.5Hz Q=1.0 ──► 峰值检测
│ │
└──► 0.25s 快速均值 ──► 手指在位判断(迟滞 + 快速释放) ▼
心搏间期 IBI
RED ─► 相同结构 ──► AC/DC ──► R 比值 ──► SpO2 HR = 60 / median(IBI)5.4 算法细节
心率:三点极值 + 自适应阈值(0.4 × 幅度滑动均值)+ 260 ms 不应期;IBI 取最近 8 拍中位数,抑制漏检/误检引起的跳变。
血氧:4 秒滑窗内分别计算两通道 AC 的 RMS 与 DC,按 Maxim 经验式
R = (AC_red / DC_red) / (AC_ir / DC_ir)
SpO2 = −45.06 R² + 30.354 R + 94.845结果限幅 70~100%,低于 70% 视为不可信舍弃,再做 0.75/0.25 的指数平滑。
HRV:对最近 8 个 IBI 求 RMSSD;同时用变异系数 CV 判断节律是否规整(CV>0.20 标记为不规则)。
信号质量:由灌注指数 PI、有效心搏数、血氧是否收敛、节律规整度四项加权成 0~100 分,≥60 判为"读数稳定"。
5.5 自适应增益(AGC)
不同人的手指厚度、肤色、按压力度差异极大,固定 LED 电流要么波形太浅、要么直流饱和。固件每 3 秒根据 IR 直流分量调整 LED 电流寄存器:
直流 > 200000(接近 18 bit 满量程)→ 降档
直流 < 50000(信号太弱)→ 升档
仅在手指在位时调整,避免空载把电流拉满
调整后重置直流跟踪,让基线重新收敛,避免波形跳变。
5.6 状态机与界面
状态 | 触发 | 界面内容 |
| 检测到手指 | 心率大字 + BPM + HRV + 血氧 + 10 段质量条 + 128 点实时波形 |
| 抬手后 8 秒内 | 本次时长 / 平均心率 / 心率区间 / 平均血氧 |
| 其余时间 |
|
手指判定采用双阈值迟滞 + 快速释放:进入阈值 30000,退出阈值 20000;同时 0.25 秒内快速均值监测骤降,连续 5 帧低于基线 45% 即判抬手。预计抬手响应 < 0.5 秒,且不会出现"抬手后读数反复弹回"。
5.7 网络与协议
MQTT 3.1.1,主题
hqcup/pulse/<设备号>-<密钥>/{data,cmd,status}
上报为短键 JSON(约 170 B),含心率、血氧、PI、HRV、质量、状态、时长、24 点波形、电量、CSQ
状态主题使用 retain + 异常掉线文本:设备异常掉线时 Broker 自动发布
{"on":0},小程序 15 秒内判定为离线状态
下行命令需携带口令
tk,错误口令直接舍弃
断线重连采用指数退避 1/2/4/8/20 s,每 5 秒检查一次链路
六、微信小程序端
页面 | 能力 |
实时 | 心率大字(随心跳节奏缩放)、本次已测时长、血氧、HRV、信号质量、128 点滚动波形、连接状态与错误诊断 |
历史 | 每次测量的时长、平均/最高/最低心率、平均与最低血氧、信号质量,本地留存最近 60 条 |
设置 | Broker 地址端口、设备号、主题密钥、命令口令、告警阈值 |
两个工程细节:
零依赖 MQTT 客户端。小程序没有可用的 MQTT SDK,
mqtt.js依赖 Node 的 Buffer/Stream。工程内用约 200 行实现了 CONNECT/CONNACK/SUBSCRIBE/PUBLISH/PING 的最小集合,直接跑在wx.connectSocket的二进制帧上。
波形为真实数据,非动画。设备每秒上送 24 个带通滤波后的采样点(int8 补码的十六进制),小程序按 24 点/秒平滑滚动,抬手即停。
七、创新点
单芯片架构:把采集、算法、显示、联网全部收敛进通信模组,省去 MCU ,BOM 与调试成本同步下降。这让"低成本联网血氧仪"成为可能。
面向现实情况的鲁棒性设计:AGC 自动增益 + 双阈值迟滞 + 快速释放,解决"换人就测不准""抬手回不到待机"这类演示现场最容易翻车的问题,而不是实验室理想条件下的精度。
端侧闭环:抬手即在屏幕上给出本次统计,不依赖网络、不依赖手机,断网也能用;联网只是增强,不是前提。
零成本云端:公共 MQTT Broker + 主题随机密钥 + 命令口令 + 机制,在不另外架设服务器的前提下做到"可用且不易被误伤"。
极简流量模型:短键 JSON + 波形抽样 + 分级上报,2 小时演示流量 < 2 MB,普通物联网卡可用数月。
九、使用说明
上电,OLED 自检并显示
PLACE FINGER。
手机打开小程序,状态灯变绿表示设备在线。
指尖轻按传感器(遮光、力度适中、保持静止),3~5 秒后即刷新结果。
持续测量 30 秒以上,抬手即显示本次统计,同时自动存入小程序历史。
在小程序"设置"中可调整告警阈值,超限时手机提醒。
