LOADING

加载过慢请开启缓存 浏览器默认开启

MAX30102模块

2023/2/14 单片机

Abstract: MAX30102 测试代码,仅使用温度和血氧测量功能。

代码部分

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "MAX30102.h"
#include "Serial.h"
#include "MAX30102_Reg.h"

uint8_t pf=0;
uint8_t mode=1;

void Config_Check(void);

int main(void)
{
    MAX30102_Init();
    Serial_Init();
    
    Config_Check();
    while (1)
    {
        float Spo2;
        MAX30102_Read_FIFO_Data(MAX30102_PPG_Data);
        if (MAX30102_PPG_Data[0]<=0x186a0) //未接近
        {
            if (pf==0)
            {
                pf=1;
                Serial_Printf("Waiting...\r\n");
            }
            //Delay_ms(20);
            continue;
        }
        pf=0;
        if (mode==0) //输出原始数据
        {
            Serial_Printf("RED=%d,IR=%d\r\n",MAX30102_PPG_Data[0],MAX30102_PPG_Data[1]);
            MAX30102_Read_Temp_Data(MAX30102_Temp_Data);
            Serial_Printf("Temp=%.2f\r\n",MAX30102_Temp_Cal(MAX30102_Temp_Data));
        }
        else if (mode==1)//输出计算后的血氧值
        {
            MAX30102_Spo2_Cal_Median_Filter(&Spo2);
//			Serial_Printf("RED=%d,IR=%d\r\n",MAX30102_PPG_Data[0],MAX30102_PPG_Data[1]);
            Serial_Printf("Spo2=%.3f%\r\n",Spo2);
        }
        Delay_ms(200);
    }
}

void Config_Check(void)
{
    Serial_Printf("rv_id=%hX\r\n",MAX30102_ReadReg(MAX30102_Revision_ID));
    Serial_Printf("part_id=%hX\r\n",MAX30102_ReadReg(MAX30102_Part_ID));
    
    Serial_Printf("mode=%hX\r\n",MAX30102_ReadReg(MAX30102_Mode_Configuration));

    Serial_Printf("status1=%hX\r\n",MAX30102_ReadReg(MAX30102_Interrupt_Status_1));
    Serial_Printf("status2=%hX\r\n",MAX30102_ReadReg(MAX30102_Interrupt_Status_2));
    
    Serial_Printf("enable1=%hX\r\n",MAX30102_ReadReg(MAX30102_Interrupt_Enable_1));
    Serial_Printf("enable2=%hX\r\n",MAX30102_ReadReg(MAX30102_Interrupt_Enable_2));
    Serial_Printf("rd_ptr=%hX\r\n",MAX30102_ReadReg(MAX30102_FIFO_Read_Pointer));
    Serial_Printf("wr_ptr=%hX\r\n",MAX30102_ReadReg(MAX30102_FIFO_Writer_Pointer));
    Serial_Printf("overflow=%hX\r\n",MAX30102_ReadReg(MAX30102_Overflow_Counter));
    Serial_Printf("fifo_conf=%hX\r\n",MAX30102_ReadReg(MAX30102_FIFO_Configuration));

    Serial_Printf("sp02_conf=%hX\r\n",MAX30102_ReadReg(MAX30102_SpO2_Configuration));
    
    Serial_Printf("temp_conf=%hX\r\n",MAX30102_ReadReg(MAX30102_Die_Temperature_Config));

    Serial_Printf("led1_amp=%hX\r\n",MAX30102_ReadReg(MAX30102_LED1_Pulse_Amplitude_Configuration));
    Serial_Printf("led2_amp=%hX\r\n",MAX30102_ReadReg(MAX30102_LED2_Pulse_Amplitude_Configuration));
}

MAX30102.c

#include "stm32f10x.h"                  // Device header
#include "MAX30102_Reg.h"
#include "Delay.h"

#define MAX30102_ADDR		0xAE //地址

uint32_t MAX30102_PPG_Data[2];
uint8_t MAX30102_Temp_Data[2];


/**
  * @brief  求最值函数
  * @param  无
  * @retval 数据缓存区大小及指针
  */
void MAX30102_Max_Min(uint32_t *Arr,uint8_t Size,uint32_t *Buf)
{
    uint32_t Max=0;
    uint32_t Min=Arr[0];
    uint8_t i;
    for (i=0;i<Size;i++)
    {
        if (Arr[i]>Max)
        {
            Max=Arr[i];
        }
        if (Arr[i]<Min)
        {
            Min=Arr[i];
        }
    }
    if (Max==Min)
    {
        Min-=1;
    }
    Buf[0]=Max;
    Buf[1]=Min;
}

