资讯详情

STM32通过IIC驱动MAX30102心率血氧传感器

STM32F103单片机通过IIC控制MAX30102心率血氧传感器

MAX30102的VCC引脚连接STM32F103mini单片机5伏引脚,GND连接5伏对应GND,SCL连PC12,SDA连PC11,INT连PA5。MAX30102其他引脚没用。

本代码可正常接收MAX30102心率血氧传感器返回red与ir心率血氧值可以正常计算。当心率或血氧值的计算结果错误时,相应的变量值为-999。

在工程文件中使用delay.h,sys.h,usart.h,myiic.h正点原子正式提供STM32F103mini单片机对应的源代码没有更改。

因此,本文只粘贴新添加剂。max30102.h(max30102驱动代码头文件),max30102.c(max30102驱动代码),algorithm.h(max30102心率血氧算法函数头文件),algorithm.c(max30102心率血氧算法函数文件)main.c的测试样例

main.c文件

#include "delay.h" #include "sys.h" #include "usart.h" #include "myiic.h" #include "max30102.h" #include "algorithm.h"  #define MAX_BRIGHTNESS 255 #define START 100 #define DATA_LENGTH 500   uint32_t aun_ir_buffer[DATA_LENGTH]; //IR LED sensor data int32_t n_ir_buffer_length;    //data length uint32_t aun_red_buffer[DATA_LENGTH];    //Red LED sensor data int32_t n_sp02; //SPO2 value int8_t ch_spo2_valid;   //indicator to show if the SP02 calculation is valid int32_t n_heart_rate;   //heart rate value int8_t  ch_hr_valid;    //indicator to show if the heart rate calculation is valid uint8_t uch_dummy;    int main(void)  { 
           uint32_t un_min, un_max, un_prev_data;  //variables to calculate the on-board LED brightness that reflects the heartbeats  int i;  int32_t n_brightness;  float f_temp;    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2  delay_init();       //延迟函数初始化   uart_init(115200);   //串口初始化为115200   IIC_Init();        maxim_max30102_reset(); //resets the MAX30102 // initialize serial communication at 115200 bits per second: //read and clear status register maxim_max30102_read_reg(0,&uch_dummy); maxim_max30102_init(); //initializes the MAX30102 n_brightness=0; un_min=0x3FFFF; un_max=0; n_ir_buffer_length=DATA_LENGTH; //buffer length of 100 stores 5 seconds of samples running at 100sps //read the first 500 samples, and determine the signal range for(i=0;i<n_ir_buffer_length;i++) { 
          while(PAin(5)==1); //wait until the interrupt pin asserts maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i)); //read from MAX30102 FIFO  if(un_min>aun_red_buffer[i]) un_min=aun_red_buffer[i]; //update signal min if(un_max<aun_red_buffer[i]) un_max=aun_red_buffer[i]; //update signal max printf("red=%i,", aun_red_buffer[i]); printf("ir=%i\r\n", aun_ir_buffer[i]); } un_prev_data=aun_red_buffer[i]; //calculate heart rate and SpO2 after first 500 samples (first 5 seconds of samples) maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid); while(1) { 
          i=0; un_min=0x3FFFF; un_max=0; //dumping the first 100 sets of samples in the memory and shift the last 400 sets of samples to the top for(i=START;i<DATA_LENGTH;i++) { 
          aun_red_buffer[i-START]=aun_red_buffer[i]; aun_ir_buffer[i-START]=aun_ir_buffer[i]; //update the signal min and max if(un_min>aun_red_buffer[i]) un_min=aun_red_buffer[i]; if(un_max<aun_red_buffer[i]) un_max=aun_red_buffer[i]; } //take 100 sets of samples before calculating the heart rate. for(i=400;i<DATA_LENGTH;i++) { 
          un_prev_data=aun_red_buffer[i-1]; while(PAin(5)==1); maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i)); if(aun_red_buffer[i]>un_prev_data)//just to determine the brightness of LED according to the deviation of adjacent two AD data { 
          f_temp=aun_red_buffer[i]-un_prev_data; f_temp/=(un_max-un_min); f_temp*=MAX_BRIGHTNESS; n_brightness-=(int)f_temp; if(n_brightness<0) n_brightness=0; } else { 
          f_temp=un_prev_data-aun_red_buffer[i]; f_temp/=(un_max-un_min); f_temp*=MAX_BRIGHTNESS; n_brightness+=(int)f_temp; if(n_brightness>MAX_BRIGHTNESS) n_brightness=MAX_BRIGHTNESS; } //send samples and calculation result to terminal program through UART // printf("red=%i,", aun_red_buffer[i]); // printf(" ir=%i,", aun_ir_buffer[i]); } maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid); printf(" HR=%i,", n_heart_rate); printf(" HRvalid=%i,", ch_hr_valid); printf(" SpO2=%i,", n_sp02); printf(" SPO2Valid=%i\r\n", ch_spo2_valid); } } 

max30102.h文件

/** \file max30102.h ****************************************************** * * Project: MAXREFDES117# * Filename: max30102.h * Description: This module is an embedded controller driver header file for MAX30102 * * Revision History: *\n 1-18-2016 Rev 01.00 GL Initial release. *\n * * -------------------------------------------------------------------- * * This code follows the following naming conventions: * * char ch_pmod_value * char (array) s_pmod_s_string[16] * float f_pmod_value * int32_t n_pmod_value * int32_t (array) an_pmod_value[16] * int16_t w_pmod_value * int16_t (array) aw_pmod_value[16] * uint16_t uw_pmod_value * uint16_t (array) auw_pmod_value[16] * uint8_t uch_pmod_value * uint8_t (array) auch_pmod_buffer[16] * uint32_t un_pmod_value * int32_t * pn_pmod_value * * ------------------------------------------------------------------------- */
/******************************************************************************* * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. ******************************************************************************* */
#ifndef MAX30102_H_
#define MAX30102_H_

#include "stm32f10x.h"
#include "stdbool.h"

#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_init(void);
bool maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led);
bool maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data);
bool maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data);
bool maxim_max30102_reset(void);
#endif /* MAX30102_H_ */

max30102.c文件

/** \file max30102.cpp ****************************************************** * * Project: MAXREFDES117# * Filename: max30102.cpp * Description: This module is an embedded controller driver for the MAX30102 * * Revision History: *\n 1-18-2016 Rev 01.00 GL Initial release. *\n */

#include "max30102.h"
#include "myiic.h"

#define max30102_WR_address 0xAE
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 */
{ 
        
    /* 第1步:发起I2C总线启动信号 */
    IIC_Start();

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

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

    /* 第4步:发送字节地址 */
    IIC_Send_Byte(uch_addr);
    if (IIC_Wait_Ack() != 0)
    { 
        
        goto cmd_fail;	/* EEPROM器件无应答 */
    }

    /* 第5步:开始写入数据 */
    IIC_Send_Byte(uch_data);

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

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

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
    /* 发送I2C总线停止信号 */
    IIC_Stop();
    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 */
{ 
        
    /* 第1步:发起I2C总线启动信号 */
    IIC_Start();

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

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

    /* 第4步:发送字节地址, */
    IIC_Send_Byte((uint8_t)uch_addr);
    if (IIC_Wait_Ack() != 0)
    { 
        
        goto cmd_fail;	/* EEPROM器件无应答 */
    }
    /* 第6步:重新启动I2C总线。下面开始读取数据 */
    IIC_Start();

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

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

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

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

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

bool maxim_max30102_init(void)
/** * \brief Initialize the MAX30102 * \par Details * This function initializes the MAX30102 * * \param None * * \retval true on success */
{ 
        
		GPIO_InitTypeDef GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC时钟
		GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试
		GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;//PA5
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //PA5设置成浮空输入,接MAX30102的INT数据转换是否完成的信号引脚 
		GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA5
    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, 0x6f)) //sample avg = 8, 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, 0x2F)) // SPO2_ADC range = 4096nA, SPO2 sample rate (400 Hz), LED pulseWidth (411uS)
        return false;

    if(!maxim_max30102_write_reg(REG_LED1_PA, 0x17))  //Choose value for ~ 4.5mA for LED1
        return false;
    if(!maxim_max30102_write_reg(REG_LED2_PA, 0x17))  // Choose value for ~ 4.5mA 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;
    uint8_t uch_temp;
    *pun_ir_led = 0;
    *pun_red_led = 0;
    maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
    maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);



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

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

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

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


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

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

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

    un_temp = IIC_Read_Byte();
    IIC_Ack();
    un_temp <<= 16;
    *pun_red_led += un_temp;
    un_temp = IIC_Read_Byte();
    IIC_Ack();
    un_temp <<= 8;
    *pun_red_led += un_temp;
    un_temp = IIC_Read_Byte();
    IIC_Ack();
    *pun_red_led += un_temp;

    un_temp = IIC_Read_Byte();
    IIC_Ack();
    un_temp <<= 16;
    *pun_ir_led += un_temp;
    un_temp = IIC_Read_Byte();
    IIC_Ack();
    un_temp <<= 8;
    *pun_ir_led += un_temp;
    un_temp = IIC_Read_Byte();
    IIC_Ack();
    *pun_ir_led += un_temp;
    *pun_red_led &= 0x03FFFF; //Mask MSB [23:18]
    *pun_ir_led &= 0x03FFFF; //Mask MSB [23:18]

    /* 发送I2C总线停止信号 */
    IIC_Stop();
    return true;
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
    /* 发送I2C总线停止信号 */
    IIC_Stop();
    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;
}


algorithm.h

/** \file algorithm.h ****************************************************** * * Project: MAXREFDES117# * Filename: algorithm.h * Description: This module is the heart rate/SpO2 calculation algorithm header file * * Revision History: *\n 1-18-2016 Rev 01.00 SK Initial release. *\n * * -------------------------------------------------------------------- * * This code follows the following naming conventions: * *\n char ch_pmod_value *\n char (array) s_pmod_s_string[16] *\n float f_pmod_value *\n int32_t n_pmod_value *\n int32_t (array) an_pmod_value[16] *\n int16_t w_pmod_value *\n int16_t (array) aw_pmod_value[16] *\n uint16_t uw_pmod_value *\n uint16_t (array) auw_pmod_value[16] *\n uint8_t uch_pmod_value *\n uint8_t (array) auch_pmod_buffer[16] *\n uint32_t un_pmod_value *\n int32_t * pn_pmod_value * * ------------------------------------------------------------------------- */
/******************************************************************************* * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. ******************************************************************************* */
#ifndef ALGORITHM_H_
#define ALGORITHM_H_
#include "stm32f10x.h"
#include "stdbool.h"

#define true 1
#define false 0
#define FS 50 //sampling frequency
#define BUFFER_SIZE (FS* 3) 
#define MA4_SIZE 4 // DONOT CHANGE
#define min(x,y) ((x) < (y) ? (x) : (y))


static  int32_t an_x[ BUFFER_SIZE]; //ir
static  int32_t an_y[ BUFFER_SIZE]; //red

void maxim_heart_rate_and_oxygen_saturation(uint32_t *pun_ir_buffer, int32_t n_ir_buffer_length, uint32_t *pun_red_buffer, int32_t *pn_spo2, int8_t *pch_spo2_valid, int32_t *pn_heart_rate, int8_t *pch_hr_valid);
void maxim_find_peaks(int32_t *pn_locs, int32_t *n_npks,  int32_t  *pn_x, int32_t n_size 

标签: exact传感器心率传感器模块lcd显示ys

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台