飞道的博客

MAX30102血氧模块的原理及编程

817人阅读  评论(0)

一.简介

MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块(芯片)。它集成了一个660nm红光LED、880nm红外光LED、光电检测器、光器件,以及带环境光抑制的低噪声电子电路。可通过软件关断模块,待机电流为零,实现电源始终维持供电状态,可运用于低功耗产品中。
MAX30102采用一个1.8V电源和一个独立的3.3V用于内部LED的电源,标准的I2C兼容的通信接口。市面很多都将MAX30102芯片集成在一个PCB模块上,内部增加一个1.8V和3.3V LDO稳压电路,可对模块单独供5.0V电源,方便开发者进行开发。

Max30102芯片及模块

二.MAX30102原理及参数

1.芯片内部框图

从框图看,芯片可分为两部分,一部分为模拟信号采集电路,通过RED和IR灯发出特定波长的光,采集人体反射回来的光,经过PD管将光信号转化为电信号,最终通过18bit ADC转换器转化为数字信号。
第二部分为数字处理电路,将ADC转换出来的原始数据进行滤波处理后放置于缓冲区内;单片机通过IIC接口读写芯片内部寄存器,读取出相应的数据;

2.模块电路


芯片内部有3.3V-5.0V的LED电源和1.8V的逻辑电源,所以模块带有两路稳压电路,将5V电源分别转化为3.3V和1.8V;由于LED驱动电源的供电范围为3.3V-5.0V,3.3V稳压电路可省去。
由于MAX30102的逻辑电路的IIC通信电平为1.8V,这与我们常用的51单片机和STM32单片机的引脚电平不匹配。
这里有个解决方法,因为MAX30102的SDA、SCL、INT引脚为开漏,

可以将模块上的R1、R2、R3电阻去掉,对于51单片机来说,在SDA、SCL、INT引脚上分别加一个4.7-10k电阻上拉至5V;对于STM32单片机,只需要将相应的控制引脚配置为上拉模式即可。

模块只需要接上5V电源,SDA、SCL、INT引脚与单片机连接即可;IRD、RD一般不接,以STM32单片机接线为例(单片机采用模拟IIC的控制方式),如图:

三.MAX30102编程

MAX30102内部集成了一整套完整信号采集电路,包括光信号发射及接收、AD转换、环境光干扰消除及数字滤波部分,只将数字接口留给用户。用户只需通过单片机的IIC接口(可用模拟IIC),对MAX30102内部的寄存器进行读写操作,就可以得到转换后的光强度数值。最后需要通过相应的处理算法计算出心率值和血氧饱和度。
对于MAX30102的驱动程序,将其拆分出来,可分为标准IIC程序和MAX30102寄存器的读写操作,实现这两部分的编程,便完成MAX30102的驱动;由于IIC程序比较常用,这里就不例举出来。在完成IIC的通信程序后,实现以下程序;

(1)MAX30102写寄存器函数

u8 max30102_Bus_Write(u8 Register_Address, u8 Word_Data)
{

	/* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */

	/* 第1步:发起I2C总线启动信号 */
	i2c_Start();

	/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
	i2c_SendByte(max30102_WR_address | I2C_WR);	/* 此处是写指令 */

	/* 第3步:发送ACK */
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 第4步:发送字节地址 */
	i2c_SendByte(Register_Address);
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}
	
	/* 第5步:开始写入数据 */
	i2c_SendByte(Word_Data);

	/* 第6步:发送ACK */
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 发送I2C总线停止信号 */
	i2c_Stop();
	return 1;	/* 执行成功 */

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
	/* 发送I2C总线停止信号 */
	i2c_Stop();
	return 0;
}

(2)MAX30102读寄存器函数