/**
  * @brief  变量交换函数
  * @param  无
  * @retval 待交换数据的指针
  */
void MAX30102_Swap(uint32_t *a, uint32_t *b)
{
    uint32_t temp = *a;
    *a = *b;
    *b = temp;
}

//中位数计算,参考自https://blog.csdn.net/ONEDAY_789/article/details/76681764
uint32_t MAX30102_PartSort(uint32_t *arr, uint8_t start, uint8_t end)
{
    uint8_t left = start;
    uint8_t right = end;
    uint32_t key = arr[end];   //选取关键字
    while (left < right)
    {
        while (left < right && arr[left] <= key)  //左边找比key大的值
        {
            ++left;
        }
        while (left < right && arr[right] >= key)  //右边找比key小的值
        {
            --right;
        }
        if (left < right)
        {
            MAX30102_Swap(&arr[left], &arr[right]);  //找到之后交换左右的值
        }
    }
    MAX30102_Swap(&arr[right], &arr[end]);
    return left;
}

uint32_t MAX30102_GetMidNumNoSort(uint32_t *arr,uint32_t size)
{
    uint8_t start = 0;
    uint8_t end = size - 1;
    uint8_t mid = (size - 1) / 2;
    uint8_t div = MAX30102_PartSort(arr,start,end);
    while (div != mid)
    {
        if (mid < div)   //左半区间找
            div = MAX30102_PartSort(arr, start, div - 1);
        else    //左半区间找
            div = MAX30102_PartSort(arr, div + 1, end);
    }
    return arr[mid];
}
//中位数计算结束

/**
  * @brief  等待事件发生
  * @param  无
  * @retval 略
  */
void MAX30102_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
    uint32_t TimeOut;
    
    TimeOut=1000;
    while(I2C_CheckEvent(I2Cx,I2C_EVENT)!=SUCCESS)
    {
        TimeOut--;
        if (TimeOut==0)
        {
            break;
        }
    }
}

/**
  * @brief  I2C指定地址写入数据
  * @param  无
  * @retval 指定写地址,数据
  */
void MAX30102_WriteReg(uint8_t RegAddress,uint8_t Data)
{
    I2C_GenerateSTART(I2C2,ENABLE); //生成起始条件
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检测EV5
    
    I2C_Send7bitAddress(I2C2,MAX30102_ADDR,I2C_Direction_Transmitter); //发送地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //检测EV6
    
    I2C_SendData(I2C2,RegAddress); //发送写入地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING); //检测EV8
    
    I2C_SendData(I2C2,Data); //发送写入数据
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //检测EV8_2
    
    I2C_GenerateSTOP(I2C2, ENABLE); //终止
}

/**
  * @brief  I2C指定地址读取数据
  * @param  无
  * @retval 指定读地址
  */
uint8_t MAX30102_ReadReg(uint8_t RegAddress)
{
    uint8_t Data;
    
    I2C_GenerateSTART(I2C2,ENABLE); //生成起始条件
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检测EV5
    
    I2C_Send7bitAddress(I2C2,MAX30102_ADDR,I2C_Direction_Transmitter); //发送地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //检测EV6
    
    I2C_SendData(I2C2,RegAddress); //发送读取地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //检测EV8
    
    I2C_GenerateSTART(I2C2,ENABLE); //生成起始条件
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检测EV5

    I2C_Send7bitAddress(I2C2,MAX30102_ADDR,I2C_Direction_Receiver); //发送地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //检测EV6
    
    //只接受一字节
    I2C_AcknowledgeConfig(I2C2,DISABLE); // 应答失效
    I2C_GenerateSTOP(I2C2,ENABLE); //申请终止
    
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED); //检测EV7
    Data=I2C_ReceiveData(I2C2);
    
    I2C_AcknowledgeConfig(I2C2,ENABLE); // 应答有效
    
    return Data;
}

/**
  * @brief  中断初始化函数
  * @param  无
  * @retval 无
  */
//void MAX30102_Exit_Init(void)
//{
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//	
//	GPIO_InitTypeDef GPIO_Initstructure;
//	GPIO_Initstructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入
//	GPIO_Initstructure.GPIO_Pin=GPIO_Pin_0; //PA0
//	GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
//	GPIO_Init(GPIOA,&GPIO_Initstructure);
//	
//	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
//	
//	EXTI_InitTypeDef EXIT_InitStructure;
//	EXIT_InitStructure.EXTI_Line=EXTI_Line0; //指定中断线
//	EXIT_InitStructure.EXTI_LineCmd=ENABLE; //开启或关闭
//	EXIT_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式
//	EXIT_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发
//	EXTI_Init(&EXIT_InitStructure);
//	
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //整个工程只用执行一次
//	NVIC_InitTypeDef NVIC_InitStructure;
//	NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
//	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
//	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
//	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
//	NVIC_Init(&NVIC_InitStructure);
//}

