1、MAX30102心率和血氧传感器介绍
MAX30102是一款集成式脉搏血氧仪和心率监测模块。采用标准I2C接口进行通讯。模块原理图如下:

2、接线图
oled显示屏使用硬件IIC,MAX30102模块使用软件iic

3、程序
3.1、程序结构

3.2、模拟iic初始化
void IIC_GPIO_INIT(void)
{
gpio_sda_out.port = MXC_GPIO_PORT_SDA;
gpio_sda_out.mask = MXC_GPIO_PIN_SDA;
gpio_sda_out.pad = MXC_GPIO_PAD_NONE;
gpio_sda_out.func = MXC_GPIO_FUNC_OUT;
gpio_sda_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_sda_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_sda_out);
gpio_scl_out.port = MXC_GPIO_PORT_SCL;
gpio_scl_out.mask = MXC_GPIO_PIN_SCL;
gpio_scl_out.pad = MXC_GPIO_PAD_NONE;
gpio_scl_out.func = MXC_GPIO_FUNC_OUT;
gpio_scl_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_scl_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_scl_out);
}3.3、max30102_init 进行了中断使能寄存器配置、对FIFO指针和溢出计数器进行重置、还配置了模块LED驱动电流。
void max30102_init(void)
{
IIC_GPIO_INIT();
max30102_reset();
max30102_Bus_Write(REG_INTR_ENABLE_1, 0xc0); // INTR setting
max30102_Bus_Write(REG_INTR_ENABLE_2, 0x00);
max30102_Bus_Write(REG_FIFO_WR_PTR, 0x00); // FIFO_WR_PTR[4:0]
max30102_Bus_Write(REG_OVF_COUNTER, 0x00); // OVF_COUNTER[4:0]
max30102_Bus_Write(REG_FIFO_RD_PTR, 0x00); // FIFO_RD_PTR[4:0]
max30102_Bus_Write(REG_FIFO_CONFIG, 0x0f); // sample avg = 1, fifo rollover=false, fifo almost full = 17
max30102_Bus_Write(REG_MODE_CONFIG, 0x03); // 0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
max30102_Bus_Write(REG_SPO2_CONFIG, 0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
max30102_Bus_Write(REG_LED1_PA, 0x24); // Choose value for ~ 7mA for LED1
max30102_Bus_Write(REG_LED2_PA, 0x24); // Choose value for ~ 7mA for LED2
max30102_Bus_Write(REG_PILOT_PA, 0x7f); // Choose value for ~ 25mA for Pilot LED
}3.4、数据读取
总共读取512组数据,并将数据写入缓存方便处理。
void max30102_read(void)
{
int num_samples = 0;
uint32_t fifo_red, fifo_ir;
num_samples = max30102_Bus_Read(REG_OVF_COUNTER)& 0x0F;
if (num_samples == 0)
{
MXC_Delay(20000);
}
else
{
for(int i = 0; i < num_samples; i++)
{
maxim_max30102_read_fifo(&fifo_red, &fifo_ir);
printf("sample_index:%d fifo_red: %d fifo_ir: %d\n",sample_index, fifo_red, fifo_ir);
// 写入当前缓冲区
s1[sample_index].real = fifo_red;
s2[sample_index].real = fifo_ir;
s1[sample_index].imag = 0;
s2[sample_index].imag = 0;
sample_index++;
// 缓冲满时切换并通知
if (sample_index >= FFT_N)
{
sample_index = 0;
process_buffer();
}
}
}
}3.5、数据处理及处理结果OLED显示
void process_buffer(void)
{
float n_denom;
uint16_t i;
float dc_red =0;
float dc_ir =0;
float ac_red =0;
float ac_ir =0;
for (i=0 ; i<FFT_N ; i++ )
{
dc_red += s1[i].real ;
dc_ir += s2[i].real ;
}
dc_red =dc_red/FFT_N ;
dc_ir =dc_ir/FFT_N ;
for (i=0 ; i<FFT_N ; i++ )
{
s1[i].real = s1[i].real - dc_red ;
s2[i].real = s2[i].real - dc_ir ;
}
for(i = 1;i < FFT_N-1;i++)
{
n_denom= ( s1[i-1].real + 2*s1[i].real + s1[i+1].real);
s1[i].real= n_denom/4.00;
n_denom= ( s2[i-1].real + 2*s2[i].real + s2[i+1].real);
s2[i].real= n_denom/4.00;
}
//八点平均滤波
for(i = 0;i < FFT_N-8;i++)
{
n_denom= ( s1[i].real+s1[i+1].real+ s1[i+2].real+ s1[i+3].real+ s1[i+4].real+ s1[i+5].real+ s1[i+6].real+ s1[i+7].real);
s1[i].real= n_denom/8.00;
n_denom= ( s2[i].real+s2[i+1].real+ s2[i+2].real+ s2[i+3].real+ s2[i+4].real+ s2[i+5].real+ s2[i+6].real+ s2[i+7].real);
s2[i].real= n_denom/8.00;
//UsartPrintf(USART_DEBUG,"%f\r\n",s1[i].real);
}
g_fft_index = 0;
FFT(s1);
FFT(s2);
//解平方
//UsartPrintf(USART_DEBUG,"开始FFT算法****************************************************************************************************\r\n");
for(i = 0;i < FFT_N;i++)
{
s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
s1[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
}
//计算交流分量
for (i=1 ; i<FFT_N ; i++ )
{
ac_red += s1[i].real ;
ac_ir += s2[i].real ;
}
int s1_max_index = find_max_num_index(s1, 30);
int s2_max_index = find_max_num_index(s2, 30);
float Heart_Rate = 60.00 * ((100.0 * s1_max_index )/ 512.00)+20;
g_blooddata.heart = Heart_Rate;
float R = (ac_ir*dc_red)/(ac_red*dc_ir);
float sp02_num =-45.060*R*R+ 30.354 *R + 94.845;
g_blooddata.SpO2 = sp02_num;
printf("Heart:%d\r\n",(int)Heart_Rate) ;
printf("SpO2:%.2f\r\n",g_blooddata.SpO2);
MXC_Delay(MXC_DELAY_MSEC(20));
OLED_CLear(0);
MXC_Delay(MXC_DELAY_MSEC(20));
char show_buf[40];
sprintf(show_buf, "Heart:%d",g_blooddata.heart);
GUI_ShowString(0,20,(uint8_t *)show_buf,16,1);
sprintf(show_buf, "SpO2:%.2f",g_blooddata.SpO2);
GUI_ShowString(0,40,(uint8_t *)show_buf,16,1);
OLED_Display();
MXC_Delay(MXC_DELAY_MSEC(20));
}3.7、结果展示
我要赚赏金
