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、结果展示