/**
  * @brief  初始化函数
  * @param  无
  * @retval 无
  */
void MAX30102_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    I2C_InitTypeDef I2C_InitStructure;
    I2C_InitStructure.I2C_Ack=I2C_Ack_Enable; //应答开启
    I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; //七位地址
    I2C_InitStructure.I2C_ClockSpeed=200000; //200Khz
    I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2; //低:高=2:1,高速有效
    I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
    I2C_InitStructure.I2C_OwnAddress1=0X00; //自身地址,从机有效
    I2C_Init(I2C2,&I2C_InitStructure);
    
    I2C_Cmd(I2C2,ENABLE);
    
    MAX30102_WriteReg(MAX30102_Mode_Configuration,0X40); //重置模式
    Delay_ms(20);

    MAX30102_WriteReg(MAX30102_Interrupt_Enable_1,0X40); //中断开启 PPG_RDY 0x40 中断信号为低电平
    MAX30102_WriteReg(MAX30102_Interrupt_Enable_2,0X02); //中断开启 DIE_TEMP_RDY 0x02
    MAX30102_WriteReg(MAX30102_FIFO_Read_Pointer,0X00); //读指针清零
    MAX30102_WriteReg(MAX30102_FIFO_Writer_Pointer,0X00); //写指针清零
    MAX30102_WriteReg(MAX30102_Overflow_Counter,0X00); //溢出计数清零
    MAX30102_WriteReg(MAX30102_FIFO_Configuration,0X2F); //FIFO配置,AVE=2,ROL=1,FULL=17
    
    MAX30102_WriteReg(MAX30102_SpO2_Configuration,0X2B); //血氧测量配置,ADC=4096,SR=200/s,LED_PW=411,18
    
    MAX30102_WriteReg(MAX30102_LED1_Pulse_Amplitude_Configuration,0X24);
    MAX30102_WriteReg(MAX30102_LED2_Pulse_Amplitude_Configuration,0X24);
    
    MAX30102_ReadReg(MAX30102_Interrupt_Status_1); //中断清零
    MAX30102_ReadReg(MAX30102_Interrupt_Status_2); //中断清零
    
    MAX30102_WriteReg(MAX30102_Die_Temperature_Config,0X01); //温度测量开
    MAX30102_WriteReg(MAX30102_Mode_Configuration,0X03); //血氧模式
    
//	MAX30102_Exit_Init();
}

/**
  * @brief  读取FIFO采样数据
  * @param  无
* @retval 数据缓存区指针
  */
void MAX30102_Read_FIFO_Data(uint32_t *Buf)
{
    uint8_t Data[6];
    I2C_AcknowledgeConfig(I2C2,ENABLE); // 应答失效
    
    I2C_GenerateSTART(I2C2,ENABLE); //生成起始条件
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检测EV5
    
    I2C_Send7bitAddress(I2C2,MAX30102_ADDR,I2C_Direction_Transmitter); //发送地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //检测EV6
    
    I2C_SendData(I2C2,MAX30102_FIFO_Data_Register); //发送读取地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //检测EV8
    
    I2C_GenerateSTART(I2C2,ENABLE); //生成起始条件
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检测EV5

    I2C_Send7bitAddress(I2C2,MAX30102_ADDR,I2C_Direction_Receiver); //发送地址
    MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //检测EV6
    
    uint8_t i;
    uint8_t Tmp;
    for (i=0;i<6;i++)
    {
        if (i==5)
        { 	
            //接受最后一字节前设置ACK=0,S=1
            I2C_AcknowledgeConfig(I2C2,DISABLE); // 应答失效
            I2C_GenerateSTOP(I2C2,ENABLE); //申请终止
        }
        Tmp=0;
        MAX30102_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED); //检测EV7
        Tmp=I2C_ReceiveData(I2C2);
        Data[i]=Tmp;
    }
    I2C_AcknowledgeConfig(I2C2,ENABLE); // 应答有效
    Buf[0] = ((Data[0]<<16 | Data[1]<<8 | Data[2]) & 0x03ffff); //3fffff
    Buf[1] = ((Data[3]<<16 | Data[4]<<8 | Data[5]) & 0x03ffff);
}

