MAX32630FTHR设计笔记(11):血氧传感器MAX30102采集人体血氧浓度和心率(C语言版...
本帖最后由 Justice_Gao 于 2017-9-21 21:55 编辑max30102的原理我就不解释了,现在网上能够下载或者共享的MAX30102程序源代码,全部是基于mbed的,编程语言为C++类型,如果使用KEIL或者IAR调试这些基于mbed导出后的程序,非常不方便,也不能很好的将MAX30102驱动程序应用到基于C语言的51单片机、STM32单片机,甚至用IAR和KEIL等C语言开发的平台,不能很好将MAX30102与自己的程序进行结合,现在,福利来了,给你共享一下,基于KEIL C语言的MAX30102驱动,以及采集人体血氧浓度和心率的测试程序。(1)首先来看,网络上共享的基于mbed的C++类型的max30102驱动程序,第一个algorithm.cpp为血氧和心率的计算算法,可以直接调用过了,无需做任何改变,只需将文件改为algorithm.c即可。
第二个main.cpp文件改成一下代码
/**
* @file main.c
* @brief 低功耗设计,程序实现舒眠科技智眠传感带信号采集和呼吸,心跳提取功能,实现和上位设备的通信功能
*/
//作者:Justice
//版本:V1.0.0
//日期:2017-05-25
//工具:Keil MDK 5.23
//修改日期:2017-06-28
//修改内容:不修改底层源代码,把需要改的函数放在相应的自定义文件中
//修改日期:2017-06-29
//修改内容:增加了BootLoader程序,支持IAP升级
/***** Includes *****/
#include "Com.h"
#define REPORTING_PERIOD_MS 1000
const uint8_t Test_Buff = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A};
uint32_t aun_ir_buffer; //IR LED sensor data
int32_t n_ir_buffer_length; //data length
uint32_t aun_red_buffer; //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_tch_hr_valid; //indicator to show if the heart rate calculation is valid
uint8_t uch_dummy;
#define MAX_BRIGHTNESS 255
#define false 0
#define true 1
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;
USART2_Configuration(115200);
I2CM_Init(MAX14690_I2CM, &max14690_sys_cfg, I2CM_SPEED_100KHZ);
I2CM_Init(MXC_I2CM1, &max30102_sys_cfg, I2CM_SPEED_100KHZ);
//Device_Hardware_Init();
maxim_max30102_reset(); //resets the MAX30102
//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=500; //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(INT.read()==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)
un_min=aun_red_buffer; //update signal min
if(un_max<aun_red_buffer)
un_max=aun_red_buffer; //update signal max
printf("red=");
printf("%i", aun_red_buffer);
printf(", ir=");
printf("%i\n\r", aun_ir_buffer);
}
un_prev_data=aun_red_buffer;
//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);
//Continuously taking samples from MAX30102.Heart rate and SpO2 are calculated every 1 second
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=100;i<500;i++)
{
aun_red_buffer=aun_red_buffer;
aun_ir_buffer=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;
}
//take 100 sets of samples before calculating the heart rate.
for(i=400;i<500;i++)
{
un_prev_data=aun_red_buffer;
// while(INT.read()==1);
maxim_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;
}
//led.write(1-(float)n_brightness/256);//pwm control led brightness
//send samples and calculation result to terminal program through UART
printf("red=");
printf("%i", aun_red_buffer);
printf(", ir=");
printf("%i", 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);
}
}
第三个文件max30102.cpp是重点,先给出max30102.cpp的源代码:
/** \file max30102.cpp ******************************************************
*
* Project: MAXREFDES117#
* Filename: max30102.cpp
* Description: This module is an embedded controller driver for the MAX30102
*
*
* --------------------------------------------------------------------
*
* This code follows the following naming conventions:
*
* char ch_pmod_value
* char (array) s_pmod_s_string
* float f_pmod_value
* int32_t n_pmod_value
* int32_t (array) an_pmod_value
* int16_t w_pmod_value
* int16_t (array) aw_pmod_value
* uint16_t uw_pmod_value
* uint16_t (array)auw_pmod_value
* uint8_t uch_pmod_value
* uint8_t (array) auch_pmod_buffer
* 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.
*******************************************************************************
*/
#include "mbed.h"
#include "MAX30102.h"
I2C i2c(P3_4, P3_5);
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 uch_addr - register address
* \param uch_data - register data
*
* \retval true on success
*/
{
char ach_i2c_data;
ach_i2c_data=uch_addr;
ach_i2c_data=uch_data;
if(i2c.write(I2C_WRITE_ADDR, ach_i2c_data, 2, false)==0)
return true;
else
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 uch_addr - register address
* \param puch_data - pointer that stores the register data
*
* \retval true on success
*/
{
char ch_i2c_data;
ch_i2c_data=uch_addr;
if(i2c.write(I2C_WRITE_ADDR, &ch_i2c_data, 1, true)!=0)
return false;
if(i2c.read(I2C_READ_ADDR, &ch_i2c_data, 1, false)==0)
{
*puch_data=(uint8_t) ch_i2c_data;
return true;
}
else
return false;
}
bool maxim_max30102_init()
/**
* \brief Initialize the MAX30102
* \par Details
* This function initializes the MAX30102
*
* \param None
*
* \retval true on success
*/
{
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
return false;
if(!maxim_max30102_write_reg(REG_OVF_COUNTER,0x00))//OVF_COUNTER
return false;
if(!maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00))//FIFO_RD_PTR
return false;
if(!maxim_max30102_write_reg(REG_FIFO_CONFIG,0x0f))//sample avg = 1, 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,0x27))// SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
return false;
if(!maxim_max30102_write_reg(REG_LED1_PA,0x24)) //Choose value for ~ 7mA for LED1
return false;
if(!maxim_max30102_write_reg(REG_LED2_PA,0x24)) // Choose value for ~ 7mA 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 *pun_red_led - pointer that stores the red LED reading data
* \param *pun_ir_led - pointer that stores the IR LED reading data
*
* \retval true on success
*/
{
uint32_t un_temp;
unsigned char uch_temp;
*pun_red_led=0;
*pun_ir_led=0;
char ach_i2c_data;
//read and clear status register
maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
ach_i2c_data=REG_FIFO_DATA;
if(i2c.write(I2C_WRITE_ADDR, ach_i2c_data, 1, true)!=0)
return false;
if(i2c.read(I2C_READ_ADDR, ach_i2c_data, 6, false)!=0)
{
return false;
}
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=16;
*pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=8;
*pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
*pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=16;
*pun_ir_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=8;
*pun_ir_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
*pun_ir_led+=un_temp;
*pun_red_led&=0x03FFFF;//Mask MSB
*pun_ir_led&=0x03FFFF;//Mask MSB
return true;
}
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;
}
移植改编后的程序为:
/***********************************************
@from Justice_Gao
***********************************************/
#include "Com.h"
/** \file max30102.cpp ******************************************************
*
* Project: MAXREFDES117#
* Filename: max30102.cpp
* Description: This module is an embedded controller driver for the MAX30102
*
*
* --------------------------------------------------------------------
*
* This code follows the following naming conventions:
*
* char ch_pmod_value
* char (array) s_pmod_s_string
* float f_pmod_value
* int32_t n_pmod_value
* int32_t (array) an_pmod_value
* int16_t w_pmod_value
* int16_t (array) aw_pmod_value
* uint16_t uw_pmod_value
* uint16_t (array)auw_pmod_value
* uint8_t uch_pmod_value
* uint8_t (array) auch_pmod_buffer
* 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.
*******************************************************************************
*/
#include "MAX30100.h"
#include "i2cm.h"
#define MBED_ASSERT(expr) ((void)0)
// write - Master Transmitter Mode
void lock()
{
}
void unlock()
{
}
int I2C_write(int address, const char* data, int length, uint8_t repeated)
{
lock();
// aquire();
int stop = (repeated) ? 0 : 1;
int written = i2c_write(MXC_I2CM1, address, data, length, stop);
unlock();
return length != written;
}
// read - Master Reciever Mode
int I2C_read(int address, char* data, int length, uint8_t repeated) {
lock();
// aquire();
int stop = (repeated) ? 0 : 1;
int read = i2c_read(MXC_I2CM1, address, data, length, stop);
unlock();
return length != read;
}
//******************************************************************************
int i2c_read(mxc_i2cm_regs_t *i2cm, int address, char *data, int length, int stop)
{
MBED_ASSERT(stop != 0);
return I2CM_Read(i2cm, address >> 1, NULL, 0, (uint8_t *)data, length);
}
//******************************************************************************
int i2c_write(mxc_i2cm_regs_t *i2cm, int address, const char *data, int length, int stop)
{
mxc_i2cm_fifo_regs_t *fifo = MXC_I2CM1_FIFO;
if (stop) {
return I2CM_Write(i2cm, address >> 1, NULL, 0, (uint8_t *)data, length);
}
i2cm->inten = 0;
i2cm->intfl = i2cm->intfl;
if (I2CM_Tx(i2cm, fifo, address >> 1, (uint8_t *)data, length, 0) == E_NO_ERROR) {
return length;
} else {
return -1;
}
}
//I2C i2c(I2C_SDA, I2C_SCL);//SDA-PB9,SCL-PB8
uint8_t 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 uch_addr - register address
* \param uch_data - register data
*
* \retval true on success
*/
{
char ach_i2c_data;
ach_i2c_data=uch_addr;
ach_i2c_data=uch_data;
if(I2C_write(I2C_WRITE_ADDR, ach_i2c_data, 2, 0)==0)
return 1;
else
return 0;
}
uint8_t 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 uch_addr - register address
* \param puch_data - pointer that stores the register data
*
* \retval true on success
*/
{
char ch_i2c_data;
ch_i2c_data=uch_addr;
if(I2C_write(I2C_WRITE_ADDR, &ch_i2c_data, 1, 1)!=0)
return 0;
if(I2C_read(I2C_READ_ADDR, &ch_i2c_data, 1, 0)==0)
{
*puch_data=(uint8_t) ch_i2c_data;
return 1;
}
else
return 0;
}
uint8_t maxim_max30102_init()
/**
* \brief Initialize the MAX30102
* \par Details
* This function initializes the MAX30102
*
* \param None
*
* \retval true on success
*/
{
if(!maxim_max30102_write_reg(REG_INTR_ENABLE_1,0xc0)) // INTR setting
return 0;
if(!maxim_max30102_write_reg(REG_INTR_ENABLE_2,0x00))
return 0;
if(!maxim_max30102_write_reg(REG_FIFO_WR_PTR,0x00))//FIFO_WR_PTR
return 0;
if(!maxim_max30102_write_reg(REG_OVF_COUNTER,0x00))//OVF_COUNTER
return 0;
if(!maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00))//FIFO_RD_PTR
return 0;
if(!maxim_max30102_write_reg(REG_FIFO_CONFIG,0x0f))//sample avg = 1, fifo rollover=false, fifo almost full = 17
return 0;
if(!maxim_max30102_write_reg(REG_MODE_CONFIG,0x03)) //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
return 0;
if(!maxim_max30102_write_reg(REG_SPO2_CONFIG,0x27))// SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
return 0;
if(!maxim_max30102_write_reg(REG_LED1_PA,0x24)) //Choose value for ~ 7mA for LED1
return 0;
if(!maxim_max30102_write_reg(REG_LED2_PA,0x24)) // Choose value for ~ 7mA for LED2
return 0;
if(!maxim_max30102_write_reg(REG_PILOT_PA,0x7f)) // Choose value for ~ 25mA for Pilot LED
return 0;
return 1;
}
uint8_t 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 *pun_red_led - pointer that stores the red LED reading data
* \param *pun_ir_led - pointer that stores the IR LED reading data
*
* \retval true on success
*/
{
uint32_t un_temp;
unsigned char uch_temp;
*pun_red_led=0;
*pun_ir_led=0;
char ach_i2c_data;
//read and clear status register
maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
ach_i2c_data=REG_FIFO_DATA;
if(I2C_write(I2C_WRITE_ADDR, ach_i2c_data, 1, 1)!=0)
return 0;
if(I2C_read(I2C_READ_ADDR, ach_i2c_data, 6, 0)!=0)
{
return 0;
}
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=16;
*pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=8;
*pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
*pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=16;
*pun_ir_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
un_temp<<=8;
*pun_ir_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data;
*pun_ir_led+=un_temp;
*pun_red_led&=0x03FFFF;//Mask MSB
*pun_ir_led&=0x03FFFF;//Mask MSB
return 1;
}
uint8_t 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 0;
else
return 1;
}
移植过程中,其实难点在于将i2c.write函数和i2c.read函数转换为代码中的I2C_write(int address, const char* data, int length, uint8_t repeated) 和I2C_read(int address, char* data, int length, uint8_t repeated),因为被移植的代码中的读写函数是调用mbed平台的API,凭借我的聪明才智,我改写处出lock(),unlock(),I2C_write,I2C_read,i2c_read,i2c_write等关键函数,解决了这几个函数,程序就可以运行了
第4个文件是max14690的驱动文件,可以借鉴我的另外一篇帖子MAX32630FTHR设计笔记(1):流水灯(GPIO输出配置)及I2C驱动MAX14690,也是基于C语言编写的,需要注意的是,我分享的所有帖子都是用KEIL C语言编写的
最后给出测试图片吧,视频就不拍了
第一图为max30102模块测到的心率为64,血氧浓度为96,第二图为专业标准设备测得的心率为64,血氧浓度为97,可以说非常准确。
楼主,能发一份工程吗,邮箱:3139927868@qq.com,万分感谢 早起的 发表于 2017-9-23 18:01
楼主,能发一份工程吗,邮箱:3139927868@qq.com,万分感谢
发你,这可是呕心沥血的作品,你先发给ipad过来吧 哈哈 楼主帮忙看看输出不是很稳定,是啥原因,谢谢了Ipad已备好哈
早起的 发表于 2017-9-23 23:07
楼主帮忙看看输出不是很稳定,是啥原因,谢谢了Ipad已备好哈
先寄过来 哈哈 Justice_Gao 发表于 2017-9-23 23:23
先寄过来 哈哈
楼主的ipad拿到了吗,程序可以开源了:congratulate: 路过看看 楼主能麻烦发一份心率和血氧计算算法吗 不知道我现在手里的算法对不对谢谢楼主了
补充内容 (2018-4-2 12:35):
楼主我用的是和你一样的测量算法,现在测量结果出来饱和度是正确的,但是心率结果一会维持一个数值,过一会又发生变化,请问你的也是这种情况吗?还是一直稳定在一个数值?
补充内容 (2018-4-2 12:35):
楼主我用的是和你一样的测量算法,现在测量结果出来饱和度是正确的,但是心率结果一会维持一个数值,过一会又发生变化,请问你的也是这种情况吗?还是一直稳定在一个数值? 楼主,可以给我一份文件么,最近电设做这个题目,一直没有头绪
1083557165@qq.com
楼主我的q2649558793,可以加上交流一下吗! 请问Com.h文件在哪找的? time_opp 发表于 2019-2-13 18:41
请问Com.h文件在哪找的?
自己编写的 大佬,能发一份工程吗,邮箱:1536760015@qq.com,万分感谢 楼主,跪求一份工程,毕设因为这个模块卡了很久:Cry:,万分感谢!!!
邮箱:978460447@qq.com 楼主可以发一下工程文件吗?邮箱1197421427@qq.com 万分感谢! 早起的 发表于 2017-9-23 23:07
楼主帮忙看看输出不是很稳定,是啥原因,谢谢了Ipad已备好哈
你好,请问你对这个压缩包里的代码进行了改动吗?我从串口输出的数据是乱码 楼主,跪求一份工程,万分感谢!!!
邮箱:2366299515@qq.com <p>楼主 能否加个qq:1148543046 想请教</p>
<p>我用nrf53832能接收到MAX30102心率血氧数据后就没搞了,不知楼主研究到什么程度了</p>
页:
[1]
2