注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
anning865的个人空间 https://home.eeworld.com.cn/space-uid-363835.html [收藏] [复制] [分享] [RSS]
日志

MAX32630FTHR板的学习(三):MAX30102的初步使用及心率、血氧的测量原理

已有 23159 次阅读2017-8-6 17:22

        在上一篇帖子中,使用MAX32630FTHR板驱动了心率脉搏传感器Pulse sensor,得到了心率数值和脉搏的图像。这篇帖子介绍并研究一款美信公司生产的光学传感器MAX30102。
       美信公司的MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。它集成了一个红光LED和一个红外光LED、光电检测器、光器件,以及带环境光抑制的低噪声电子电路。MAX30102采用一个1.8V电源和一个独立的5.0V用于内部LED的电源,应用于可穿戴设备进行心率和血氧采集检测,佩戴于手指、耳垂和手腕等处。标准的I2C兼容的通信接口可以将采集到的数值传输给Arduino、KL25Z等单片机进行心率和血氧计算。此外,该芯片还可通过软件关断模块,待机电流接近为零,实现电源始终维持供电状态。正因为其优异的性能,该芯片被大量应用在了三星Galaxy S7手机。与前代产品MAX30100相比(MAX30100目前已经停产淘汰),MAX30102集成了玻璃盖可以有效排除外界和内部光干扰,拥有最优可靠的性能。
       与Pulse sensor这种传感器相比,MAX30102的有点在于:
1.集成度高:MAX30102将两个发光LED、光电检测二极管、ADC、环境光抑制电路和光学机械外壳都集成在了一起,形成了一个完整模块。这样的优势就是体积小、能耗小、外界干扰小,易于集成系统。
2.数字输出:MAX30102本身自带18位高精度ADC,使用I2C接口与外接MCU通信。而且自身还有FIFO,可以减轻MCU负担,降低功耗。
3.功能丰富:MAX30102集成了LED驱动电路,可以根据不同情况调节LED电流,采样率也可以根据不同应用进行选择。此外还集成了片上温度传感器,可以随时监测片上温度(对血氧饱和度计算有用)。
       正是有以上一些优点,现在的模拟集成前端(AFE)都走向了集成化、小型化、数字化的方向,模拟电路的门槛越来越低了。
       首先看一下MAX30102的结构框图:

图1、MAX30102的结构框图


       MAX30102的发光部分包括两个LED,一个是红光LED(660nm),另一个是红外光LED(880nm),这个是测量血氧饱和度SPO2最常见的配置。接收部分是一个对可见光和红外光都敏感的光电二极管,其接收的光强度信号转换为电流信号,经过环境光消除电路后,最后被自带的18位ADC进行采样转化,至此模拟部分完成。AD转化后的数字经过数字滤波后储存在数据寄存器中,最后可通过I2C总线被外接MCU读取。在硬件上,LED的电源和其他部分的电源不是同一个,因为LED为了保证足够的出射光强,需要瞬间大电流(最大50ma),这就要求LED的正向电压足够大(要求3.1V以上)。而其余的AD转换和I2C总线部分,为了实现低功耗要求电压足够小(要求1.8V),所以传感器需要两路独立的电源。此外,由于LED电源会产生瞬间大电流,所以电源引脚附近要加一个大电容减轻对电源电压的影响。

图2、MAX30102引脚图


传统的脉搏测量方法主要有三种:一是从心电信号中提取;二是从测量血压时压力传感器测到的波动来计算脉率;三是光电容积法。前两种方法提取信号都会限制病人的活动,如果长时间使用会增加病人生理和心理上的不舒适感。而光电容积法脉搏测量作为监护测量中最普遍的方法之一,其具有方法简单、佩戴方便、可靠性高等特点。
光电容积法的基本原理是利用人体组织在血管搏动时造成透光率不同来进行脉搏和血氧饱和度测量的。其使用的传感器由光源和光电变换器两部分组成,通过绑带或夹子固定在病人的手指、手腕或耳垂上。光源一般采用对动脉血中氧合血红蛋白(HbO2)和去氧血红蛋白(Hb)有选择性的特定波长的发光二极管(一般选用660nm附近的红光和900nm附近的红外光)。当光束透过人体外周血管,由于动脉搏动充血容积变化导致这束光的透光率发生改变,此时由光电变换器接收经人体组织反射的光线,转变为电信号并将其放大和输出。由于脉搏是随心脏的搏动而周期性变化的信号,动脉血管容积也呈现周期性变化,因此光电变换器的电信号变化周期就是脉搏率。同时根据血氧饱和度的定义,其表示为:
图3、血氧饱和度定义式

