这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'Sdo第二期智能手环DIY-心率和血氧检测并显示 成果贴

共1条 1/1 1 跳转至

Let'Sdo第二期智能手环DIY-心率和血氧检测并显示 成果贴

菜鸟
2025-10-11 19:44:28     打赏

1、MAX30102心率和血氧传感器介绍

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

image.png

2、接线图

oled显示屏使用硬件IIC,MAX30102模块使用软件iic

image.png


3、程序

3.1、程序结构

image.png


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




关键词: 智能手环      血氧     检测     max30102    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]