文章目录
一、引言
本次设计主要使用STM32F103C8T6作为主控,0.96寸OLED 显示(四针IIC),MAX30102采集心率血氧。
为了让读者更好地理解MAX30102的驱动,我们将通过一个详细的示例项目展示如何使用该传感器进行心率和血氧测量。示例项目将包含完整的硬件连接步骤、代码实现和数据处理方法,帮助读者快速上手
二、MAX30102传感器概述
2.1 模块原理
血氧饱和度(SpO2)测量原理
血氧饱和度是指血液中氧合血红蛋白(HbO2)占总血红蛋白(包括氧合血红蛋白和脱氧血红蛋白)的比例。不同波长的光对氧合血红蛋白和脱氧血红蛋白的吸收率不同,通过测量反射光的强度可以推算出血氧饱和度。
- 红光(660nm): 氧合血红蛋白(HbO2)和脱氧血红蛋白(Hb)对红光的吸收率不同。脱氧血红蛋白对红光吸收较强,而氧合血红蛋白对红光吸收较弱。
- 红外光(880nm): 氧合血红蛋白和脱氧血红蛋白对红外光的吸收率差异较小,但红外光的穿透力较强,可以更深层次地检测血液。
通过比较这两种波长光的吸收情况,能够计算出血液中氧合血红蛋白的比例,即血氧饱和度(SpO2)。具体公式如下:
SpO
2
=
HbO
2
HbO
2
+
Hb
\text{SpO}_2 = \frac{\text{HbO}_2}{\text{HbO}_2 + \text{Hb}}
SpO2=HbO2+HbHbO2
通过采集红光和红外光的反射信号,利用比值和校准曲线计算出SpO2值
心率测量原理
心率测量是基于血液容积随时间变化来进行光学检测。手指中血液随心脏律动,从而改变组织对光的吸收率。这种变化可以通过检测反射光的强度变化来捕捉。
- 光学脉搏波(PPG):当心脏跳动时,血液流量增加,导致组织对光的吸收增加,反射光的强度减少。相反,在心脏舒张时,血液流量减少,反射光的强度增加。通过分析红光或红外光的反射信号强度变化,形成光学脉搏波(PPG)信号。
- 心率计算: PPG信号中每个峰值对应一次心跳,通过计算一段时间内的峰值数,可以得出心率(BPM,次/分钟)。
具体步骤如下:
发光: 红光和红外光LED交替发光,穿透皮肤和血管。
接收: 光电二极管接收反射回来的光信号。
信号处理: 反射信号经过环境光消除、模数转换和数字滤波处理。
PPG信号提取: 从处理后的信号中提取出光学脉搏波(PPG)信号。
峰值检测: 检测PPG信号中的峰值,计算峰值之间的时间间隔。
心率计算: 根据峰值间隔时间,计算心率(BPM)。
2.2 模块工作流程
这个架构图展示了MAX30102传感器将光信号转换为数字数据,并通过I2C接口传输给外部设备,用于心率和血氧饱和度测量
红光LED(660nm)和红外LED(880nm)用于发射光束穿过人体组织。光通过人体组织后部分被吸收,部分被反射,反射回来的光被光电二极管检测到。将从光电二极管接收到的模拟信号转换为数字信号。这里有两个ADC,一个是红光信号,一个是红外光信号。对从ADC采集的数字信号进行处理,去除噪声,得到更精确的数据,然后把数据等待通过I2C接口发送给外部微控制器
三、硬件连接
MAX30102:
VCC<->3.3V
GND<->GND
SCL<->PB7
SDA<->PB8
INT<->PB9
0.96inch OLED :
VCC<->3.3V
GND<->GND
SCL<->PC13
SDA<->PC14
四、驱动程序
IIC通信原理在之前的文章已经介绍过,本小节主要介绍MAX30102如何通过IIC驱动
4.1 FIFO介绍
MAX30102可通过寄存器进行配置,ADC输出数据存储在32深度的数据缓存器(FIFO)。FIFO 允许MAX30102连接到共享总线上的微控制器或处理器,所以ADC数据不会从MAX30102 的寄存器中读取。
MAX30102 的 FIFO 有 32 个 3 字节的样本位置,也就是说,它的 FIFO 深度是 32。每个样本包含红光和红外光的数据,每个数据占用 3 个字节,所以一个完整的样本占用 6 个字节(红光数据的3个字节 + 红外光数据的3个字节)
由于每个样本由两个数据通道组成,因此每个样本有6个字节的数据,因此 FIFO 中总共可以存储 192 个字节的数据
4.2 寄存器配置
通常设置为 SpO2 mode (可以同时测量心率和血氧饱和度)
max30102_Bus_Write(REG_MODE_CONFIG,0x03);//0x03(011) for SpO2 mode
测量量程,采样率,功率(AD采样精度)的配置
max30102_Bus_Write(REG_SPO2_CONFIG,0x27);//0x27(001 001 11)
//SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (411uS)
小灯的驱动电流幅度控制,红光LED1和红外光LED2的电流配置为约 7mA
Pilot LED 的电流配置为约 25mA
max30102_Bus_Write(REG_LED1_PA,0x24); //Choose value for ~ 7mA for LED1 0xe0 0x24
max30102_Bus_Write(REG_LED2_PA,0x24); // Choose value for ~ 7mA for LED2 0xe0 0x24
max30102_Bus_Write(REG_PILOT_PA,0x7f); // Choose value for ~ 25mA for Pilot LED
每当读取中断状态寄存器或读取触发中断的寄存器时,中断都会被清除
中断使能:可以配置 MAX30102 的中断,在数据准备好时通知微控制器,提高数据读取的实时性和效率
FIFO配置: 配置为在 FIFO 中存储2次样本平均值,也就是说每两个点取平均存一次。结合上面配置采样率为100HZ,最终采样率是50HZ
max30102_Bus_Write(REG_FIFO_CONFIG,0x2f);//001 0 1111
//sample avg = 2, fifo rollover=false, fifo almost full = 17
FIFO读取数据:
设置读指针:将 FIFO 读指针设为开始读取的位置。
读取数据:从 FIFO 数据寄存器连续读取 6 个字节(3 个字节红光数据 + 3 个字节红外光数据)。
更新读指针:读取完成后,读指针自动更新到下一个位置。
五、数据采集与处理
5.1 原始数据采集
这里的
aun_ir_buffer
和aun_red_buffer
就是原始adc数据,我们可以在单片机处理,也可以用串口输出在其他设备进行处理
#define REG_FIFO_DATA 0x07
max30102_FIFO_ReadBytes(REG_FIFO_DATA,temp);//从MAX30102读数据
//红色三字节数字,红外三字节数据
aun_ir_buffer[i] = (long)((long)((long)temp[0]&0x03)<<16) | (long)temp[1]<<8 | (long)temp[2]; // Combine values to get the actual number
aun_red_buffer[i] = (long)((long)((long)temp[3] & 0x03)<<16) |(long)temp[4]<<8 | (long)temp[5];
5.2 数据处理算法(心率和血氧饱和度的计算)
计算DC均值并去除DC成分:
首先计算红光和红外光信号的平均值
f_ir_mean=0.0;
f_red_mean=0.0;
for (k=0; k<n_ir_buffer_length; ++k) {
f_ir_mean += pun_ir_buffer[k];
f_red_mean += pun_red_buffer[k];
}
f_ir_mean=f_ir_mean/n_ir_buffer_length ;
f_red_mean=f_red_mean/n_ir_buffer_length ;
然后减去该均值以去除DC成分
for (k=0,ptr_x=an_x,ptr_y=an_y; k<n_ir_buffer_length; ++k,++ptr_x,++ptr_y) {
*ptr_x = pun_ir_buffer[k] - f_ir_mean;
*ptr_y = pun_red_buffer[k] - f_red_mean;
}
去除基线漂移:
线性回归计算斜率:
beta_ir = rf_linear_regression_beta(an_x, mean_X, sum_X2);
beta_red = rf_linear_regression_beta(an_y, mean_X, sum_X2);
去除基线漂移:
for(k=0,x=-mean_X,ptr_x=an_x,ptr_y=an_y; k<n_ir_buffer_length; ++k,++x,++ptr_x,++ptr_y) {
*ptr_x -= beta_ir*x;
*ptr_y -= beta_red*x;
}
计算RMS值和皮尔逊相关系数:
计算信号的RMS值
f_y_ac=rf_rms(an_y,n_ir_buffer_length,&f_red_sumsq);
f_x_ac=rf_rms(an_x,n_ir_buffer_length,&f_ir_sumsq);
计算红光和红外信号的皮尔逊相关系数,确保信号质量
*correl=rf_Pcorrelation(an_x, an_y, n_ir_buffer_length)/sqrt(f_red_sumsq*f_ir_sumsq);
检测信号周期性:
通过自相关方法检测信号的周期性,从而推算心率
if(*correl>=min_pearson_correlation) {//判断信号质量。
//皮尔逊相关系数衡量两个信号之间的线性相关性,较高的值表示信号质量较高。如果相关系数低于阈值,信号被认为质量不佳,无法可靠地计算心率和SpO2。
if(LOWEST_PERIOD==n_last_peak_interval) //如果n_last_peak_interval等于LOWEST_PERIOD,表示需要重新初始化周期性搜索。
rf_initialize_periodicity_search(an_x, BUFFER_SIZE, &n_last_peak_interval, HIGHEST_PERIOD, min_autocorrelation_ratio, f_ir_sumsq);
if(n_last_peak_interval!=0)//调用rf_signal_periodicity函数来检测信号的周期性
rf_signal_periodicity(an_x, BUFFER_SIZE, &n_last_peak_interval, LOWEST_PERIOD, HIGHEST_PERIOD, min_autocorrelation_ratio, f_ir_sumsq, ratio);
} else n_last_peak_interval=0;
计算SpO2:
通过AC/DC比值计算血氧饱和度
xy_ratio= (f_y_ac*f_ir_mean)/(f_x_ac*f_red_mean);
使用预定义的公式计算SpO2,并检查计算结果的有效性
if(xy_ratio>0.02 && xy_ratio<1.84) {
*pn_spo2 = (-45.060*xy_ratio + 30.354)*xy_ratio + 94.845;
*pch_spo2_valid = 1;
} else {
*pn_spo2 = -999 ; // 不要使用血氧饱和度,因为信号比率超出范围
*pch_spo2_valid = 0;
}
六、项目结果
本次项目成功实现了基于STM32F103C8T6主控的心率和血氧测量系统。通过集成MAX30102传感器和0.96寸OLED显示屏,我们能够实时监测和显示心率和血氧饱和度(SpO2)
我们成功实时监测到心率和血氧饱和度。以下是测量的截图:
七、故障排除
在项目开发过程中,遇到读取不到max30102数据的问题,解决方法如下:
硬件方面:
- 检查电路连接,确保各个引脚正确连接,排除焊接问题
- 检查MCU和传感器供电是否正常
软件方面:
- 确保IIC通信按照手册运行,通过示波器/逻辑分析仪观察时钟线和数据线电平变化
数据不稳定,测量结果偏差较大的问题,解决方法如下:
- 通过遮光措施,减小环境光对测量结果的影响。
- 通过丢弃质量较差的数据和滤波算法来提高测量精度
八、结论
本项目成功实现了基于STM32F103C8T6和MAX30102传感器的心率和血氧测量系统。该系统具有较高的测量准确性和实时性,能够稳定地监测心率和血氧饱和度。未来可以通过进一步优化算法和硬件设计,提升系统的性能和应用范围。
九、附录
参考手册:MAX30102: High-Sensitivity Pulse Oximeter and Heart-Rate Sensor for Wearable Health Data Sheet (Rev.1)
代码资料:
链接:https://pan.baidu.com/s/1jxEsUzZaDuBs-3dSfXlcgg?pwd=ixzn
提取码:ixzn