EM7028

EM7028 是一款专门用于心率检测血氧检测 的低功耗传感器芯片,广泛应用于可穿戴设备(如智能手表、手环)和健康监测设备。它可以基于 PPG(光电容积脉搏波)技术,通过发射光线并接收反射信号来计算心率和血氧饱和度(SpO₂)。

工作原理

心率芯片包括发射 LED 和 PD 接收两部分。

芯片工作时,LED 发出的光打到皮肤下并反射回接收端,反射回的光强便包含了脉搏信息,这个光强经过处理后被 ADC 转换为数值,这个值会随着脉搏跳动周期性的变化。

gzyl

工作模式

连续模式

在正常 HRS 模式下,其中一个 LED 亮起,HRS 传感器同时检测环境光与绿色 LED 发出的光。光敏度为 1 勒克斯/计数,全范围内总共有65536 勒克斯;ADC 的典型分辨率为16位,转换时间为 25 毫秒。
在低亮度模式下,选择 8 倍 ADC 增益来接收光线,检测范围为 0.125 亮度到 8192 亮度。

LED 点亮:LED1 或 LED2 持续发光。

光检测:传感器实时接收 反射光线环境光线,并进行测量。

数据处理:通过 ADC 转换,将光线信号转化为数字信号,提供给主控 MCU。

输出数据:数据存储到寄存器(如 HRS_DATA0),主控 MCU 通过 I²C 通信读取数据。

脉冲模式

脉冲模式下的心率传感器在脉冲状态下打开 LED,检测反射光。

LED 脉冲点亮:LED 以一定周期脉冲式点亮,亮起时间较短。

光检测:在 LED 点亮期间,传感器检测光线反射强度。

ADC 转换:将检测到的光信号通过 ADC 转换为数字信号。

数据输出:将数据存储到寄存器,主控 MCU 在需要时读取。

LED 熄灭:在脉冲关闭期间,LED 熄灭,传感器休眠以节省功耗。

通过 EMP7028 的寄存器配置工作模式与相关参数

引脚说明

yjsm

PinNo PinName Type Description
1 SDA I/O (开漏) I²C 数据线:用于 I²C 通信的数据传输,需外接上拉电阻。
2 INT O (开漏) 中断引脚:当传感器有数据或事件触发时,该引脚输出中断信号。
3 LED1 O (开漏) LED 电流驱动引脚 1:可提供高达 200mA 电流,通常用于驱动高功率 LED 光源。
4 LED2 O (开漏) LED 电流驱动引脚 2:可提供高达 12mA 电流,通常用于低功率 LED 光源。
5 LEDA I LED 阳极端:需要连接到 LED 电源 VDD_LED,用于 LED 驱动电路供电。
6 GND 电源地:所有电压均参考此引脚接地。
7 SCL I (开漏) I²C 时钟线:提供 I²C 通信的时钟信号,需外接上拉电阻。
8 VDD 电源电压:为芯片提供供电,通常为 3.3V 或符合设备要求的电压。

I2C 时序特性

sstx

fclek:SCL 时钟频率

  • Normal Mode 下,SCL 的最大频率为 100 kHz

  • Fast Mode 下,SCL 的最大频率可达 400 kHz

tSUDAT:数据设置时间 (tSUDAT)

  • 主机在时钟信号(SCL)上升沿前,数据线(SDA)上的数据必须保持稳定的最短时间。

tHDDAT:数据保持时间 (tHDDAT)

  • 在时钟信号(SCL)下降沿之后,数据线(SDA)上的数据必须继续保持的时间。

trise:时钟/数据上升时间

  • 上升时间 (trise):SCL 和 SDA 从低电平到高电平的时间。

tfall:时钟/数据下降时间

  • 下降时间 (tfall):SCL 和 SDA 从高电平到低电平的时间。

tLOW:SCL 低电平时间

tHIGH:SCL 高电平时间

tBUF:起始状态和停止状态之间的空闲时间

  • tBUF 定义了停止条件与下一次起始条件之间的最小空闲时间。

tHDSTA:起始条件保持时间(重复启动)

  • 起始条件(START)信号的保持时间。

tSUSTA:起始条件设置时间

  • 主机发送起始条件前,数据线 SDA 必须稳定的最短时间。

tSUSTO:停止条件设置时间

  • 主机发送停止条件前,数据线 SDA 必须稳定的最短时间。

tTIMEOUT:低检测时钟/数据超时时间

Cload:每条总线线的电容负载

RBUS:SDA 和 SCL 的上拉电阻

tVD:数据有效时间

tVDACK:数据有效确认时间

  • 定义了数据在传输中的有效性以及接收方发送确认(ACK)时的时序要求。

I2C 状态机

I2Cztj

IDLE

  • 初始状态或空闲状态。
  • 系统处于等待信号或数据的状态。

Address Dec(Address Decode)

  • 解析或解码地址的状态。
  • 设备从总线或数据流中获取地址,并进行地址匹配。

ACK(Acknowledge)

  • 确认状态。
  • 当设备接收到正确的数据或地址后,会发送 ACK 信号(确认响应)。

REV(Receive)

  • 数据接收状态。
  • 系统从通信中接收数据。

TRANS(Transmit)

  • 数据传输状态。
  • 系统将数据传输给通信对方(比如主机或其他设备)。

IDLE → Address Dec

  • 系统从空闲状态进入地址解析状态,可能是因为接收到通信请求(如 Start 信号)。

Address Dec → IDLE

  • 如果地址解析失败,系统返回空闲状态,等待下一次请求。

Address Dec → ACK

  • 当地址成功匹配时,进入 ACK 状态,表示地址有效并响应确认信号。

