求助 max30102 心率血氧测试模块的问题
[复制链接]
本帖最后由 小白(学习中) 于 2019-8-4 14:57 编辑
我用的stm32f103rct6 软件模拟的iic 收到max30102 采集的数据处理之后的波形 浮动很大,怎么解决啊
这是采样数据,浮动值很大,下面配上IIC配置,算法模块是美信官网找的。求大佬指教
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x.h"
#include "drv_systick.h"
#include "stdio.h"
#include "max30102_algorithm.h"
#include "DataScope_DP.h"
#define MAX_BRIGHTNESS 255
//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 IIC_MAX30102_OK 0
#define IIC_MAX30102_Err 1
/*max30102 iic */
#define MAX30102_IIC_APBPERIPH_CLK_FUNC RCC_APB2PeriphClockCmd
#define MAX30102_IIC_APBPERIPH_PORT RCC_APB2Periph_GPIOB
#define MAX30102_IIC_PORT GPIOB
#define MAX30102_IIC_PIN_SCL GPIO_Pin_4
#define MAX30102_IIC_PIN_SDA GPIO_Pin_3
#define MAX30102_INT GPIO_Pin_5
#define MAX30102_SDA_HIGH() GPIO_SetBits(MAX30102_IIC_PORT, MAX30102_IIC_PIN_SDA)
#define MAX30102_SDA_LOW() GPIO_ResetBits(MAX30102_IIC_PORT, MAX30102_IIC_PIN_SDA)
#define MAX30102_SDA_READ() GPIO_ReadInputDataBit(MAX30102_IIC_PORT, MAX30102_IIC_PIN_SDA)
#define MAX30102_SCL_HIGH() GPIO_SetBits(MAX30102_IIC_PORT, MAX30102_IIC_PIN_SCL)
#define MAX30102_SCL_LOW() GPIO_ResetBits(MAX30102_IIC_PORT, MAX30102_IIC_PIN_SCL)
#define MAX30102_INT_HIGH() GPIO_SetBits(MAX30102_IIC_PORT, MAX30102_INT)
#define MAX30102_INT_LOW() GPIO_ResetBits(MAX30102_IIC_PORT, MAX30102_INT)
#define MAX30102_INT_READ() GPIO_ReadInputDataBit(MAX30102_IIC_PORT, MAX30102_INT)
#define IIC_TIME_OUT 2
#define WAIT_TIME_OUT 2000
#define MAX30102_I2C_OK 1
#define MAX30102_I2C_ERR 0
#define MAX30102_WRITE_ADDR 0XAE
#define MAX30102_READ_ADDR 0XAF
#define BUFSIZE 500
/*引脚初始化*/
void MAX30102_I2C_Config(void)
{
/*PB3 ,PB4 PB5为int 推挽输出 */
/*先失能JTAG 功能*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
/*改变指定管脚的映射 GPIO_Remap_SWJ_Disable SWJ 完全禁用(JTAG+SW-DP)*/
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
/*改变指定管脚的映射 GPIO_Remap_SWJ_JTAGDisable ,JTAG-DP 禁用 + SW-DP 使能*/
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
RCC_APB2PeriphClockCmd(MAX30102_IIC_APBPERIPH_PORT, ENABLE); //打开GPIOB的时钟
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = MAX30102_IIC_PIN_SCL | MAX30102_IIC_PIN_SDA;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MAX30102_IIC_PORT,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = MAX30102_INT;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MAX30102_IIC_PORT,&GPIO_InitStruct);
}
/*SDA输出*/
void MAX30102_I2C_SdaOut(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = MAX30102_IIC_PIN_SDA;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MAX30102_IIC_PORT,&GPIO_InitStruct);
}
/*SDA输入*/
void MAX30102_I2C_SdaIn(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = MAX30102_IIC_PIN_SDA;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(MAX30102_IIC_PORT,&GPIO_InitStruct);
}
/*开始信号*/
void MAX30102_I2C_Start(void)
{
MAX30102_SCL_LOW(); //拉低SCL
MAX30102_I2C_SdaOut();
MAX30102_SDA_HIGH(); //拉高SDA
MAX30102_SCL_HIGH(); //拉高SCL
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SDA_LOW();
SYSTICK_DelayNus(IIC_TIME_OUT); //延时,速度控制
MAX30102_SCL_LOW(); //钳住SCL
}
/*停止信号*/
void MAX30102_I2C_Stop(void)
{
MAX30102_SCL_LOW(); //拉低SCL
MAX30102_I2C_SdaOut();
MAX30102_SDA_LOW(); //拉低SDA
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_HIGH(); //拉高SCL
MAX30102_SDA_HIGH(); //拉高SDA
SYSTICK_DelayNus(IIC_TIME_OUT);
}
/*ACK信号*/
void MAX30102_I2C_SendAck(void)
{
MAX30102_SCL_LOW();
MAX30102_I2C_SdaOut();
//MAX30102_SDA_HIGH();
MAX30102_SDA_LOW();
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_HIGH();
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_LOW();
MAX30102_SDA_HIGH();
}
/*NACK*/
void MAX30102_I2C_SendNoAck(void)
{
MAX30102_SCL_LOW();
MAX30102_I2C_SdaOut();
MAX30102_SDA_HIGH();
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_HIGH();
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_LOW();
}
/*等待ACK信号*/
uint8_t MAX30102_I2C_WaitAck(uint16_t TimeOut)
{
MAX30102_SCL_LOW();
MAX30102_I2C_SdaIn();
MAX30102_SCL_HIGH(); /*数据高电平有效 读之前先拉高*/
while(MAX30102_SDA_READ())
{
if(TimeOut == 0) /*超时检测,异常终止*/
{
printf("WaitAck TimeOut!\n");
MAX30102_I2C_Stop();
return MAX30102_I2C_ERR;
}
TimeOut--;
SYSTICK_DelayNus(IIC_TIME_OUT);
}
MAX30102_SCL_LOW();
return MAX30102_I2C_OK;
}
/*i2c 发送一个字节*/
void MAX30102_I2C_SendByte(uint8_t byte)
{
uint8_t i = 0;
MAX30102_SCL_LOW(); /*拉低时钟传输数据*/
MAX30102_I2C_SdaOut();
for(i = 0; i < 8; i++)
{
if(byte & 0x80) /*高位先行*/
MAX30102_SDA_HIGH();
else
MAX30102_SDA_LOW();
byte <<= 1;
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_HIGH(); /*拉高数据有效*/
SYSTICK_DelayNus(IIC_TIME_OUT);
MAX30102_SCL_LOW();
}
}
/*I2c接收一个字节 */
uint8_t MAX30102_I2C_RecvByte(void)
{
uint8_t date = 0;
uint8_t i = 0;
MAX30102_SCL_LOW();
MAX30102_I2C_SdaIn();
for(i = 0; i < 8; i++)
{
date <<= 1;
MAX30102_SCL_HIGH();
SYSTICK_DelayNus(IIC_TIME_OUT);
if(MAX30102_SDA_READ())
date |= 0x01;
MAX30102_SCL_LOW();
SYSTICK_DelayNus(IIC_TIME_OUT);
}
return date;
}
/* 软件IIC写一个数据
slaveAddr:从机地址
regAddr:寄存器地址
byte:需要写入的数据*/
uint8_t MAX30102_I2C_WriteByte(uint8_t regAddr,uint8_t *byte)
{
MAX30102_I2C_Start(); /*起始信号*/
MAX30102_I2C_SendByte(MAX30102_WRITE_ADDR); /*设备地址,写操作0*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答,超时检测*/
{
printf("WaitAck1 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_SendByte(regAddr); /*发送寄存器地址*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答*/
{
printf("WaitAck2 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_SendByte(*byte);
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答*/
{
printf("WaitAck3 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_Stop(); /*停止*/
return MAX30102_I2C_OK;
ERR_HANDLER:
return MAX30102_I2C_ERR;
}
/*I2C读一个数据*/
uint8_t MAX30102_I2C_ReadByte(uint8_t regAddr,uint8_t *byte)
{
MAX30102_I2C_Start(); /*起始信号*/
MAX30102_I2C_SendByte(MAX30102_WRITE_ADDR); /*设备地址,写操作0,*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答,超时检测*/
{
printf("WaitAck4 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_SendByte(regAddr); /*发送寄存器地址*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答*/
{
printf("WaitAck5 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_Start(); /*重启信号*/
MAX30102_I2C_SendByte(MAX30102_READ_ADDR); /*设备地址,读操作1*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答,超时检测*/
{
printf("WaitAck6 TimeOut!\n");
goto ERR_HANDLER;
}
*byte = MAX30102_I2C_RecvByte(); /*接收*/
MAX30102_I2C_SendNoAck(); /*产生一个非应答信号*/
MAX30102_I2C_Stop();
return MAX30102_I2C_OK;
ERR_HANDLER:
return MAX30102_I2C_ERR;
}
/*软件I2C 向指定设备 指定地址 写多个数据*/
/*regAddr寄存器地址*/
/*buf 数据缓冲区*/
/*num 缓冲区大小*/
uint8_t MAX30102_I2C_WriteBytes(uint8_t regAddr,uint8_t *buf,uint8_t num)
{
MAX30102_I2C_Start(); /*起始信号*/
MAX30102_I2C_SendByte(MAX30102_WRITE_ADDR); /*设备地址,写操作0*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答,超时检测*/
{
printf("WaitAck1 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_SendByte(regAddr); /*发送寄存器地址*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答*/
{
printf("WaitAck2 TimeOut!\n");
goto ERR_HANDLER;
}
while(num--) /*循环写入*/
{
MAX30102_I2C_SendByte(*buf); /*发送数据*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答*/
{
printf("WaitAck3 TimeOut!\n");
goto ERR_HANDLER;
}
buf++;
SYSTICK_DelayNus(10);
}
MAX30102_I2C_Stop(); /*停止*/
return MAX30102_I2C_OK;
ERR_HANDLER:
return MAX30102_I2C_ERR;
}
/*I2C读多个数据*/
uint8_t MAX30102_I2C_ReadBytes(uint8_t regAddr,uint8_t *buf,uint8_t num)
{
MAX30102_I2C_Start(); /*起始信号*/
MAX30102_I2C_SendByte(MAX30102_WRITE_ADDR); /*设备地址,写操作0,*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答,超时检测*/
{
printf("WaitAck4 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_SendByte(regAddr); /*发送寄存器地址*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答*/
{
printf("WaitAck5 TimeOut!\n");
goto ERR_HANDLER;
}
MAX30102_I2C_Start(); /*重启信号*/
MAX30102_I2C_SendByte(MAX30102_READ_ADDR); /*设备地址,读操作1*/
if(!MAX30102_I2C_WaitAck(WAIT_TIME_OUT)) /*等待应答,超时检测*/
{
printf("WaitAck6 TimeOut!\n");
goto ERR_HANDLER;
}
while(num--) /*循环读数据*/
{
*buf = MAX30102_I2C_RecvByte();
buf++;
if(num == 0)
MAX30102_I2C_SendNoAck(); /*最后一个数据回 NoACK*/
else
MAX30102_I2C_SendAck(); /*回应ACK*/
}
MAX30102_I2C_Stop();
return MAX30102_I2C_OK;
ERR_HANDLER:
return MAX30102_I2C_ERR;
}
/*复位*/
uint8_t MAX30102_Reset(void)
{
uint8_t val = 0x40;
if(MAX30102_I2C_WriteByte(REG_MODE_CONFIG,&val))
return MAX30102_I2C_OK;
else
return MAX30102_I2C_ERR;
}
/*初始化*/
uint8_t MAX30102_Config(void)
{
uint8_t val = 0;
val = 0xc0;
if(!MAX30102_I2C_WriteByte(REG_INTR_ENABLE_1,&val)) // INTR setting
return MAX30102_I2C_ERR;
val = 0x00;
if(!MAX30102_I2C_WriteByte(REG_INTR_ENABLE_2,&val))
return MAX30102_I2C_ERR;
/*val = 0x01;
if(!MAX30102_I2C_WriteByte(REG_TEMP_CONFIG,&val)) //
return MAX30102_I2C_ERR;*/
val = 0x00;
if(!MAX30102_I2C_WriteByte(REG_FIFO_WR_PTR,&val)) //FIFO_WR_PTR[4:0]
return MAX30102_I2C_ERR;
val = 0x00;
if(!MAX30102_I2C_WriteByte(REG_OVF_COUNTER,&val)) //OVF_COUNTER[4:0]
return MAX30102_I2C_ERR;
val = 0x00;
if(!MAX30102_I2C_WriteByte(REG_FIFO_RD_PTR,&val)) //FIFO_RD_PTR[4:0]
return MAX30102_I2C_ERR;
val = 0x0f;
if(!MAX30102_I2C_WriteByte(REG_FIFO_CONFIG,&val)) //sample avg = 1, fifo rollover=false, fifo almost full = 17
return MAX30102_I2C_ERR;
val = 0x03;
if(!MAX30102_I2C_WriteByte(REG_MODE_CONFIG,&val)) //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
return MAX30102_I2C_ERR;
val = 0x27;
if(!MAX30102_I2C_WriteByte(REG_SPO2_CONFIG,&val)) // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
return MAX30102_I2C_ERR;
val = 0x24;
if(!MAX30102_I2C_WriteByte(REG_LED1_PA,&val)) //Choose value for ~ 7mA for LED1
return MAX30102_I2C_ERR;
val = 0x24;
if(!MAX30102_I2C_WriteByte(REG_LED2_PA,&val)) // Choose value for ~ 7mA for LED2
return MAX30102_I2C_ERR;
val = 0x7f;
if(!MAX30102_I2C_WriteByte(REG_PILOT_PA,&val)) // Choose value for ~ 25mA for Pilot LED
return MAX30102_I2C_ERR;
return MAX30102_I2C_OK;
}
/*从MAX3102FIFO寄存器中简要读取一组样本
param[out]*pun_red_LED-存储红色LED读取数据的指针
param[out]* pun_ir_led-存储红外LED读取数据的指针
成功时返回真值*/
uint8_t MAX30102_Read_FIFO(uint32_t *pun_red_led, uint32_t *pun_ir_led)
{
uint32_t un_temp;
uint8_t ach_i2c_data[6];
uint8_t uch_temp;
*pun_red_led = 0;
*pun_ir_led = 0;
/*读取清除寄存器状态*/
MAX30102_I2C_ReadByte(REG_INTR_STATUS_1, &uch_temp);
MAX30102_I2C_ReadByte(REG_INTR_STATUS_2, &uch_temp);
ach_i2c_data[0] = REG_FIFO_DATA;
if(!MAX30102_I2C_WriteBytes(REG_FIFO_DATA,ach_i2c_data,1))
return MAX30102_I2C_ERR;
if(!MAX30102_I2C_ReadBytes(REG_FIFO_DATA, ach_i2c_data,6))
return MAX30102_I2C_ERR;
un_temp = (unsigned char) ach_i2c_data[0];
un_temp <<= 16;
*pun_red_led += un_temp;
un_temp = (unsigned char) ach_i2c_data[1];
un_temp <<= 8;
*pun_red_led += un_temp;
un_temp = (unsigned char) ach_i2c_data[2];
*pun_red_led += un_temp;
un_temp = (unsigned char) ach_i2c_data[3];
un_temp <<= 16;
*pun_ir_led += un_temp;
un_temp = (unsigned char) ach_i2c_data[4];
un_temp <<= 8;
*pun_ir_led += un_temp;
un_temp = (unsigned char) ach_i2c_data[5];
*pun_ir_led += un_temp;
*pun_red_led &= 0x03ffff; /* Mask MSB [23:18] */
*pun_ir_led &= 0x03ffff;
return MAX30102_I2C_OK;
}
uint32_t aun_ir_buffer[BUFSIZE]; //红外LED传感器数据
int32_t n_ir_buffer_length; //数据长度
uint32_t aun_red_buffer[BUFSIZE]; //红色LED传感器数据
int32_t n_sp02; //SpO2值
int8_t ch_spo2_valid; //指示SP02计算是否有效的指示器
int32_t n_heart_rate; //心率值
int8_t ch_hr_valid; //显示心率计算是否有效的指示器
uint8_t uch_dummy;
uint32_t un_min, un_max, un_prev_data; //用于计算反映心跳的LED亮度的变量
int i;
int32_t n_brightness;
float f_temp;
void MAX30102_test1(void)
{
//MAX30102_Reset(); /*复位*/
MAX30102_I2C_ReadByte(REG_INTR_STATUS_1, &uch_dummy);
//while(!MAX30102_Config()) /*初始化*/
//{
// printf("max30102_init error!\n");
//}
n_brightness = 0;
un_min = 0x3ffff;
un_max = 0;
n_ir_buffer_length = BUFSIZE;
/*读取前n_ir_buffer_length个样本,确定信号范围*/
for(i = 0; i < n_ir_buffer_length; i++ )
{
while(MAX30102_INT_READ()); /*等待中断响应 低电平有效*/
MAX30102_Read_FIFO((aun_red_buffer+i),(aun_ir_buffer+i));
if(un_min > aun_red_buffer)
un_min = aun_red_buffer; //update signal min
if(un_max < aun_red_buffer)
un_max = aun_red_buffer; //update signal max
/*打印波形*/
//sendwares(&aun_red_buffer,&aun_ir_buffer,4);
/*printf("red=");
printf("%i", aun_red_buffer);
printf(", ir=");
printf("%i\n\r", aun_ir_buffer);*/
}
un_prev_data = aun_red_buffer;
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);
/*打印波形*/
sendwares(&n_heart_rate,&n_sp02,4);
}
uint8_t HR_value;
uint8_t SpO2_value;
void MAX30102_test2(void)
{
i=0;
un_min = 0x3FFFF;
un_max = 0;
/*将前100组样本转储到内存中,并将最后400组样本移到顶部*/
for(i = 100; i < n_ir_buffer_length; i++)
{
aun_red_buffer[i-100] = aun_red_buffer;
aun_ir_buffer[i-100] = aun_ir_buffer;
//update the signal min and max
if(un_min > aun_red_buffer)
un_min = aun_red_buffer;
if(un_max < aun_red_buffer)
un_max = aun_red_buffer;
}
/*计算心率前取100组样本*/
for(i = 400 ; i < 500; i++ )
{
un_prev_data = aun_red_buffer[i-1];
while(MAX30102_INT_READ());
MAX30102_Read_FIFO((aun_red_buffer + i), (aun_ir_buffer + i));
if(aun_red_buffer > un_prev_data) //just to determine the brightness of LED according to the deviation of adjacent two AD data
{
f_temp = aun_red_buffer-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;
f_temp /= (un_max-un_min);
f_temp *= MAX_BRIGHTNESS;
n_brightness += (int)f_temp;
if(n_brightness > MAX_BRIGHTNESS)
n_brightness = MAX_BRIGHTNESS;
}
/*if(n_heart_rate < 40|| n_heart_rate >150)
n_heart_rate = 0;
if(n_sp02 < 40|| n_sp02 >100)
n_sp02 = 0;*/
printf(" red=");
printf("%i", aun_red_buffer);
printf(", ir=");
printf("%i\n\r", aun_ir_buffer);
printf(" HR=%i, ", n_heart_rate);
printf("HRvalid=%i, ", ch_hr_valid);
printf("SpO2=%i, ", n_sp02);
printf("SPO2Valid=%i\n\r", ch_spo2_valid);
}
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);
}
|