/**
  * @brief  读取温度数据
  * @param  无
  * @retval 数据缓存区指针
  */
void MAX30102_Read_Temp_Data(uint8_t *Buf)
{
    Buf[0]=MAX30102_ReadReg(MAX30102_Die_Temp_Integer); //整数部分
    Buf[1]=MAX30102_ReadReg(MAX30102_Die_Temp_Fraction); //小数部分(只取后四位)
}

/**
  * @brief  读取版本ID
  * @param  无
  * @retval 无
  */
uint8_t MAX30102_Get_Revision_ID(void)
{
    return MAX30102_ReadReg(MAX30102_Revision_ID);
}

/**
  * @brief  读取部件ID
  * @param  无
  * @retval 无
  */
uint8_t MAX30102_Get_Part_ID(void)
{
    return MAX30102_ReadReg(MAX30102_Part_ID);
}

/**
  * @brief  温度计算函数
  * @param  无
  * @retval 数据缓存区指针
  */
float MAX30102_Temp_Cal(uint8_t *Buf)
{
    return (float)Buf[0]+(float)Buf[1]*0.625;
}

/**
  * @brief  血氧计算函数
  * @param  无
  * @retval 略
  */
float MAX30102_Spo2_Cal(uint32_t *Red_Data,uint32_t *Ir_Data,uint8_t Size)
{
    float Red_Max,Red_Min;
    float Ir_Max,Ir_Min;
    float R;
    uint32_t Temp[2];
    //求出最大最小值
    MAX30102_Max_Min(Red_Data,Size,Temp);
    Red_Max=Temp[0];
    Red_Min=Temp[1];
    MAX30102_Max_Min(Ir_Data,Size,Temp);
    Ir_Max=Temp[0];
    Ir_Min=Temp[1];
    
    R=((Red_Max + Red_Min) / (Red_Max - Red_Min)) / ((Ir_Max + Ir_Min) / (Ir_Max - Ir_Min));
    float result=-45.060 * R * R + 30.354 * R + 94.845;
    if (result<0)
    {
        result=0;
    }
    return result;
}

/**
  * @brief  血氧原始数据中位数滤波函数
  * @param  无
  * @retval 略
  */
void MAX30102_Spo2_Cal_Median_Filter(float *Buf)
{	
    const uint8_t each_1=8; //each_1 个数据为一组计算血氧
    uint32_t Red_m[each_1];
    uint32_t Ir_m[each_1];
    uint8_t i;
    for (i=0;i<each_1;i++)
    {
        const uint8_t each_2=5; //each_2(奇数) 个数据为一组计算中位数
        uint32_t Red_Data[each_2];
        uint32_t Ir_Data[each_2];
        uint8_t j=0;
        for (j=0;j<each_2;j++)
        {
            MAX30102_Read_FIFO_Data(MAX30102_PPG_Data); // 读取FIFO数据
            Red_Data[j]=MAX30102_PPG_Data[0];
            Ir_Data[j]=MAX30102_PPG_Data[1];
        }
        Red_m[i]=MAX30102_GetMidNumNoSort(Red_Data,each_2); //分别计算中位数
        Ir_m[i]=MAX30102_GetMidNumNoSort(Ir_Data,each_2);
    }
    *Buf=MAX30102_Spo2_Cal(Red_m,Ir_m,each_1);
}

/**
  * @brief  中断函数
  * @param  无
  * @retval 无
  */
//void EXTI0_IRQHandler(void)
//{
//	if (EXTI_GetITStatus(EXTI_Line0)==SET)
//	{
//		uint8_t ppg_flag = MAX30102_ReadReg(MAX30102_Interrupt_Status_1) & 0x40;
//		uint8_t temp_flag = MAX30102_ReadReg(MAX30102_Interrupt_Status_1) & 0x02;
//		if (ppg_flag==0x40)
//		{
//			MAX30102_Read_FIFO_Data(MAX30102_PPG_Data); //读取采样数据
//		}
//		if (temp_flag==0x02)
//		{
//			MAX30102_Read_Temp_Data(MAX30102_Temp_Data); //读取温度数据
//		}
//		EXTI_ClearITPendingBit(EXTI_Line0);
//	}
//}

MAX30102.h

#ifndef __MAX30102_H
#define __MAX30102_H
#include "stm32f10x.h"                  // Device header
#include "MAX30102_Reg.h"

extern uint32_t MAX30102_PPG_Data[2];
extern uint8_t MAX30102_Temp_Data[2];
void MAX30102_Init(void);
void MAX30102_Read_FIFO_Data(uint32_t *Buf);
void MAX30102_Read_Temp_Data(uint8_t *Buf);
uint8_t MAX30102_Get_Revision_ID(void);
uint8_t MAX30102_Get_Part_ID(void);
uint8_t MAX30102_ReadReg(uint8_t RegAddress);
float MAX30102_Temp_Cal(uint8_t *Buf);
void MAX30102_Spo2_Cal_Median_Filter(float *Buf);

#endif

MAX30102_Reg.h

#ifndef __MAX30102_Reg_H
#define __MAX30102_Reg_H

//STATUS
#define MAX30102_Interrupt_Status_1								0X00 //中断状态1
#define MAX30102_Interrupt_Status_2								0X01 //中断状态2
#define MAX30102_Interrupt_Enable_1								0x02 //中断使能1
#define MAX30102_Interrupt_Enable_2								0x03 //中断使能2
#define MAX30102_FIFO_Writer_Pointer							0x04 //FIFO写指针
#define MAX30102_Overflow_Counter								0x05 //FIFO满后遗失的采样数
#define MAX30102_FIFO_Read_Pointer								0x06 //FIFO读指针
#define MAX30102_FIFO_Data_Register								0x07 //FIFO数据寄存器
//Configuration
#define MAX30102_FIFO_Configuration								0x08 //FIFO配置
#define MAX30102_Mode_Configuration								0x09 //模式配置
#define MAX30102_SpO2_Configuration								0x0A //血氧测量配置
#define MAX30102_LED1_Pulse_Amplitude_Configuration 			0x0C //LED1脉冲波幅配置(RED)
#define MAX30102_LED2_Pulse_Amplitude_Configuration 			0x0D //LED2脉冲波幅配置(IR)
#define MAX30102_Proximity_Mode_LED_Pulse_Amplitude 			0X10 //接近检测模式LED波幅配置
#define MAX30102_MultiLED_Mode_Control_Registers_SLOT2_SLOT1	0x11 //混合LED模式配置(slot2、slot1)
#define MAX30102_MultiLED_Mode_Control_Registers_SLOT4_SLOT3	0x12 //混合LED模式配置(slot4、slot3)
//DIE TEMPERATURE
#define MAX30102_Die_Temp_Integer								0x1F //温度测量值(整数部分)
#define MAX30102_Die_Temp_Fraction								0x20 //温度测量值(小数部分)
#define MAX30102_Die_Temperature_Config 						0x21 //温度测量配置
//PROXIMITY FUNCTION
#define MAX30102_Proximity_Interrupt_Threshold 					0x30 //接近检测中断阈值
//PART ID
#define MAX30102_Revision_ID									0XFE //版本ID,从寄存器读取
#define MAX30102_Part_ID										0xFF //器件ID,0x15

#endif

串口数据样例

mode=0,输出原始数据

RED=150445,IR=134586
Temp=28.25
RED=150581,IR=134643
Temp=28.25
RED=150676,IR=134684
Temp=28.25
RED=150872,IR=134769
Temp=28.25
RED=151041,IR=134828
Temp=28.25
RED=151136,IR=134869
Temp=28.25
RED=151271,IR=134928
Temp=28.25
RED=151357,IR=134979
Temp=28.25
RED=151447,IR=135035
Temp=28.25
RED=151501,IR=135065
Temp=28.25
RED=151573,IR=135072
Temp=28.25
RED=151270,IR=134908
Temp=28.25
RED=150767,IR=134666
Temp=28.25
RED=150037,IR=134310
Temp=28.25
RED=149637,IR=134133
Temp=28.25
Waiting…

mode=1,输出血氧值

Spo2=98.968
Spo2=97.083
Spo2=99.789
Spo2=99.755
Spo2=99.537
Spo2=97.666
Spo2=99.740
Spo2=99.955
Spo2=96.622
Spo2=97.839
Spo2=98.715
Spo2=95.240
Spo2=96.473
Spo2=99.735
Spo2=95.161
Spo2=87.345
Spo2=59.356
Spo2=89.408
Spo2=95.111
Spo2=90.659
Spo2=99.778
Spo2=97.260
Spo2=99.744
Spo2=99.481
Spo2=98.376
Spo2=97.231
Spo2=99.917
Spo2=97.851
Spo2=98.049
Spo2=99.458
Spo2=99.815
Spo2=80.416
Waiting…

其他

  • 有时会出现I2C应答正常但是读写数据异常的情况,此时断电重启就可以解决,具体原因未知
  • 代码注释部分为中断功能,使用困难固注释
  • 原始数据使用了中位数滤波,但是结果仍不稳定