[设计过程分享]
MAX32630FTHR设计笔记(11):血氧传感器MAX30102采集人体血氧浓度和心率(C语言版...
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[10] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A};
-
- uint32_t aun_ir_buffer[500]; //IR LED sensor data
- int32_t n_ir_buffer_length; //data length
- uint32_t aun_red_buffer[500]; //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_t ch_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[i])[/i]
- [i] un_min=aun_red_buffer; //update signal min[/i]
- [i] if(un_max<aun_red_buffer)[/i]
- [i] un_max=aun_red_buffer; //update signal max[/i]
- [i] printf("red=");[/i]
- [i] printf("%i", aun_red_buffer);[/i]
- [i] printf(", ir=");[/i]
- [i] printf("%i\n\r", aun_ir_buffer);[/i]
- [i] }[/i]
- [i] un_prev_data=aun_red_buffer;[/i]
-
-
- [i] //calculate heart rate and SpO2 after first 500 samples (first 5 seconds of samples)[/i]
- [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); [/i]
-
- [i] //Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second[/i]
- [i] while(1)[/i]
- [i] {[/i]
- [i] i=0;[/i]
- [i] un_min=0x3FFFF;//???[/i]
- [i] un_max=0;[/i]
-
- [i] //dumping the first 100 sets of samples in the memory and shift the last 400 sets of samples to the top[/i]
- [i] for(i=100;i<500;i++)[/i]
- [i] {[/i]
- [i] aun_red_buffer[i-100]=aun_red_buffer;[/i]
- [i] aun_ir_buffer[i-100]=aun_ir_buffer;[/i]
-
- [i] //update the signal min and max[/i]
- [i] if(un_min>aun_red_buffer)[/i]
- [i] un_min=aun_red_buffer;[/i]
- [i] if(un_max<aun_red_buffer)[/i]
- [i] un_max=aun_red_buffer;[/i]
- [i] }[/i]
-
- [i] //take 100 sets of samples before calculating the heart rate.[/i]
- [i] for(i=400;i<500;i++)[/i]
- [i] {[/i]
- [i] un_prev_data=aun_red_buffer[i-1];[/i]
- [i] // while(INT.read()==1);[/i]
- [i] maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));[/i]
-
- [i] if(aun_red_buffer>un_prev_data)//just to determine the brightness of LED according to the deviation of adjacent two AD data[/i]
- [i] {[/i]
- [i] f_temp=aun_red_buffer-un_prev_data;[/i]
- [i] f_temp/=(un_max-un_min);[/i]
- [i] f_temp*=MAX_BRIGHTNESS;[/i]
- [i] n_brightness-=(int)f_temp;[/i]
- [i] if(n_brightness<0)[/i]
- [i] n_brightness=0;[/i]
- [i] }[/i]
- [i] else[/i]
- [i] {[/i]
- [i] f_temp=un_prev_data-aun_red_buffer;[/i]
- [i] f_temp/=(un_max-un_min);[/i]
- [i] f_temp*=MAX_BRIGHTNESS;[/i]
- [i] n_brightness+=(int)f_temp;[/i]
- [i] if(n_brightness>MAX_BRIGHTNESS)[/i]
- [i] n_brightness=MAX_BRIGHTNESS;[/i]
- [i] }[/i]
-
- [i] //led.write(1-(float)n_brightness/256);//pwm control led brightness[/i]
-
- [i] //send samples and calculation result to terminal program through UART[/i]
- [i] printf("red=");[/i]
- [i] printf("%i", aun_red_buffer);[/i]
- [i] printf(", ir=");[/i]
- [i] printf("%i", aun_ir_buffer);[/i]
- [i] printf(", HR=%i, ", n_heart_rate); [/i]
- [i] printf("HRvalid=%i, ", ch_hr_valid);[/i]
- [i] printf("SpO2=%i, ", n_sp02);[/i]
- [i] printf("SPO2Valid=%i\n\r", ch_spo2_valid);[/i]
- [i] }[/i]
- [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); [/i]
- [i] }[/i]
-
- [i]}[/i]
- [i]
第三个文件max30102.cpp是重点,先给出max30102.cpp的源代码:
- /** \file max30102.cpp ******************************************************[/i]
- [i]*[/i]
- [i]* Project: MAXREFDES117#[/i]
- [i]* Filename: max30102.cpp[/i]
- [i]* Description: This module is an embedded controller driver for the MAX30102[/i]
- [i]*[/i]
- [i]*[/i]
- [i]* --------------------------------------------------------------------[/i]
- [i]*[/i]
- [i]* This code follows the following naming conventions:[/i]
- [i]*[/i]
- [i]* char ch_pmod_value[/i]
- [i]* char (array) s_pmod_s_string[16][/i]
- [i]* float f_pmod_value[/i]
- [i]* int32_t n_pmod_value[/i]
- [i]* int32_t (array) an_pmod_value[16][/i]
- [i]* int16_t w_pmod_value[/i]
- [i]* int16_t (array) aw_pmod_value[16][/i]
- [i]* uint16_t uw_pmod_value[/i]
- [i]* uint16_t (array) auw_pmod_value[16][/i]
- [i]* uint8_t uch_pmod_value[/i]
- [i]* uint8_t (array) auch_pmod_buffer[16][/i]
- [i]* uint32_t un_pmod_value[/i]
- [i]* int32_t * pn_pmod_value[/i]
- [i]*[/i]
- [i]* ------------------------------------------------------------------------- */[/i]
- [i]/*******************************************************************************[/i]
- [i]* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.[/i]
- [i]*[/i]
- [i]* Permission is hereby granted, free of charge, to any person obtaining a[/i]
- [i]* copy of this software and associated documentation files (the "Software"),[/i]
- [i]* to deal in the Software without restriction, including without limitation[/i]
- [i]* the rights to use, copy, modify, merge, publish, distribute, sublicense,[/i]
- [i]* and/or sell copies of the Software, and to permit persons to whom the[/i]
- [i]* Software is furnished to do so, subject to the following conditions:[/i]
- [i]*[/i]
- [i]* The above copyright notice and this permission notice shall be included[/i]
- [i]* in all copies or substantial portions of the Software.[/i]
- [i]*[/i]
- [i]* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS[/i]
- [i]* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF[/i]
- [i]* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.[/i]
- [i]* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES[/i]
- [i]* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,[/i]
- [i]* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR[/i]
- [i]* OTHER DEALINGS IN THE SOFTWARE.[/i]
- [i]*[/i]
- [i]* Except as contained in this notice, the name of Maxim Integrated[/i]
- [i]* Products, Inc. shall not be used except as stated in the Maxim Integrated[/i]
- [i]* Products, Inc. Branding Policy.[/i]
- [i]*[/i]
- [i]* The mere transfer of this software does not imply any licenses[/i]
- [i]* of trade secrets, proprietary technology, copyrights, patents,[/i]
- [i]* trademarks, maskwork rights, or any other form of intellectual[/i]
- [i]* property whatsoever. Maxim Integrated Products, Inc. retains all[/i]
- [i]* ownership rights.[/i]
- [i]*******************************************************************************[/i]
- [i]*/[/i]
- [i]#include "mbed.h"[/i]
- [i]#include "MAX30102.h"[/i]
-
- [i]I2C i2c(P3_4, P3_5);[/i]
-
- [i]bool maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data)[/i]
- [i]/**[/i]
- [i]* \brief Write a value to a MAX30102 register[/i]
- [i]* \par Details[/i]
- [i]* This function writes a value to a MAX30102 register[/i]
- [i]*[/i]
- [i]* \param[in] uch_addr - register address[/i]
- [i]* \param[in] uch_data - register data[/i]
- [i]*[/i]
- [i]* \retval true on success[/i]
- [i]*/[/i]
- [i]{[/i]
- [i] char ach_i2c_data[2];[/i]
- [i] ach_i2c_data[0]=uch_addr;[/i]
- [i] ach_i2c_data[1]=uch_data;[/i]
-
- [i] if(i2c.write(I2C_WRITE_ADDR, ach_i2c_data, 2, false)==0)[/i]
- [i] return true;[/i]
- [i] else[/i]
- [i] return false;[/i]
- [i]}[/i]
-
- [i]bool maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data)[/i]
- [i]/**[/i]
- [i]* \brief Read a MAX30102 register[/i]
- [i]* \par Details[/i]
- [i]* This function reads a MAX30102 register[/i]
- [i]*[/i]
- [i]* \param[in] uch_addr - register address[/i]
- [i]* \param[out] puch_data - pointer that stores the register data[/i]
- [i]*[/i]
- [i]* \retval true on success[/i]
- [i]*/[/i]
- [i]{[/i]
- [i] char ch_i2c_data;[/i]
- [i] ch_i2c_data=uch_addr;[/i]
- [i] if(i2c.write(I2C_WRITE_ADDR, &ch_i2c_data, 1, true)!=0)[/i]
- [i] return false;[/i]
- [i] if(i2c.read(I2C_READ_ADDR, &ch_i2c_data, 1, false)==0)[/i]
- [i] {[/i]
- [i] *puch_data=(uint8_t) ch_i2c_data;[/i]
- [i] return true;[/i]
- [i] }[/i]
- [i] else[/i]
- [i] return false;[/i]
- [i]}[/i]
-
- [i]bool maxim_max30102_init()[/i]
- [i]/**[/i]
- [i]* \brief Initialize the MAX30102[/i]
- [i]* \par Details[/i]
- [i]* This function initializes the MAX30102[/i]
- [i]*[/i]
- [i]* \param None[/i]
- [i]*[/i]
- [i]* \retval true on success[/i]
- [i]*/[/i]
- [i]{[/i]
- [i] if(!maxim_max30102_write_reg(REG_INTR_ENABLE_1,0xc0)) // INTR setting[/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_INTR_ENABLE_2,0x00))[/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_FIFO_WR_PTR,0x00)) //FIFO_WR_PTR[4:0][/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_OVF_COUNTER,0x00)) //OVF_COUNTER[4:0][/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00)) //FIFO_RD_PTR[4:0][/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_FIFO_CONFIG,0x0f)) //sample avg = 1, fifo rollover=false, fifo almost full = 17[/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_MODE_CONFIG,0x03)) //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED[/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_SPO2_CONFIG,0x27)) // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)[/i]
- [i] return false;[/i]
-
- [i] if(!maxim_max30102_write_reg(REG_LED1_PA,0x24)) //Choose value for ~ 7mA for LED1[/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_LED2_PA,0x24)) // Choose value for ~ 7mA for LED2[/i]
- [i] return false;[/i]
- [i] if(!maxim_max30102_write_reg(REG_PILOT_PA,0x7f)) // Choose value for ~ 25mA for Pilot LED[/i]
- [i] return false;[/i]
- [i] return true; [/i]
- [i]}[/i]
-
- [i]bool maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led)[/i]
- [i]/**[/i]
- [i]* \brief Read a set of samples from the MAX30102 FIFO register[/i]
- [i]* \par Details[/i]
- [i]* This function reads a set of samples from the MAX30102 FIFO register[/i]
- [i]*[/i]
- [i]* \param[out] *pun_red_led - pointer that stores the red LED reading data[/i]
- [i]* \param[out] *pun_ir_led - pointer that stores the IR LED reading data[/i]
- [i]*[/i]
- [i]* \retval true on success[/i]
- [i]*/[/i]
- [i]{[/i]
- [i] uint32_t un_temp;[/i]
- [i] unsigned char uch_temp;[/i]
- [i] *pun_red_led=0;[/i]
- [i] *pun_ir_led=0;[/i]
- [i] char ach_i2c_data[6];[/i]
-
- [i] //read and clear status register[/i]
- [i] maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);[/i]
- [i] maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);[/i]
-
- [i] ach_i2c_data[0]=REG_FIFO_DATA;[/i]
- [i] if(i2c.write(I2C_WRITE_ADDR, ach_i2c_data, 1, true)!=0)[/i]
- [i] return false;[/i]
- [i] if(i2c.read(I2C_READ_ADDR, ach_i2c_data, 6, false)!=0)[/i]
- [i] {[/i]
- [i] return false;[/i]
- [i] }[/i]
- [i] un_temp=(unsigned char) ach_i2c_data[0];[/i]
- [i] un_temp<<=16;[/i]
- [i] *pun_red_led+=un_temp;[/i]
- [i] un_temp=(unsigned char) ach_i2c_data[1];[/i]
- [i] un_temp<<=8;[/i]
- [i] *pun_red_led+=un_temp;[/i]
- [i] un_temp=(unsigned char) ach_i2c_data[2];[/i]
- [i] *pun_red_led+=un_temp;[/i]
-
- [i] un_temp=(unsigned char) ach_i2c_data[3];[/i]
- [i] un_temp<<=16;[/i]
- [i] *pun_ir_led+=un_temp;[/i]
- [i] un_temp=(unsigned char) ach_i2c_data[4];[/i]
- [i] un_temp<<=8;[/i]
- [i] *pun_ir_led+=un_temp;[/i]
- [i] un_temp=(unsigned char) ach_i2c_data[5];[/i]
- [i] *pun_ir_led+=un_temp;[/i]
- [i] *pun_red_led&=0x03FFFF; //Mask MSB [23:18][/i]
- [i] *pun_ir_led&=0x03FFFF; //Mask MSB [23:18][/i]
-
-
- [i] return true;[/i]
- [i]}[/i]
-
- [i]bool maxim_max30102_reset()[/i]
- [i]/**[/i]
- [i]* \brief Reset the MAX30102[/i]
- [i]* \par Details[/i]
- [i]* This function resets the MAX30102[/i]
- [i]*[/i]
- [i]* \param None[/i]
- [i]*[/i]
- [i]* \retval true on success[/i]
- [i]*/[/i]
- [i]{[/i]
- [i] if(!maxim_max30102_write_reg(REG_MODE_CONFIG,0x40))[/i]
- [i] return false;[/i]
- [i] else[/i]
- [i] return true; [/i]
- [i]}[/i]
- [i]
移植改编后的程序为:
- /***********************************************
- @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[16]
- * float f_pmod_value
- * int32_t n_pmod_value
- * int32_t (array) an_pmod_value[16]
- * int16_t w_pmod_value
- * int16_t (array) aw_pmod_value[16]
- * uint16_t uw_pmod_value
- * uint16_t (array) auw_pmod_value[16]
- * uint8_t uch_pmod_value
- * uint8_t (array) auch_pmod_buffer[16]
- * 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[in] uch_addr - register address
- * \param[in] uch_data - register data
- *
- * \retval true on success
- */
- {
- char ach_i2c_data[2];
- ach_i2c_data[0]=uch_addr;
- ach_i2c_data[1]=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[in] uch_addr - register address
- * \param[out] 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[4:0]
- return 0;
- if(!maxim_max30102_write_reg(REG_OVF_COUNTER,0x00)) //OVF_COUNTER[4:0]
- return 0;
- if(!maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00)) //FIFO_RD_PTR[4:0]
- 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[out] *pun_red_led - pointer that stores the red LED reading data
- * \param[out] *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[6];
-
- //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[0]=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[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; //Mask MSB [23:18]
-
-
- 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,可以说非常准确。
本帖最后由 Justice_Gao 于 2017-9-21 21:55 编辑
楼主,能发一份工程吗,邮箱:3139927868@qq.com,万分感谢
发你,这可是呕心沥血的作品,你先发给ipad过来吧 哈哈
楼主 帮忙看看 输出不是很稳定,是啥原因,谢谢了 Ipad已备好哈
楼主的ipad拿到了吗,程序可以开源了
路过看看
充放电数显全套方案,双口快充慢充检测电流电压,两线三线直流电压表,配套三个8尺寸15*8MM带AV电流电压单位专利数码屏,资料QQ2981074992 邮箱同上
楼主 能麻烦发一份心率和血氧计算算法吗 不知道我现在手里的算法对不对 谢谢楼主了
补充内容 (2018-4-2 12:35):
楼主我用的是和你一样的测量算法,现在测量结果出来饱和度是正确的,但是心率结果一会维持一个数值,过一会又发生变化,请问你的也是这种情况吗?还是一直稳定在一个数值?
补充内容 (2018-4-2 12:35):
楼主我用的是和你一样的测量算法,现在测量结果出来饱和度是正确的,但是心率结果一会维持一个数值,过一会又发生变化,请问你的也是这种情况吗?还是一直稳定在一个数值?
楼主,可以给我一份文件么,最近电设做这个题目,一直没有头绪
1083557165@qq.com
楼主我的q2649558793,可以加上交流一下吗!
大佬,能发一份工程吗,邮箱:1536760015@qq.com,万分感谢
楼主,跪求一份工程,毕设因为这个模块卡了很久
,万分感谢!!!
邮箱:
978460447@qq.com
楼主可以发一下工程文件吗?邮箱
1197421427@qq.com 万分感谢!
你好,请问你对这个压缩包里的代码进行了改动吗?我从串口输出的数据是乱码
楼主,跪求一份工程,万分感谢!!!
邮箱:
2366299515@qq.com
我用nrf53832能接收到MAX30102心率血氧数据后就没搞了,不知楼主研究到什么程度了