图4、不同波长下氧合血红蛋白(HbO2)和去氧血红蛋白(Hb)的吸收
     MAX30102本身集成了完整的发光LED及驱动部分,光感应和AD转换部分,环境光干扰消除及数字滤波部分,只将数字接口留给用户,极大地减轻了用户的设计负担。用户只需要使用单片机通过硬件I2C或者模拟I2C接口来读取MAX30102本身的FIFO,就可以得到转换后的光强度数值,通过编写相应算法就可以得到心率值和血氧饱和度。
    本来为了方便验证MAX30102和MAX32630FTHR板配合使用,本人从淘宝上买了一个现成的MAX30102模块。但是让人意想不到的是,这个模块本身设计存在很大问题,它的I2C总线上拉电压被强制固定在1.8V上了,这导致了该模块与IO口为3.3v,5v电平的单片机无法正常通信!真的是脑残的设计啊!为了找这个原因,浪费了很多时间,后来在GITHUB上看到有外国人抱怨,我才明白!最后只能飞线解决。

图5、X宝上某有问题的模块设计


图6、问题模块及飞线解决方法

       这次简单验证一下MAX32630FTHR板可以通过I2C总线对MAX30102进行通信,所以在MBED上写了读取MAX30102片上温度的程序,并通过串口打印输出温度结果。具体程序如下:
[C] 纯文本查看 复制代码
#include "mbed.h"
#include "max32630fthr.h"

#define false 0
#define true 1
MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
Serial pc(USBTX, USBRX);//USB TO SERIAL
DigitalIn INT(P3_2);  //pin P3.2 connects to the interrupt output pin of the MAX30102
I2C i2cm1(P3_4, P3_5);


#define I2C_WRITE_ADDR 0xAE
#define I2C_READ_ADDR 0xAF

//register addresses
#define REG_INTR_STATUS_1 0x00
#define REG_INTR_STATUS_2 0x01
#define REG_INTR_ENABLE_1 0x02
#define REG_INTR_ENABLE_2 0x03
#define REG_FIFO_WR_PTR 0x04
#define REG_OVF_COUNTER 0x05
#define REG_FIFO_RD_PTR 0x06
#define REG_FIFO_DATA 0x07
#define REG_FIFO_CONFIG 0x08
#define REG_MODE_CONFIG 0x09
#define REG_SPO2_CONFIG 0x0A
#define REG_LED1_PA 0x0C
#define REG_LED2_PA 0x0D
#define REG_PILOT_PA 0x10
#define REG_MULTI_LED_CTRL1 0x11
#define REG_MULTI_LED_CTRL2 0x12
#define REG_TEMP_INTR 0x1F
#define REG_TEMP_FRAC 0x20
#define REG_TEMP_CONFIG 0x21
#define REG_PROX_INT_THRESH 0x30
#define REG_REV_ID 0xFE
#define REG_PART_ID 0xFF

bool maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data)
/**
* \brief        Write a value to a MAX30102 register
* \par          Details
*               This function writes a value to a MAX30102 register
*
* \param[in]    uch_addr    - register address
* \param[in]    uch_data    - register data
*
* \retval       true on success
*/
{
  char ach_i2c_data[2];
  ach_i2c_data[0]=uch_addr;
  ach_i2c_data[1]=uch_data;
  
  if(i2cm1.write(I2C_WRITE_ADDR, ach_i2c_data, 2, false)==0)
    return true;
  else
    return false;
}