ACK → REV

  • 系统进入接收数据状态,表示通信对方发送数据过来,系统开始接收。

ACK → TRANS

  • 系统进入数据传输状态,表示系统主动发送数据给对方。

REV → ACKTRANS → ACK

  • 数据传输或接收完成后,系统返回 ACK 状态,进行确认或等待下一步操作。

ACK → IDLE

  • 在某些情况下,数据传输或接收结束,系统返回空闲状态,等待下一次通信。

传输顺序

cssx

从设备地址

The I2C Interface and 7-bit slave address is 0x24.

示例电路

HRS2 脉冲模式的典型应用电路(VDD2.63.6V,VDD PC1.63.6V、VDD LED 2.6~4.5V)

mcsldl

HRS1 连续模式下的典型应用电路

lxmsdl

VDD、VDD_I2C、VDD_LED可以连接在一起,形成VDD3.3V至3.3V的电压。

VDD3.3V应将0.1uF电容器接地。

如果不需要中断模式,INT可以断开。

R0是LED2调节电阻器,R0的典型值为100Ω。

示例代码

波峰检测算法

波峰检测算法,通过传感器采集到的数据推算出心率值。

在心率算法中,通过波峰(即心跳信号的峰值)之间的时间间隔计算心率,常用以下公式:

xlsf

人体正常的心率范围一般在 60 BPM(一分钟 60 次) 到 180 BPM 之间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// HRAlgorithm.c

// 定义队列结构
#define QUEUE_SIZE 7

typedef struct {
int8_t front;
int8_t rear;
int8_t size;
uint32_t data[QUEUE_SIZE];
} Queue;

// 计算 HrList 的平均值,用于平滑处理心率数据,从而减小心率计算中的波动,提高数据稳定性。
uint8_t Hr_Ave_Filter(uint32_t *HrList, uint8_t lenth) {
uint32_t ave = 0;
uint8_t i = 0;
for(i = 0;i<lenth;i++) {
ave += HrList[i];
}
ave /= lenth;
}

/*
present_dat:当前时刻传感器采集到的数据值(光信号强度值)。
present_time:当前时刻的时间戳(单位为毫秒)。
*/
uint16_t HR_Calculate(uint16_t present_dat,uint32_t present_time) {

// peaks_time:保存最近检测到的两个波峰的时间戳。
// peaks_time[0]:当前检测到的波峰时间。
// peaks_time[1]:上一个波峰的时间。
static uint16_t peaks_time[]={0,0};
// 当前计算得到的心率值。
static uint8_t HR=0;

// isQueueFull() 判断队列是否以满
// dequeue() 从队列中移除旧数据。
if(isQueueFull(&datas)) {
dequeue(&datas);
}
if(isQueueFull(&times)) {
dequeue(&times);
}
if(isQueueFull(&HR_List)) {
dequeue(&HR_List);
}

// 将新数据加入队列。
enqueue(&datas,present_dat);
enqueue(&times,present_time);

if((datas.data[3]>=datas.data[2]) && (datas.data[3]>=datas.data[1]) && (datas.data[3]>datas.data[0])
&& (datas.data[3]>=datas.data[4]) && (datas.data[3]>=datas.data[5]) && (datas.data[3]>datas.data[6])) {
if((times.data[3]-peaks_time[0]) > 425) {
peaks_time[1] = peaks_time[0];
peaks_time[0] = times.data[3];
enqueue(&HR_List,60000/(peaks_time[0]-peaks_time[1]));
if(HR_List.data[6]!=0) {
HR = Hr_Ave_Filter(HR_List.data,7);
}
}
}
return HR;
}

维护队列

  • 如果 datas、times 和 HR_List 队列已满,则先移除最早的数据点。
  • 将当前的传感器数据 present_dat 和时间 present_time 加入队列。

波峰检测

  • 判断 datas.data[3](第4个数据点)是否为波峰。
  • 判断条件:第4个数据点必须大于前面 3 个和后面 3 个数据点(即满足局部最大值)。
  • 原理:通过比较前后数据点,检测光信号数据中的局部峰值,通常对应于心跳导致的光反射峰。

波峰间隔时间检查

  • 如果当前检测到的波峰与上一个波峰的时间间隔 times.data[3] - peaks_time[0] > 425(大约 425 毫秒,即心率下限 60/0.425 ≈ 141 BPM),则认为是有效波峰。
  • 更新 peaks_time 数组,保存当前和上一个波峰的时间戳。

心率计算

  • 使用公式: \text{HR} = \frac{60000}{\text{peaks_time[0]} - \text{peaks_time[1]}} 其中,60000 表示 1 分钟的时间(单位为毫秒)。
  • 将计算得到的心率值存入 HR_List 队列。

心率平滑滤波

  • 当 HR_List 数据满 7 个心率值时,调用 Hr_Ave_Filter 函数对最近 7 个心率值进行平均滤波,减少抖动,提高稳定性。
  • Hr_Ave_Filter 负责对心率值进行滤波平滑处理,返回最终的平滑心率值。

返回心率

  • 返回当前平滑处理后的心率值 HR。

算法中的固定阈值 425 毫秒(对应心率上限约为 141 BPM)在高心率场景下存在局限性,无法正确检测心率超过 141 BPM 的波峰。因此,波峰间隔阈值不应设为固定值,而是应根据用户状态动态调整,应当结合陀螺仪数据判断用户当前处于静止、运动或剧烈活动状态,从而设置适合的波峰间隔阈值以提高算法的适应性和准确性。

驱动库

https://github.com/TooUpper/SensorDrive