项目概况:
项目用的主控是ADI公司的MAX78000单片机,具有arm cortex-m4内核与risc-v AI协处理器。板卡还带有音频line-in/out接口,SD卡接口。本次智能手环项目的重点放在
板载屏幕RGB彩灯,使用GPIO驱动。
oled屏幕驱动,使用硬件IIC接口驱动。
驱动max30102传感器实现心率与血氧数据的测量,使用硬件IIC接口驱动。
系统框图:
项目硬件框图如下:P2.0, P2.1, P2.2用于驱动R,G,B小灯。0.16与P0.17用于IIC总线SCL,SDA。

软件流程图:
项目软件流程图如下所示,基于bare-metal模式,比较简单。

开发关键:
任务1:点亮RGB灯
实现细节参考:第二期-智能手环DIY活动-GPIO点亮LED过程贴 https://forum.eepw.com.cn/thread/394430/1
重点是相关结构体:
mxc_gpio_cfg_t red_led_pin = {MXC_GPIO2, MXC_GPIO_PIN_0,
MXC_GPIO_FUNC_OUT, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH};
MXC_GPIO_Config(&red_led_pin);
MXC_GPIO_OutSet(red_led_pin.port, red_led_pin.mask);任务2:驱动OLED屏幕
实现细节参考:第二期-智能手环DIY活动-屏幕驱动过程贴 https://forum.eepw.com.cn/thread/394423/1
重点是如何调用MAX78000 SDK的IIC接口进行数据发送。
任务3:驱动MAX30102,实现血氧、心率检测并显示
实现重点如下:
复位与配置MAX30102模式:
Max30102_reset(); //reset max30102 MAX30102_Config(); //config max30102
实现如下:
uint8_t Max30102_reset(void)
{
if(max30102_write_reg(REG_MODE_CONFIG, 0x40))
return 1;
else
return 0;
}
void MAX30102_Config(void)
{
max30102_write_reg(REG_INTR_ENABLE_1,0xc0); //INTR setting
max30102_write_reg(REG_INTR_ENABLE_2,0x00);//
max30102_write_reg(REG_FIFO_WR_PTR,0x00);//FIFO_WR_PTR[4:0]
max30102_write_reg(REG_OVF_COUNTER,0x00);//OVF_COUNTER[4:0]
max30102_write_reg(REG_FIFO_RD_PTR,0x00);//FIFO_RD_PTR[4:0]
max30102_write_reg(REG_FIFO_CONFIG,0x0f);//sample avg = 1, fifo rollover=false, fifo almost full = 17
max30102_write_reg(REG_MODE_CONFIG,0x03);//0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
max30102_write_reg(REG_SPO2_CONFIG,0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (50 Hz), LED pulseWidth (400uS)
max30102_write_reg(REG_LED1_PA,0x32);//Choose value for ~ 10mA for LED1
max30102_write_reg(REG_LED2_PA,0x32);// Choose value for ~ 10mA for LED2
max30102_write_reg(REG_PILOT_PA,0x7f);// Choose value for ~ 25mA for Pilot LED
}max30102传感器数据的获取:
void blood_data_update(void)
{
g_fft_index=0;
while(g_fft_index < FFT_N)
{
while(max30102_read_reg(REG_INTR_STATUS_1)&0x40 )
{
max30102_read_fifo(); //read from MAX30102 FIFO2
if(g_fft_index < FFT_N)
{
s1[g_fft_index].real = fifo_red;
s1[g_fft_index].imag= 0;
s2[g_fft_index].real = fifo_ir;
s2[g_fft_index].imag= 0;
g_fft_index++;
}
}
}
}提取心率与血氧数据:
void blood_data_translate(void)
{
float n_denom;
uint16_t i;
float dc_red =0;
float dc_ir =0;
float ac_red =0;
float ac_ir =0;
for (i=0 ; i<FFT_N ; i++ )
{
dc_red += s1[i].real ;
dc_ir += s2[i].real ;
}
dc_red =dc_red/FFT_N ;
dc_ir =dc_ir/FFT_N ;
for (i=0 ; i<FFT_N ; i++ )
{
s1[i].real = s1[i].real - dc_red ;
s2[i].real = s2[i].real - dc_ir ;
}
for(i = 1;i < FFT_N-1;i++)
{
n_denom= ( s1[i-1].real + 2*s1[i].real + s1[i+1].real);
s1[i].real= n_denom/4.00;
n_denom= ( s2[i-1].real + 2*s2[i].real + s2[i+1].real);
s2[i].real= n_denom/4.00;
}
for(i = 0;i < FFT_N-8;i++)
{
n_denom= ( s1[i].real+s1[i+1].real+ s1[i+2].real+ s1[i+3].real+ s1[i+4].real+ s1[i+5].real+ s1[i+6].real+ s1[i+7].real);
s1[i].real= n_denom/8.00;
n_denom= ( s2[i].real+s2[i+1].real+ s2[i+2].real+ s2[i+3].real+ s2[i+4].real+ s2[i+5].real+ s2[i+6].real+ s2[i+7].real);
s2[i].real= n_denom/8.00;
}
g_fft_index = 0;
FFT(s1);
FFT(s2);
for(i = 0;i < FFT_N;i++)
{
s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
s1[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
}
for (i=1 ; i<FFT_N ; i++ )
{
ac_red += s1[i].real ;
ac_ir += s2[i].real ;
}
for(i = 0;i < 50;i++)
{
if(s1[i].real<=10)
break;
}
int s1_max_index = find_max_num_index(s1, 60);
int s2_max_index = find_max_num_index(s2, 60);
if(i>=45)
{
uint16_t Heart_Rate = 60.00 * SAMPLES_PER_SECOND * s1_max_index / FFT_N;
heart = Heart_Rate;
float R = (ac_ir*dc_red)/(ac_red*dc_ir);
float sp02_num = -45.060*R*R+ 30.354 *R + 94.845;
SpO2 = sp02_num;
}
else
{
heart = 0;
SpO2 = 0;
}
}演示视频:
项目演示视频发布在B站:https://www.bilibili.com/video/BV1A6hqzzEkG/?vd_source=06b417808f9325071f39e5fd55985221
总结:
项目实现的过程中熟悉了MAX78000的SDK,首次实现了硬件IIC驱动SSD1315屏幕和MAX30102传感器。
在OLED显示遇到困难的时候,参考了论坛网友之前的分享,特此感谢。
整体上完成了基础任务的3个任务,感谢EEPW与得捷提供的机会。
完整代码:
我要赚赏金
