电子模块|心率血氧传感器模块MAX30102及其驱动代码

04-27 3978阅读 0评论

电子模块|心率血氧传感器模块MAX30102及其驱动代码

  • 实物照片
  • 模块简介
  • 工作原理
  • 原理图及引脚说明
  • STM32软件驱动
    • IIC通信代码
    • 数值转换代码
    • main函数
    • 结果

      实物照片

      电子模块|心率血氧传感器模块MAX30102及其驱动代码 第1张

      电子模块|心率血氧传感器模块MAX30102及其驱动代码 第2张

      模块简介

      MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。

      它集成了一个红光LED和一个红外光LED、光电检测器、光器件,以及带环境光抑制的低噪声电子电路。

      MAX30102采用一个1.8V电源和一个独立的5.0V用于内部LED的电源,应用于可穿戴设备进行心率和血氧采集检测,佩戴于手指点耳垂和手腕处。

      标准的I2C兼容的通信接口可以将采集到的数值传输给Arduino、KL25Z、STM32、STC51等单片机进行心率和血氧计算。

      此外,该芯片还可以通过软件关断模块,待机电流接近为零,实现电源始终维持供电状态。

      主要参数:

      产品名称MAX30102 心率模块
      LED峰值波长器660nm/880nm
      LED供电电压3.3 ~ 5V
      检测信号类型光反射信号(PPG)
      输出信号接口I2C接口
      通信接口电压1.8 ~ 3.3V ~ 5V(可选)

      产品尺寸:

      电子模块|心率血氧传感器模块MAX30102及其驱动代码 第3张

      工作原理

      光溶积法:利用人体组织在血管搏动时造成透光率不同来进行脉搏和血氧饱和度测量

      光源:采用对动脉血中痒合血红蛋白(HbO2)和血红蛋白(Hb)有选择性的特定波长的发光二极管

      透光率转化为电信号:动脉搏动充血容积变化导致这束光的透光率发送改变,此时由光电变换接收经人体组织反射光线,转变为电信号并将其放大输出。

      电子模块|心率血氧传感器模块MAX30102及其驱动代码 第4张

      原理图及引脚说明

      电子模块|心率血氧传感器模块MAX30102及其驱动代码 第5张

      电子模块|心率血氧传感器模块MAX30102及其驱动代码 第2张

      引脚说明

      名称管教定义
      VIN电源输入 1.6V-5.5V
      3位焊盘选择总线的上拉电平,取决于引脚主控电压可选1.8v或者3.3v
      SDAIIC-SDA
      SCLIIC-SCL
      GND
      INTINT 低电平有效中断(漏极开路)MAX30102 的中断引脚
      IRDIR_DRV IR LED阴极和LED驱动器连接点 一般不接
      RDR_DRV 红色LED阴极和LED驱动器连接点 一般不接

      STM32软件驱动

      使用STM32F103C8T6最小系统开发板验证。

      接线如下:

      MAX30102模块接口:PB9-SDA,PB8-SCL,PB7-INT

      PA2/PA3为串口传输口TX和RX,波特率设置为115200

      PC13为显示LED

      IIC通信代码

      #include "mbed.h"
      #include "MAX30102.h"
      I2C i2c(I2C_SDA, I2C_SCL);//SDA-PB9,SCL-PB8
      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(i2c.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(i2c.write(I2C_WRITE_ADDR, &ch_i2c_data, 1, true)!=0)
          return false;
        if(i2c.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_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,0x00))
          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;
        return true;  
      }
      bool maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led)
      /**
      * \brief        Read a set of samples from the MAX30102 FIFO register
      * \par          Details
      *               This function reads a set of samples from the MAX30102 FIFO register
      *
      * \param[out]   *pun_red_led   - pointer that stores the red LED reading data
      * \param[out]   *pun_ir_led    - pointer that stores the IR LED reading data
      *
      * \retval       true on success
      */
      {
        uint32_t un_temp;
        unsigned char uch_temp;
        *pun_red_led=0;
        *pun_ir_led=0;
        char ach_i2c_data[6];
        
        //read and clear status register
        maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
        maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
        
        ach_i2c_data[0]=REG_FIFO_DATA;
        if(i2c.write(I2C_WRITE_ADDR, ach_i2c_data, 1, true)!=0)
          return false;
        if(i2c.read(I2C_READ_ADDR, ach_i2c_data, 6, false)!=0)
        {
          return false;
        }
        un_temp=(unsigned char) ach_i2c_data[0];
        un_temp
          if(!maxim_max30102_write_reg(REG_MODE_CONFIG,0x40))
              return false;
          else
              return true;    
      }
      
          uint32_t un_ir_mean ,un_only_once ;
          int32_t k ,n_i_ratio_count;
          int32_t i, s, m, n_exact_ir_valley_locs_count ,n_middle_idx;
          int32_t n_th1, n_npks,n_c_min;      
          int32_t an_ir_valley_locs[15] ;
          int32_t an_exact_ir_valley_locs[15] ;
          int32_t an_dx_peak_locs[15] ;
          int32_t n_peak_interval_sum;
          
          int32_t n_y_ac, n_x_ac;
          int32_t n_spo2_calc; 
          int32_t n_y_dc_max, n_x_dc_max; 
          int32_t n_y_dc_max_idx, n_x_dc_max_idx; 
          int32_t an_ratio[5],n_ratio_average; 
          int32_t n_nume,  n_denom ;
          // remove DC of ir signal    
          un_ir_mean =0; 
          for (k=0 ; k
              n_denom= ( an_x[k]+an_x[k+1]+ an_x[k+2]+ an_x[k+3]);
              an_x[k]=  n_denom/(int32_t)4; 
          }
          // get difference of smoothed IR signal
          
          for( k=0; k
              an_dx[k] =  ( an_dx[k]+an_dx[k+1])/2 ;
          }
          
          // hamming window
          // flip wave form so that we can detect valley with peak detector
          for ( i=0 ; i
              s= 0;
              for( k=i; k
                  s -= an_dx[k] *auw_hamm[k-i] ; 
                           }
              an_dx[i]= s/ (int32_t)1146; // divide by sum of auw_hamm 
          }
       
          n_th1=0; // threshold calculation
          for ( k=0 ; k
              n_th1 += ((an_dx[k]0)? an_dx[k] : ((int32_t)0-an_dx[k])) ;
          }
          n_th1= n_th1/ ( BUFFER_SIZE-HAMMING_SIZE);
          // peak location is acutally index for sharpest location of raw signal since we flipped the signal         
          maxim_find_peaks( an_dx_peak_locs, &n_npks, an_dx, BUFFER_SIZE-HAMMING_SIZE, n_th1, 8, 5 );//peak_height, peak_distance, max_num_peaks 
          n_peak_interval_sum =0;
          if (n_npks=2){
              for (k=1; k
              *pn_heart_rate = -999;
              *pch_hr_valid  = 0;
          }
                  
          for ( k=0 ; k
              an_x[k] =  pun_ir_buffer[k] ; 
              an_y[k] =  pun_red_buffer[k] ; 
          }
          // find precise min near an_ir_valley_locs
          n_exact_ir_valley_locs_count =0; 
          for(k=0 ; k
              un_only_once =1;
              m=an_ir_valley_locs[k];
              n_c_min= 16777216;//2^24;
              if (m+5 

免责声明
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明。
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所
提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何
损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在
转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并白负版权等法律责任。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,3978人围观)

还没有评论,来说两句吧...

目录[+]