MAX30102模块
软件代码部分
main函数
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "max30102.h"
#include "myiic.h"
#include "algorithm.h"
#include "oled_iic.h"
#define MAX_BRIGHTNESS 255
u32 aun_ir_buffer[500];
int32_t n_ir_buffer_length;
u32 aun_red_buffer[500];
int32_t n_sp02;
int8_t ch_spo2_valid;
int32_t n_heart_rate;
int8_t ch_hr_valid;
int main(void)
{
u8 t = 0;
u32 un_min, un_max, un_prev_data;
int32_t n_brightness;
u16 i;
u8 temp[6];
float f_temp;
u8 dis_hr = 0, dis_spo2 = 0;
delay_init();
HZ = GB16_NUM();
delay_ms(50);
OLED_Init();
delay_ms(50);
OLED_Clear();
delay_ms(50);
OLED_ShowCH(16,2,"心率:000");
OLED_ShowCH(16,4,"血氧:000%");
uart_init(115200);
MX_GPIO_Init();
max30102_init();
un_min = 0x3FFFF;
un_max = 0;
n_ir_buffer_length = 500;
for(i = 0; i < n_ir_buffer_length; i++)
{
while(MAX30102_INT == 1);
max30102_FIFO_ReadBytes(REG_FIFO_DATA, temp);
aun_red_buffer[i] = (long)((long)((long)temp[0] & 0x03) << 16) | (long)temp[1] << 8 | (long)temp[2];
aun_ir_buffer[i] = (long)((long)((long)temp[3] & 0x03) << 16) | (long)temp[4] << 8 | (long)temp[5];
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];
}
un_prev_data = aun_red_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);
while(1)
{
i = 0;
un_min = 0x3FFFF;
un_max = 0;
for(i = 100; i < 500; i++)
{
aun_red_buffer[i - 100] = aun_red_buffer[i];
aun_ir_buffer[i - 100] = aun_ir_buffer[i];
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];
}
for(i = 400; i < 500; i++)
{
un_prev_data = aun_red_buffer[i - 1];
while(MAX30102_INT == 1);
max30102_FIFO_ReadBytes(REG_FIFO_DATA, temp);
aun_red_buffer[i] = (long)((long)((long)temp[0] & 0x03) << 16) | (long)temp[1] << 8 | (long)temp[2];
aun_ir_buffer[i] = (long)((long)((long)temp[3] & 0x03) << 16) | (long)temp[4] << 8 | (long)temp[5];
if(aun_red_buffer[i] > un_prev_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;
}
if((ch_hr_valid == 1))
{
if(n_heart_rate < 120)
dis_hr = n_heart_rate;
else
dis_hr = 0;
dis_spo2 = n_sp02;
}
else
{
dis_hr = 0;
dis_spo2 = 0;
}
t++;
if(t > 10)
{
t = 0;
printf("HR=%i,SpO2=%i\r\n ", dis_hr, dis_spo2);
}
OLED_ShowNum(56, 2, dis_hr, 3, 1);
OLED_ShowNum(56, 4, dis_spo2, 3, 1);
}
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);
delay_ms(200);
}
}
max30102模块
max30102.h
#ifndef __MAX30102_H
#define __MAX30102_H
#include "sys.h"
#define MAX30102_INT PBin(9)
#define I2C_WR 0
#define I2C_RD 1
#define max30102_WR_address 0xAE
#define I2C_WRITE_ADDR 0xAE
#define I2C_READ_ADDR 0xAF
#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
void MX_GPIO_Init(void);
void max30102_init(void);
void max30102_reset(void);
u8 max30102_Bus_Write(u8 Register_Address, u8 Word_Data);
u8 max30102_Bus_Read(u8 Register_Address);
void max30102_FIFO_ReadWords(u8 Register_Address,u16 Word_Data[][2],u8 count);
void max30102_FIFO_ReadBytes(u8 Register_Address,u8* Data);
void maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data);
void maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data);
void maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led);
#endif
max30102.c
#include "max30102.h"
#include "myiic.h"
#include "delay.h"
void MX_GPIO_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
u8 max30102_Bus_Write(u8 Register_Address, u8 Word_Data)
{
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_WR);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Send_Byte(Register_Address);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Send_Byte(Word_Data);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Stop();
return 1;
cmd_fail:
iic_Stop();
return 0;
}
u8 max30102_Bus_Read(u8 Register_Address)
{
u8 data;
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_WR);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Send_Byte((uint8_t)Register_Address);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_RD);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
{
data = iic_Read_Byte(0);
iic_NAck();
}
iic_Stop();
return data;
cmd_fail:
iic_Stop();
return 0;
}
void max30102_FIFO_ReadWords(u8 Register_Address, u16 Word_Data[][2], u8 count)
{
u8 i = 0;
u8 no = count;
u8 data1, data2;
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_WR);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Send_Byte((uint8_t)Register_Address);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_RD);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
while (no)
{
data1 = iic_Read_Byte(0);
iic_Ack();
data2 = iic_Read_Byte(0);
iic_Ack();
Word_Data[i][0] = (((u16)data1 << 8) | data2);
data1 = iic_Read_Byte(0);
iic_Ack();
data2 = iic_Read_Byte(0);
if (1 == no)
iic_NAck();
else
iic_Ack();
Word_Data[i][1] = (((u16)data1 << 8) | data2);
no--;
i++;
}
iic_Stop();
cmd_fail:
iic_Stop();
}
void max30102_FIFO_ReadBytes(u8 Register_Address, u8* Data)
{
max30102_Bus_Read(REG_INTR_STATUS_1);
max30102_Bus_Read(REG_INTR_STATUS_2);
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_WR);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Send_Byte((uint8_t)Register_Address);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
iic_Start();
iic_Send_Byte(max30102_WR_address | I2C_RD);
if (iic_Wait_Ack() != 0)
{
goto cmd_fail;
}
Data[0] = iic_Read_Byte(1);
Data[1] = iic_Read_Byte(1);
Data[2] = iic_Read_Byte(1);
Data[3] = iic_Read_Byte(1);
Data[4] = iic_Read_Byte(1);
Data[5] = iic_Read_Byte(0);
iic_Stop();
cmd_fail:
iic_Stop();
}
void max30102_init(void)
{
iic_Init();
max30102_reset();
max30102_Bus_Write(REG_INTR_ENABLE_1, 0xc0);
max30102_Bus_Write(REG_INTR_ENABLE_2, 0x00);
max30102_Bus_Write(REG_INTR_ENABLE_1, 0xc0);
max30102_Bus_Write(REG_INTR_ENABLE_2, 0x00);
max30102_Bus_Write(REG_FIFO_WR_PTR, 0x00);
max30102_Bus_Write(REG_OVF_COUNTER, 0x00);
max30102_Bus_Write(REG_FIFO_RD_PTR, 0x00);
max30102_Bus_Write(REG_FIFO_CONFIG, 0x0f);
max30102_Bus_Write(REG_MODE_CONFIG, 0x03);
max30102_Bus_Write(REG_SPO2_CONFIG, 0x27);
max30102_Bus_Write(REG_LED1_PA, 0x24);
max30102_Bus_Write(REG_LED2_PA, 0x24);
max30102_Bus_Write(REG_PILOT_PA, 0x7f);
}
void max30102_reset(void)
{
max30102_Bus_Write(REG_MODE_CONFIG, 0x40);
max30102_Bus_Write(REG_MODE_CONFIG, 0x40);
}
void maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data)
{
iic_Write_One_Byte(I2C_WRITE_ADDR, uch_addr, uch_data);
}
void maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data)
{
iic_Read_One_Byte(I2C_WRITE_ADDR, uch_addr, puch_data);
}
void maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led)
{
uint32_t un_temp;
unsigned char uch_temp;
char ach_i2c_data[6];
*pun_red_led = 0;
*pun_ir_led = 0;
maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
iic_ReadBytes(I2C_WRITE_ADDR, REG_FIFO_DATA, (u8 *)ach_i2c_data, 6);
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;
*pun_ir_led &= 0x03FFFF;
}
algorithm函数
algorithm.h
#ifndef ALGORITHM_H_
#define ALGORITHM_H_
#include "sys.h"
#define true 1
#define false 0
#define FS 100
#define BUFFER_SIZE (FS* 5)
#define HR_FIFO_SIZE 7
#define MA4_SIZE 4
#define HAMMING_SIZE 5
#define min(x,y) ((x) < (y) ? (x) : (y))
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 *pn_npks, int32_t *pn_x, int32_t n_size, int32_t n_min_height, int32_t n_min_distance, int32_t n_max_num );
void maxim_peaks_above_min_height( int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x, int32_t n_size, int32_t n_min_height );
void maxim_remove_close_peaks( int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x, int32_t n_min_distance );
void maxim_sort_ascend( int32_t *pn_x, int32_t n_size );
void maxim_sort_indices_descend( int32_t *pn_x, int32_t *pn_indx, int32_t n_size);
#endif
algorithm.c
#include "algorithm.h"
const uint16_t auw_hamm[31]={ 41, 276, 512, 276, 41 };
const uint8_t uch_spo2_table[184]={ 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 99, 99, 99, 99,
99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 97, 97,
97, 97, 96, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91,
90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81,
80, 80, 79, 78, 78, 77, 76, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67,
66, 66, 65, 64, 63, 62, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50,
49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29,
28, 27, 26, 25, 23, 22, 21, 20, 19, 17, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5,
3, 2, 1 } ;
static int32_t an_dx[ BUFFER_SIZE-MA4_SIZE];
static int32_t an_x[ BUFFER_SIZE];
static int32_t an_y[ BUFFER_SIZE];
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)
{
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;
un_ir_mean = 0;
for (k = 0; k < n_ir_buffer_length; k++) un_ir_mean += pun_ir_buffer[k];
un_ir_mean = un_ir_mean / n_ir_buffer_length;
for (k = 0; k < n_ir_buffer_length; k++) an_x[k] = pun_ir_buffer[k] - un_ir_mean;
for (k = 0; k < BUFFER_SIZE - MA4_SIZE; 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;
}
for (k = 0; k < BUFFER_SIZE - MA4_SIZE - 1; k++)
an_dx[k] = (an_x[k + 1] - an_x[k]);
for (k = 0; k < BUFFER_SIZE - MA4_SIZE - 2; k++)
{
an_dx[k] = (an_dx[k] + an_dx[k + 1]) / 2;
}
for (i = 0; i < BUFFER_SIZE - HAMMING_SIZE - MA4_SIZE - 2; i++)
{
s = 0;
for (k = i; k < i + HAMMING_SIZE; k++)
{
s -= an_dx[k] * auw_hamm[k - i];
}
an_dx[i] = s / (int32_t)1146;
}
n_th1 = 0;
for (k = 0; k < BUFFER_SIZE - HAMMING_SIZE; k++)
{
n_th1 += ((an_dx[k] > 0) ? an_dx[k] : ((int32_t)0 - an_dx[k]));
}
n_th1 = n_th1 / (BUFFER_SIZE - HAMMING_SIZE);
maxim_find_peaks(an_dx_peak_locs, &n_npks, an_dx, BUFFER_SIZE - HAMMING_SIZE, n_th1, 8, 5);
n_peak_interval_sum = 0;
if (n_npks >= 2)
{
for (k = 1; k < n_npks; k++)
n_peak_interval_sum += (an_dx_peak_locs[k] - an_dx_peak_locs[k - 1]);
n_peak_interval_sum = n_peak_interval_sum / (n_npks - 1);
*pn_heart_rate = (int32_t)(6000 / n_peak_interval_sum);
*pch_hr_valid = 1;
}
else
{
*pn_heart_rate = -999;
*pch_hr_valid = 0;
}
for (k = 0; k < n_npks; k++)
an_ir_valley_locs[k] = an_dx_peak_locs[k] + HAMMING_SIZE / 2;
for (k = 0; k < n_ir_buffer_length; k++)
{
an_x[k] = pun_ir_buffer[k];
an_y[k] = pun_red_buffer[k];
}
n_exact_ir_valley_locs_count = 0;
for (k = 0; k < n_npks; k++)
{
un_only_once = 1;
m = an_ir_valley_locs[k];
n_c_min = 16777216;
if (m + 5 < BUFFER_SIZE - HAMMING_SIZE && m - 5 > 0)
{
for (i = m - 5; i < m + 5; i++)
{
if (an_x[i] < n_c_min)
{
if (un_only_once > 0)
{
un_only_once = 0;
}
n_c_min = an_x[i];
an_exact_ir_valley_locs[k] = i;
}
}
if (un_only_once == 0)
n_exact_ir_valley_locs_count++;
}
}
if (n_exact_ir_valley_locs_count < 2)
{
*pn_spo2 = -999;
*pch_spo2_valid = 0;
return;
}
for (k = 0; k < BUFFER_SIZE - MA4_SIZE; k++)
{
an_x[k] = (an_x[k] + an_x[k + 1] + an_x[k + 2] + an_x[k + 3]) / (int32_t)4;
an_y[k] = (an_y[k] + an_y[k + 1] + an_y[k + 2] + an_y[k + 3]) / (int32_t)4;
}
n_ratio_average = 0;
n_i_ratio_count = 0;
for (k = 0; k < 5; k++)
an_ratio[k] = 0;
for (k = 0; k < n_exact_ir_valley_locs_count; k++)
{
if (an_exact_ir_valley_locs[k] > BUFFER_SIZE)
{
*pn_spo2 = -999;
*pch_spo2_valid = 0;
return;
}
}
for (k = 0; k < n_exact_ir_valley_locs_count - 1; k++)
{
n_y_dc_max = -16777216;
n_x_dc_max = -16777216;
if (an_exact_ir_valley_locs[k + 1] - an_exact_ir_valley_locs[k] > 10)
{
for (i = an_exact_ir_valley_locs[k]; i < an_exact_ir_valley_locs[k + 1]; i++)
{
if (an_x[i] > n_x_dc_max)
{
n_x_dc_max = an_x[i];
n_x_dc_max_idx = i;
}
if (an_y[i] > n_y_dc_max)
{
n_y_dc_max = an_y[i];
n_y_dc_max_idx = i;
}
}
n_y_ac = (an_y[an_exact_ir_valley_locs[k + 1]] - an_y[an_exact_ir_valley_locs[k]]) * (n_y_dc_max_idx - an_exact_ir_valley_locs[k]);
n_y_ac = an_y[an_exact_ir_valley_locs[k]] + n_y_ac / (an_exact_ir_valley_locs[k + 1] - an_exact_ir_valley_locs[k]);
n_y_ac = an_y[n_y_dc_max_idx] - n_y_ac;
n_x_ac = (an_x[an_exact_ir_valley_locs[k + 1]] - an_x[an_exact_ir_valley_locs[k]]) * (n_x_dc_max_idx - an_exact_ir_valley_locs[k]);
n_x_ac = an_x[an_exact_ir_valley_locs[k]] + n_x_ac / (an_exact_ir_valley_locs[k + 1] - an_exact_ir_valley_locs[k]);
n_x_ac = an_x[an_exact_ir_valley_locs[k + 1]] - n_x_ac;
n_nume = (n_y_ac * n_x_dc_max) >> 7;
n_denom = (n_x_ac * n_y_dc_max) >> 7;
if (n_denom > 0 && n_i_ratio_count < 5 && n_nume != 0)
{
an_ratio[n_i_ratio_count] = (n_nume * 20) / n_denom;
n_i_ratio_count++;
}
}
}
maxim_sort_ascend(an_ratio, n_i_ratio_count);
n_middle_idx = n_i_ratio_count / 2;
if (n_middle_idx > 1)
n_ratio_average = (an_ratio[n_middle_idx - 1] + an_ratio[n_middle_idx]) / 2;
else
n_ratio_average = an_ratio[n_middle_idx];
if (n_ratio_average > 2 && n_ratio_average < 184)
{
n_spo2_calc = uch_spo2_table[n_ratio_average];
*pn_spo2 = n_spo2_calc;
*pch_spo2_valid = 1;
}
else
{
*pn_spo2 = -999;
*pch_spo2_valid = 0;
}
}
void maxim_find_peaks(int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x, int32_t n_size, int32_t n_min_height, int32_t n_min_distance, int32_t n_max_num)
{
maxim_peaks_above_min_height( pn_locs, pn_npks, pn_x, n_size, n_min_height );
maxim_remove_close_peaks( pn_locs, pn_npks, pn_x, n_min_distance );
*pn_npks = min( *pn_npks, n_max_num );
}
void maxim_peaks_above_min_height(int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x, int32_t n_size, int32_t n_min_height)
{
int32_t i = 1, n_width;
*pn_npks = 0;
while (i < n_size-1){
if (pn_x[i] > n_min_height && pn_x[i] > pn_x[i-1]){
n_width = 1;
while (i+n_width < n_size && pn_x[i] == pn_x[i+n_width])
n_width++;
if (pn_x[i] > pn_x[i+n_width] && (*pn_npks) < 15 ){
pn_locs[(*pn_npks)++] = i;
i += n_width+1;
}
else
i += n_width;
}
else
i++;
}
}
void maxim_remove_close_peaks(int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x, int32_t n_min_distance)
{
int32_t i, j, n_old_npks, n_dist;
maxim_sort_indices_descend( pn_x, pn_locs, *pn_npks );
for ( i = -1; i < *pn_npks; i++ ){
n_old_npks = *pn_npks;
*pn_npks = i+1;
for ( j = i+1; j < n_old_npks; j++ ){
n_dist = pn_locs[j] - ( i == -1 ? -1 : pn_locs[i] );
if ( n_dist > n_min_distance || n_dist < -n_min_distance )
pn_locs[(*pn_npks)++] = pn_locs[j];
}
}
maxim_sort_ascend( pn_locs, *pn_npks );
}
void maxim_sort_ascend(int32_t *pn_x,int32_t n_size)
{
int32_t i, j, n_temp;
for (i = 1; i < n_size; i++) {
n_temp = pn_x[i];
for (j = i; j > 0 && n_temp < pn_x[j-1]; j--)
pn_x[j] = pn_x[j-1];
pn_x[j] = n_temp;
}
}
void maxim_sort_indices_descend(int32_t *pn_x, int32_t *pn_indx, int32_t n_size)
{
int32_t i, j, n_temp;
for (i = 1; i < n_size; i++) {
n_temp = pn_indx[i];
for (j = i; j > 0 && pn_x[n_temp] > pn_x[pn_indx[j-1]]; j--)
pn_indx[j] = pn_indx[j-1];
pn_indx[j] = n_temp;
}
}
其他部分函数如myiic等使用的是正点原子的官方例程,基于篇幅原因,不再敖述。
接线图与实物连接

max30102 | stm32最小板 |
---|
INT | PB9 |
VIN | 3V3 |
GND | GND |
SDA | PB8 |
SCL | PB7 |
OLED显示屏 | stm32最小板 |
---|
SCL | PB13 |
SDA | PB12 |
GND | GND |
VCC | VCC |
蓝牙模块 | stm32最小板 |
---|
TXD | PA10 |
RXD | PA9 |
GND | GND |
VCC | VCC |
测试效果图