u8 max30102_Bus_Read(u8 Register_Address)
{
	u8  data;


	/* 第1步:发起I2C总线启动信号 */
	i2c_Start();

	/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
	i2c_SendByte(max30102_WR_address | I2C_WR);	/* 此处是写指令 */

	/* 第3步:发送ACK */
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 第4步:发送字节地址, */
	i2c_SendByte((uint8_t)Register_Address);
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}
	

	/* 第6步:重新启动I2C总线。下面开始读取数据 */
	i2c_Start();

	/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
	i2c_SendByte(max30102_WR_address | I2C_RD);	/* 此处是读指令 */

	/* 第8步:发送ACK */
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 第9步:读取数据 */
	{
		data = i2c_ReadByte();	/* 读1个字节 */

		i2c_NAck();	/* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
	}
	/* 发送I2C总线停止信号 */
	i2c_Stop();
	return data;	/* 执行成功 返回data值 */

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
	/* 发送I2C总线停止信号 */
	i2c_Stop();
	return 0;
}

(3)MAX30102读缓冲器FIFO

void max30102_FIFO_Read(u8 Register_Address,u16  Word_Data[][2],u8 count)
{
	u8 i=0;
	u8 no = count;
	u8 data1, data2;
	/* 第1步:发起I2C总线启动信号 */
	i2c_Start();

	/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
	i2c_SendByte(max30102_WR_address | I2C_WR);	/* 此处是写指令 */

	/* 第3步:发送ACK */
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 第4步:发送字节地址, */
	i2c_SendByte((uint8_t)Register_Address);
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}
	

	/* 第6步:重新启动I2C总线。下面开始读取数据 */
	i2c_Start();

	/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
	i2c_SendByte(max30102_WR_address | I2C_RD);	/* 此处是读指令 */

	/* 第8步:发送ACK */
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 第9步:读取数据 */
	while (no)
	{
		data1 = i2c_ReadByte();	
		i2c_Ack();
		data2 = i2c_ReadByte();
		i2c_Ack();
		Word_Data[i][0] = (((u16)data1 << 8) | data2);  //

		
		data1 = i2c_ReadByte();	
		i2c_Ack();
		data2 = i2c_ReadByte();
		if(1==no)
			i2c_NAck();	/* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
		else
			i2c_Ack();
		Word_Data[i][1] = (((u16)data1 << 8) | data2); 

		no--;	
		i++;
	}
	/* 发送I2C总线停止信号 */
	i2c_Stop();

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
	/* 发送I2C总线停止信号 */
	i2c_Stop();
}

(4)MAX30102初始化(可根据自己的实际情况更改相应的配置)

void max30102_init()
{
	
	max30102_Bus_Write(0x09, 0x0b);  //mode configuration : temp_en[3]      MODE[2:0]=010 HR only enabled    011 SP02 enabled
	max30102_Bus_Write(0x01, 0xF0); //open all of interrupt
	max30102_Bus_Write(INTERRUPT_REG, 0x00); //all interrupt clear
	max30102_Bus_Write(0x03, 0x02); //DIE_TEMP_RDY_EN
	max30102_Bus_Write(0x21, 0x01); //SET   TEMP_EN

	max30102_Bus_Write(0x0a, 0x47); //SPO2_SR[4:2]=001  100 per second    LED_PW[1:0]=11  16BITS

	max30102_Bus_Write(0x0c, 0x47); 
	max30102_Bus_Write(0x0d, 0x47); 
											
}

(5)数据采集

此程序只演示读取出温度,读取血氧数据需要通过max30102_FIFO_Read函数读出;

int main(void)
{
	u8 temp_num=0;
	main_init();
	
	max30102_init();
	
	printf("\r\n MAX30102  init  \r\n");

	
	while(1)
	{
		delay_ms(1000);            
		max30102_init();
		temp_num = max30102_Bus_Read(0x1f);
		printf("当前温度 = %d\r\n",temp_num);
	}

}

如需MAX30102相关资料及完整例程, 请关注公众号,首页回复MAX30102获取资料


转载:https://blog.csdn.net/lin5103151/article/details/109412943
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场