bool maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data)
/**
* \brief        Read a MAX30102 register
* \par          Details
*               This function reads a MAX30102 register
*
* \param[in]    uch_addr    - register address
* \param[out]   puch_data    - pointer that stores the register data
*
* \retval       true on success
*/
{
  char ch_i2c_data;
  ch_i2c_data=uch_addr;
  if(i2cm1.write(I2C_WRITE_ADDR, &ch_i2c_data, 1, true)!=0)
    return false;
  if(i2cm1.read(I2C_READ_ADDR, &ch_i2c_data, 1, false)==0)
  {
    *puch_data=(uint8_t) ch_i2c_data;
    return true;
  }
  else
    return false;
}

bool maxim_max30102_reset()
/**
* \brief        Reset the MAX30102
* \par          Details
*               This function resets the MAX30102
*
* \param        None
*
* \retval       true on success
*/
{
    if(!maxim_max30102_write_reg(REG_MODE_CONFIG,0x40))
        return false;
    else
        return true;   
}

bool maxim_max30102_init()
/**
* \brief        Initialize the MAX30102
* \par          Details
*               This function initializes the MAX30102
*
* \param        None
*
* \retval       true on success
*/
{
  if(!maxim_max30102_write_reg(REG_INTR_ENABLE_1,0xc0)) // INTR setting
    return false;
  if(!maxim_max30102_write_reg(REG_INTR_ENABLE_2,0x02))
    return false;
  if(!maxim_max30102_write_reg(REG_FIFO_WR_PTR,0x00))  //FIFO_WR_PTR[4:0]
    return false;
  if(!maxim_max30102_write_reg(REG_OVF_COUNTER,0x00))  //OVF_COUNTER[4:0]
    return false;
  if(!maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00))  //FIFO_RD_PTR[4:0]
    return false;
  if(!maxim_max30102_write_reg(REG_FIFO_CONFIG,0x0f))  //sample avg = 1, fifo rollover=false, fifo almost full = 17
    return false;
  if(!maxim_max30102_write_reg(REG_MODE_CONFIG,0x03))   //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
    return false;
  if(!maxim_max30102_write_reg(REG_SPO2_CONFIG,0x27))  // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
    return false;
  
  if(!maxim_max30102_write_reg(REG_LED1_PA,0x24))   //Choose value for ~ 7mA for LED1
    return false;
  if(!maxim_max30102_write_reg(REG_LED2_PA,0x24))   // Choose value for ~ 7mA for LED2
    return false;
  if(!maxim_max30102_write_reg(REG_PILOT_PA,0x7f))   // Choose value for ~ 25mA for Pilot LED
    return false;
if(!maxim_max30102_write_reg(REG_TEMP_CONFIG,0x01))   // En temp
    return false;
   
  return true;  
}

int main()
{
    uint8_t temp_inter,temp_fra;
    float temp_value;
   
    maxim_max30102_reset(); //resets the MAX30102
    // initialize serial communication at 9600 bits per second:
    pc.baud(9600);
    pc.format(8,SerialBase::None,1);
    pc.printf("ready to go!");
    wait(1);
   
    //read and clear status register
    maxim_max30102_read_reg(0,&temp_inter);
    maxim_max30102_init();
   
    while(1)
    {
    while(INT.read()==1);
    maxim_max30102_read_reg(REG_TEMP_INTR,&temp_inter);
    maxim_max30102_read_reg(REG_TEMP_FRAC,&temp_fra);
    temp_value=temp_inter+temp_fra*0.0625;
    pc.printf("temperature is %6.4f \n\r", temp_value);
    }
}

上面的代码在MBED平台记得添加MAX32630FTHR和MBED库文件。

图7、实验图片(MAX30102的LED已经点亮了)


图8、串口输出温度数据

        最后KEIL的PACK包已经由论坛发出了,MBED的程序终于可以导出到KEIL调试了,但是我在下载选项中没有找到MAX32630的FLASH选项,请教了几个坛友,希望有成功者指点一二。





本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章