项目概况:
项目用的主控是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与得捷提供的机会。
完整代码: