Skip to content
  • info@aiwedo.com
CONTACT US
ABOUT US
REQUEST QUOTE
SUPPORT
AIWEDO LOGO
  • HOME
  • PRODUCT
  • Free Consulting
  • Solution
  • BLOG
    • Tech
    • Feature
    • News
  • CONTACT US
    • company
    • culture
    • Support
    • Request Quote
HOME / Driving MAX30102 Heart Rate and Blood Oxygen Sensor with STM32+HAL Library
SOLUTION POST

Driving MAX30102 Heart Rate and Blood Oxygen Sensor with STM32+HAL Library

Hardware Development Board: STM32F407VET6

Software Platform: CubeMX+Keil+VSCode

Working Principle of MAX30102 Heart Rate and Blood Oxygen Sensor

The MAX30102 sensor is a highly integrated sensor that combines infrared light source, photoelectric detector, and signal processing circuits, primarily used for heart rate and blood oxygen saturation measurement. The following are the main features and working principles of the MAX30102 sensor:
Infrared Light Source: The MAX30102 sensor has an integrated infrared LED light source used to illuminate the skin surface. The reflection characteristics of infrared light in blood can be used to measure heart rate and blood oxygen saturation.

Photoelectric Detector: The sensor also integrates a photoelectric detector to receive light signals reflected from the skin surface. These light signals contain information about the absorption of infrared light by the blood, and the level of blood oxygen saturation can be inferred from the degree of absorption.

Signal Processing Circuit: The MAX30102 sensor also incorporates a series of signal processing circuits for filtering, amplifying, and digitizing the received light signals. The processed signals can be directly output to a microcontroller for further processing and analysis.

Working Principle: The working principle of the MAX30102 sensor is based on the absorption characteristics of infrared light in blood. Infrared light can penetrate the skin and be absorbed by blood. Oxygenated and deoxygenated blood absorb infrared light to different degrees, so the blood’s oxygenation state can be inferred by measuring infrared light absorption. The sensor uses LED light to illuminate the skin surface, then receives the light signals reflected through the skin via the photoelectric detector, and calculates heart rate and blood oxygen saturation based on changes in the light signals.

In summary, the MAX30102 sensor measures heart rate and blood oxygen saturation through infrared light sources and photoelectric detectors. It features high integration, high precision, and low cost, with widespread applications in medical monitoring, health monitoring, and other fields.

2.CubeMX Configuration

2.1 Configure Programming Environment

MAX30102 Configure Programming Environment

2.2 Enable External Clock

MAX30102 Enable External Clock

2.3 Configure Clock Tree

MAX30102 Configure Clock Tree

2.4 Configure UART

For printing debug output

2.5 Configure I2C

2.6 Complete Configuration and Export Project

Complete Configuration and Export Project

3.Program

3.1 MAX30102.h

				
					/**
 * ************************************************************************
 * 
 * @file MAX30102.h
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#ifndef _MAX30102_H
#define _MAX30102_H

#include "main.h"                  // Device header
#include "i2c.h"
#include "stdbool.h"

#define MAX30102_Device_address 			0xAE

//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

#define SAMPLES_PER_SECOND 					100	//Detection frequency

uint8_t Max30102_reset(void);
void MAX30102_Config(void);
void max30102_read_fifo(void);

uint8_t max30102_write_reg(uint8_t addr, uint8_t data);
uint8_t max30102_read_reg(uint8_t addr );

#endif




				
			

3.2 MAX30102.c

				
					/**
 * ************************************************************************
 * 
 * @file MAX30102.c
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#include "MAX30102.h"

uint16_t fifo_red;  //define FIFO Red
uint16_t fifo_ir;   //define FIFO ir

/**
 * ************************************************************************
 * @brief  Write a value to the MAX30102 register
 * 
 * @param[in] addr  register addr
 * @param[in] data  data transmission
 * 
 * @return 
 * ************************************************************************
 */
uint8_t max30102_write_reg(uint8_t addr, uint8_t data)
{
  HAL_I2C_Mem_Write(&hi2c1, MAX30102_Device_address,	addr,	1,	&data,1,HAL_MAX_DELAY);
  return 1;
}


/**
 * ************************************************************************
 * @brief  Read a value from the MAX30102 register
 * 
 * @param[in] addr  register address
 * 
 * @return 
 * ************************************************************************
 */
uint8_t max30102_read_reg(uint8_t addr )
{
  uint8_t data=0;
  HAL_I2C_Mem_Read(&hi2c1, MAX30102_Device_address, addr, 1, &data, 1, HAL_MAX_DELAY);
  return data;
}


/**
 * ************************************************************************
 * @brief Max30102 reset sensor
 * 
 * 
 * @return 
 * ************************************************************************
 */
uint8_t Max30102_reset(void)
{
	if(max30102_write_reg(REG_MODE_CONFIG, 0x40))
        return 1;
    else
        return 0;    
}

/**
 * ************************************************************************
 * @brief MAX30102 sensor mode config
 * 
 * 
 * ************************************************************************
 */
void MAX30102_Config(void)
{
	max30102_write_reg(REG_INTR_ENABLE_1,0xc0); INTR setting
	max30102_write_reg(REG_INTR_ENABLE_2,0x00);//
	max30102_write_reg(REG_FIFO_WR_PTR,0x00);//FIFO_WR_PTR[4:0]
	max30102_write_reg(REG_OVF_COUNTER,0x00);//OVF_COUNTER[4:0]
	max30102_write_reg(REG_FIFO_RD_PTR,0x00);//FIFO_RD_PTR[4:0]
	
	max30102_write_reg(REG_FIFO_CONFIG,0x0f);//sample avg = 1, fifo rollover=false, fifo almost full = 17
	max30102_write_reg(REG_MODE_CONFIG,0x03);//0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
	max30102_write_reg(REG_SPO2_CONFIG,0x27);	// SPO2_ADC range = 4096nA, SPO2 sample rate (50 Hz), LED pulseWidth (400uS)  
	max30102_write_reg(REG_LED1_PA,0x32);//Choose value for ~ 10mA for LED1
	max30102_write_reg(REG_LED2_PA,0x32);// Choose value for ~ 10mA for LED2
	max30102_write_reg(REG_PILOT_PA,0x7f);// Choose value for ~ 25mA for Pilot LED
}

/**
 * ************************************************************************
 * @brief read FIFO register data
 * 
 * 
 * ************************************************************************
 */
void max30102_read_fifo(void)
{
  uint16_t un_temp;
  fifo_red=0;
  fifo_ir=0;
  uint8_t ach_i2c_data[6];
  
  //read and clear status register
  max30102_read_reg(REG_INTR_STATUS_1);
  max30102_read_reg(REG_INTR_STATUS_2);
  
  ach_i2c_data[0]=REG_FIFO_DATA;
	
	HAL_I2C_Mem_Read(&hi2c1,MAX30102_Device_address,REG_FIFO_DATA,1,ach_i2c_data,6,HAL_MAX_DELAY);
	
  un_temp=ach_i2c_data[0];
  un_temp<<=14;
  fifo_red+=un_temp;
  un_temp=ach_i2c_data[1];
  un_temp<<=6;
  fifo_red+=un_temp;
  un_temp=ach_i2c_data[2];
	un_temp>>=2;
  fifo_red+=un_temp;
  
  un_temp=ach_i2c_data[3];
  un_temp<<=14;
  fifo_ir+=un_temp;
  un_temp=ach_i2c_data[4];
  un_temp<<=6;
  fifo_ir+=un_temp;
  un_temp=ach_i2c_data[5];
	un_temp>>=2;
  fifo_ir+=un_temp;
	
	if(fifo_ir<=10000)
	{
		fifo_ir=0;
	}
	if(fifo_red<=10000)
	{
		fifo_red=0;
	}
}




				
			

3.3 algorithm.h

				
					/**
 * ************************************************************************
 * 
 * @file algorithm.h
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#ifndef __ALGORITHM_H
#define __ALGORITHM_H

#define FFT_N 			1024    
#define START_INDEX 	8  		

struct compx     	
{
	float real;
	float imag;
};  

typedef struct		
{
	float w;
	int init;
	float a;
}DC_FilterData;		


typedef struct		
{
	float v0;
	float v1;
}BW_FilterData;		



double my_floor(double x);

double my_fmod(double x, double y);

double XSin( double x );

double XCos( double x );

int qsqrt(int a);


struct compx EE(struct compx a,struct compx b);

void FFT(struct compx *xin);

int find_max_num_index(struct compx *data,int count);
int dc_filter(int input,DC_FilterData * df);
int bw_filter(int input,BW_FilterData * bw);


#endif



				
			

3.4 algorithm.c

				
					/**
 * ************************************************************************
 * 
 * @file algorithm.c
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#include "algorithm.h"
#include "stm32f4xx.h" 


#define XPI         (3.1415926535897932384626433832795)				//define PI
#define XENTRY      (100)
#define XINCL       (XPI/2/XENTRY)									
#define PI 			3.1415926535897932384626433832795028841971    	


/**
 * ************************************************************************
 * @brief
 * ************************************************************************
 */
static const double XSinTbl[] = 
{
	0.00000000000000000  , 0.015707317311820675 , 
	0.031410759078128292 , 0.047106450709642665 , 
	0.062790519529313374 , 0.078459095727844944 , 
	0.094108313318514325 , 0.10973431109104528  , 
	0.12533323356430426  , 0.14090123193758267  ,
	0.15643446504023087  , 0.17192910027940955  , 
	0.18738131458572463  , 0.20278729535651249  , 
	0.21814324139654256  , 0.23344536385590542  , 
	0.24868988716485479  , 0.26387304996537292  , 
	0.27899110603922928  , 0.29404032523230400  ,
	0.30901699437494740  , 0.32391741819814940  , 
	0.33873792024529142  , 0.35347484377925714  , 
	0.36812455268467797  , 0.38268343236508978  , 
	0.39714789063478062  , 0.41151435860510882  , 
	0.42577929156507272  , 0.43993916985591514  ,
	0.45399049973954680  , 0.46792981426057340  , 
	0.48175367410171532  , 0.49545866843240760  , 
	0.50904141575037132  , 0.52249856471594880  , 
	0.53582679497899666  , 0.54902281799813180  , 
	0.56208337785213058  , 0.57500525204327857  ,
	0.58778525229247314  , 0.60042022532588402  , 
	0.61290705365297649  , 0.62524265633570519  , 
	0.63742398974868975  , 0.64944804833018377  , 
	0.66131186532365183  , 0.67301251350977331  , 
	0.68454710592868873  , 0.69591279659231442  ,
	0.70710678118654757  , 0.71812629776318881  , 
	0.72896862742141155  , 0.73963109497860968  , 
	0.75011106963045959  , 0.76040596560003104  , 
	0.77051324277578925  , 0.78043040733832969  , 
	0.79015501237569041  , 0.79968465848709058  ,
	0.80901699437494745  , 0.81814971742502351  , 
	0.82708057427456183  , 0.83580736136827027  , 
	0.84432792550201508  , 0.85264016435409218  , 
	0.86074202700394364  , 0.86863151443819120  , 
	0.87630668004386369  , 0.88376563008869347  ,
	0.89100652418836779  , 0.89802757576061565  , 
	0.90482705246601958  , 0.91140327663544529  , 
	0.91775462568398114  , 0.92387953251128674  , 
	0.92977648588825146  , 0.93544403082986738  , 
	0.94088076895422557  , 0.94608535882754530  ,
	0.95105651629515353  , 0.95579301479833012  , 
	0.96029368567694307  , 0.96455741845779808  , 
	0.96858316112863108  , 0.97236992039767667  , 
	0.97591676193874743  , 0.97922281062176575  , 
	0.98228725072868872  , 0.98510932615477398  ,
	0.98768834059513777  , 0.99002365771655754  , 
	0.99211470131447788  , 0.99396095545517971  , 
	0.99556196460308000  , 0.99691733373312796  , 
	0.99802672842827156  , 0.99888987496197001  , 
	0.99950656036573160  , 0.99987663248166059  ,
	1.00000000000000000  
};


/**
 * ************************************************************************
 * @brief
 * 
 * @param[in] x
 * 
 * @return 
 * ************************************************************************
 */
double my_floor(double x)
{
	double y=x;
    if( (*( ( (int *) &y)+1) & 0x80000000)  != 0) //or if(x<0)
        return (float)((int)x)-1;
    else
        return (float)((int)x);
}


/**
 * ************************************************************************
 * @brief 
 * 
 * @param[in] x  1
 * @param[in] y  2
 * @note	
 * @return 
 * ************************************************************************
 */
double my_fmod(double x, double y)
{
	double temp, ret;

	if (y == 0.0)
		return 0.0;
	temp = my_floor(x/y);
   ret = x - temp * y;
	if ((x < 0.0) != (y < 0.0))
		ret = ret - y;
	return ret;
}


/**
 * ************************************************************************
 * @brief
 * 
 * @param[in] x ang
 * 
 * @return 
 * 
 * @note 
 * ************************************************************************
 */
double XSin( double x )
{
    int s = 0 , n;
    double dx , sx , cx;
    if( x < 0 )
        s = 1 , x = -x;
    x = my_fmod( x , 2 * XPI );
    if( x > XPI )
        s = !s , x -= XPI;
    if( x > XPI / 2 )
        x = XPI - x;
    n = (int)( x / XINCL );
    dx = x - n * XINCL;
    if( dx > XINCL / 2 )
        ++n , dx -= XINCL;
    sx = XSinTbl[n];
    cx = XSinTbl[XENTRY-n];
    x = sx + dx*cx - (dx*dx)*sx/2
        - (dx*dx*dx)*cx/6 
        + (dx*dx*dx*dx)*sx/24;

    return s ? -x : x;
}


/**
 * ************************************************************************
 * @brief 
 * 
 * @param[in] x ang
 * 
 * @return 
 * ************************************************************************
 */
double XCos( double x )
{
    return XSin( x + XPI/2 );
}


/**
 * ************************************************************************
 * @brief
 * 
 * @param[in] a 
 * 
 * @return 
 * ************************************************************************
 */
int qsqrt(int a)
{
	uint32_t rem = 0, root = 0, divisor = 0;
	uint16_t i;
	for(i=0; i<16; i++)
	{
		root <<= 1;
		rem = ((rem << 2) + (a>>30));
		a <<= 2;
		divisor = (root << 1) + 1;
		if(divisor <= rem)
		{
			rem -= divisor;
			root++;
		}
	}
	return root;
}


/**
 * ************************************************************************
 * @brief 
 * 
 * @param[in] a 
 * @param[in] b  
 * @note 
 * @return 
 * ************************************************************************
 */
struct compx EE(struct compx a,struct compx b)
{
	struct compx c;
	c.real=a.real*b.real-a.imag*b.imag;
	c.imag=a.real*b.imag+a.imag*b.real;
	return(c);
}


/**
 * ************************************************************************
 * @brief (FFT)
 * 
 * @param[in] xin  
 * 
 * ************************************************************************
 */
void FFT(struct compx *xin)
{
	int f,m,nv2,nm1,i,k,l,j=0;
	struct compx u,w,t;

	nv2=FFT_N/2;                  
	nm1=FFT_N-1;  
	for(i=0;i<nm1;i++)        
	{
		if(i<j)                   
		{
			t=xin[j];           
			xin[j]=xin[i];
			xin[i]=t;
		}
		k=nv2;                    
		
		while(k<=j)                
		{           
			j=j-k;                 
			k=k/2;                 
		}
		
		j=j+k;                   
	}

	{  //FFT运算核,使用蝶形运算完成FFT运算
		int le,lei,ip;                           
		f=FFT_N;
		for(l=1;(f=f/2)!=1;l++)                  
			;
		for(m=1;m<=l;m++)         
		{                                           
			le=2<<(m-1);                            
			lei=le/2;                               
			u.real=1.0;                             
			u.imag=0.0;
			w.real=XCos(PI/lei);                     
			w.imag=-XSin(PI/lei);
			for(j=0;j<=lei-1;j++)                   
			{
				for(i=j;i<=FFT_N-1;i=i+le)            
				{
					ip=i+lei;                           
					t=EE(xin[ip],u);                    
					xin[ip].real=xin[i].real-t.real;
					xin[ip].imag=xin[i].imag-t.imag;
					xin[i].real=xin[i].real+t.real;
					xin[i].imag=xin[i].imag+t.imag;
				}
				u=EE(u,w);                          
			}
		}
	}
}


/**
 * ************************************************************************
 * @brief 
 * 
 * @param[in] data  Comment
 * @param[in] count  Comment
 * 
 * @return 
 * ************************************************************************
 */
int find_max_num_index(struct compx *data,int count)
{
	int i=START_INDEX;
	int max_num_index = i;
	float temp = data[i].real;
	for(i=START_INDEX;i<count;i++)
	{
		if(temp < data[i].real)
		{
			temp = data[i].real;
			max_num_index = i;
		}
	}
	return max_num_index; 
}


/**
 * ************************************************************************
 * @brief
 * 
 * @param[in] input  
 * @param[in] df  Comment
 * 
 * @return 
 * ************************************************************************
 */
int dc_filter(int input,DC_FilterData * df) 
{

	float new_w  = input + df->w * df->a;
	int16_t result = 5*(new_w - df->w);
	df->w = new_w;
	
	return result;
}


/**
 * ************************************************************************
 * @brief 
 * 
 * @param[in] input  
 * @param[in] bw  Comment
 * 
 * @return 
 * ************************************************************************
 */
int bw_filter(int input,BW_FilterData * bw) 
{
    bw->v0 = bw->v1;
    
    bw->v1 = (1.241106190967544882e-2*input)+(0.97517787618064910582 * bw->v0);
    return bw->v0 + bw->v1;
}




				
			

3.5 blood.h

				
					/**
 * ************************************************************************
 * 
 * @file blood.h
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#ifndef _BLOOD_H
#define _BLOOD_H

#include "main.h"
#include "MAX30102.h"
#include "algorithm.h"
#include "math.h"



void blood_data_translate(void);
void blood_data_update(void);
void blood_Loop(void);

#endif




				
			

3.6 blood.c

				
					/**
 * ************************************************************************
 * 
 * @file blood.c
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#include "blood.h"
#include "usart.h"

int heart;		
float SpO2;		


extern uint16_t fifo_red;	
extern uint16_t fifo_ir;		

uint16_t g_fft_index = 0;         	 	
struct compx s1[FFT_N+16];           	
struct compx s2[FFT_N+16];           	



#define CORRECTED_VALUE			47   			

/**
 * ************************************************************************
 * @brief 
 * @note 
 * ************************************************************************
 */
void blood_data_update(void)
{

	g_fft_index=0;
	while(g_fft_index < FFT_N)
	{
		while(max30102_read_reg(REG_INTR_STATUS_1)&0x40 )
		{
			
			max30102_read_fifo();  //read from MAX30102 FIFO2
			
			if(g_fft_index < FFT_N)
			{
			
				s1[g_fft_index].real = fifo_red;
				s1[g_fft_index].imag= 0;
				s2[g_fft_index].real = fifo_ir;
				s2[g_fft_index].imag= 0;
				g_fft_index++;
			}
		}
	}
}


/**
 * ************************************************************************
 * @brief
 * 
 * 
 * ************************************************************************
 */
void blood_data_translate(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; 
		
	}

	
	g_fft_index = 0;	

	FFT(s1);
	FFT(s2);
	
	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 ;
	}
	
	for(i = 0;i < 50;i++) 
	{
		if(s1[i].real<=10)
			break;
	}
	

	int s1_max_index = find_max_num_index(s1, 60);
	int s2_max_index = find_max_num_index(s2, 60);

	
	if(i>=45)
	{
	
		uint16_t Heart_Rate = 60.00 * SAMPLES_PER_SECOND * s1_max_index / FFT_N;
		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;
		SpO2 = sp02_num;
		
	
	}
	else 
	{
		heart = 0;
		SpO2 = 0;
	}
	
}

/**
 * ************************************************************************
 * @brief 
 * 
 * 
 * ************************************************************************
 */
void blood_Loop(void)
{

	blood_data_update();
	
	blood_data_translate();

	SpO2 = (SpO2 > 99.99) ? 99.99:SpO2;  

	printf("pulse-rate%3d/min; oximetry%2d%%\n", heart, (int)SpO2);

}



				
			

3.7 main.c

				
					#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "MAX30102.h"
#include "algorithm.h"
#include "blood.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

extern int heart;
extern float SpO2;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  Max30102_reset();  
	MAX30102_Config();    
  printf("MAX30102 Initialization complete\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		blood_Loop();
		// printf("display ok\n");
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

				
			

4.Experimental Results

Sampling and signal processing completed once every 10 seconds.

5.Additional Notes

If you need to change the sampling time, you can modify the FFT_N value in the algorithm.h file.

PrevPreviousHuawei Unveils ADS 4 Autonomous Driving System: Redefining Intelligent Mobility
NextPhysical Intelligence Launches π0.5 ModelNext
We offers Free Hardware Design and Solution Consulting Services.click the button below to get free consulting.
Get Free Consulting
Last Solution
Analysis of Synaptics SR Series MCUs: Performance for Edge AI
Analysis of Synaptics SR Series MCUs: Performance for Edge AI
Solution
SENNA Inference Accelerator: Neuromorphic Computing Accelerates Edge AI
SENNA Inference Accelerator: Neuromorphic Computing Accelerates Edge AI
Solution
AOV IPC Solution Based on Rockchip RV1106
AOV IPC Solution Based on Rockchip RV1106
Solution
An Overview of An Overview of Linux 6.8 Updates for Arm, RISC-V, and MIPS Platforms
An Overview of An Overview of Linux 6.8 Updates for Arm, RISC-V, and MIPS Platforms
Solution
360° Panoramic Camera Solution Based on Rockchip RK3576
360° Panoramic Camera Solution Based on Rockchip RK3576
Solution
Developing a Tricrystalline 4K Medical Endoscope System Based on RK3588
Developing a Tricrystalline 4K Medical Endoscope System Based on RK3588
Solution
Blog Categories
  • Tech
  • Feature
  • News
  • Solution
  • Tech
  • Feature
  • News
  • Solution
Share Our Web Site
  • TAGS
  • Nextcloud
  • PCIe
  • Bluetooth
  • AI Lawnmowers
  • DSP
  • MCU
  • UWB
  • Smart Gateway
  • Edge AI
  • network
  • RFID
  • RISC-V
  • High Frequency Circuit
  • IoT Wireless Communication
  • X86 CPU
  • Rockchip Development Board
  • Rockchip SoC
  • electric vehicle
  • ARM development board
  • ARM
  • IoT
  • AI CHIPS
  • AIoT
  • AI
Solution you may be interested in
synapitcs
Analysis of Synaptics SR Series MCUs: Performance for Edge AI
Solution
SENNA SNN chip
SENNA Inference Accelerator: Neuromorphic Computing Accelerates Edge AI
Solution
rockchip RV1106
AOV IPC Solution Based on Rockchip RV1106
Solution
Ic Linking
SoC Chip Design – AI Accelerator Interconnect Technology Analysis
BLOG Tech
Overview of Linux 6.8 Updates for Arm, RISC-V, and MIPS Platforms
An Overview of An Overview of Linux 6.8 Updates for Arm, RISC-V, and MIPS Platforms
Solution
360 Panoramic Camera Solution Based on Rockchip RK3576
360° Panoramic Camera Solution Based on Rockchip RK3576
Solution
Professional Special gas equipment and chemicals Supplier In Asia. Members Of AIWEDO.We Ship worldwide.
TOP RATED PROJECT
Rockchip SDC-RK3288
HD Wireless Ear Wax Removal Kit X2
HD Wireless Ear Wax Removal Kit X8
TAGS

Anything in here will be replaced on browsers that support the canvas element

  • RK3288
  • RK3566
  • Edge computing
  • Wireless Ear Wax Removal
  • Rockchip development board
  • allwinner development board
CONTACT INFO
  • Sales Department:
  • sales@aiwedo.com
  • Whatsapp : 0085296847998
  • Address:R/315,FL3, Qi Life A.I. Pinus Tabuliformis Garden, Ruifeng Community, Pinus Tabuliformis Estate, Longhua District, Shenzhen City,GD province,China
GET IN TOUCH
  • Sales Department:
  • sales@aiwedo.com
  • Whatsapp : 0085296847998
  • Address:R/315,FL3, Qi Life A.I. Pinus Tabuliformis Garden, Ruifeng Community, Pinus Tabuliformis Estate, Longhua District, Shenzhen City,GD province,China
Company Logo
Professional Special gas equipment and chemicals Supplier In Asia. Members Of AIWEDO.We Ship worldwide.
TOP RATED PRODUCT

Rockchip SDC-RK3288
HD Wireless Ear Wax Removal Kit X2
HD Wireless Ear Wax Removal Kit X8

HOT TAGS

  • RK3288
  • RK3566
  • Edge computing
  • Wireless Ear Wax Removal
  • Rockchip development board
  • allwinner development board

Privacy Policy
Terms Of Use
XML Sitemap
© Copyright 2012 - 2022 | AIWEDO CO., LIMITED and SZFT CO., LIMITED All Rights Reserved |