首先来张硬件全家福,运行结果和软件项目构成图。



硬件上主要用了以下几个模块:
MAX78000开发板 2.MAXREFDES117开发板 3. OLED模块 4.转接底板5.USB转mini usb数据线(和stlink相连)
软件上,使用VSCODE作为开发环境,依托于ADI提供的maximsdk 的固件进行开发。
电路中使用一个软件模拟IIC用来驱动OLED,使用硬件IIC来驱动max30102,使用一个IO控制RGB中的R灯。
max78000开发板资源分配如下:
IO分配 | 信号 | IO方向 | IO功能 |
P2.3 | OLED_SDA | IO | OLED模拟IIC数据 |
P2.4 | OLED_SCL | O | oled模拟IIC时钟 |
P0.16 | IIC1_SCL1 | 0 | max30102 IIC时钟 |
P0.17 | IIC1_SDA1 | IO | max30102 IIC数据 |
P0.19 | max30102 INT | I | 中断信号 |
P2.0 | RGB R灯 | O | R灯控制信号 |
实现的任务:
1、使用 eclipse maximsdk 的固件,学会点亮 RGB 灯
2、实现 OLED 屏幕显示信息
3、驱动 MAX30102 传感器,采集数据并通过分析,生成血氧、心率,显示 到 OLED 屏幕中
下面是成果。
第一张图是驱动RGB中的R灯。

第二张图是U8G2驱动库的移植。可详见过程贴【“Let'sdo“活动第二期-DIY智能手环】过程贴-电子产品世界论坛 (eepw.com.cn)

第三张图是驱动 MAX30102 传感器,采集数据并通过分析,生成血氧、心率,显示 到 OLED 屏幕中

下面是主要的功能代码。
在数据结构上,定义了u8g2需要的结构体,其余则是心率和血氧的采集和计算过程。这部分参考了论坛网友的一些算法,但感觉结果不太准,因此这里就简单描述一下。在过程贴中有采集的原始数据,估计还是要一些更合适的算法才能计算得到较好的结果。
/***** Includes *****/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "board.h"
#include "mxc_device.h"
#include "mxc_delay.h"
#include "nvic_table.h"
#include "i2c.h"
#include "max30102.h"
#include "max7800_u8g2.h"
#include "pb.h"
#include "gpio.h"
#include "u8g2.h"
/***** Globals *****/
uint8_t counter = 0;
char buff[20];
#define MXC_GPIO_PORT_OUT MXC_GPIO2
#define MXC_GPIO_PIN_OUT MXC_GPIO_PIN_0
uint8_t spo2Data=0; // 血氧数据
uint8_t heartData=0; // 心率数据
u8g2_t u8g2;
void max30102_i2c_init(void)
{
int error = MXC_I2C_Init(I2C_MASTER, 1, 0);
if (error != E_NO_ERROR)
{
printf("I2C init fail:%d\n", error);
}
else
{
MXC_I2C_SetFrequency(I2C_MASTER, I2C_FREQ);
printf("I2C init success\n");
}
}
int main(void)
{
unsigned int flag = 0;
mxc_gpio_cfg_t gpio_out;
IIC_Init(); //Init I2C pins
u8g2Init(&u8g2);
draw(&u8g2);
MXC_Delay(1000000);
/* Setup output pin. */
gpio_out.port = MXC_GPIO_PORT_OUT;
gpio_out.mask = MXC_GPIO_PIN_OUT;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
MXC_GPIO_Config(&gpio_out);
u8g2_SetFont(&u8g2, u8g2_font_sirclivethebold_tr); //u8g2_font_smart_patrol_nbp_tr
u8g2_ClearBuffer(&u8g2);
u8g2_SetFontRefHeightText(&u8g2);
u8g2_SetFontPosTop(&u8g2);
//u8g2_DrawStr(&u8g2, 0, 30, "u8g2 Soft I2C");
// u8g2_SendBuffer(&u8g2);
max30102_i2c_init();
if (max30102_init() != E_NO_ERROR)
{
printf("MAX30102 init failed\n");
u8g2_DrawStr(&u8g2, 0, 30, "MAX30102 init failed");
u8g2_SendBuffer(&u8g2);
}
else{
printf("MAX30102 init OK\n");
u8g2_DrawStr(&u8g2, 0, 30, "MAX30102 init OK");
u8g2_SendBuffer(&u8g2);
}
// max30102_read_fifo(&REDDATA, &IRDATA);
// u8g2_ClearBuffer(&u8g2);
// u8g2_DrawStr(&u8g2, 0, 30, "HR");
// sprintf(buff,"%d%%",REDDATA);
// u8g2_DrawStr(&u8g2,80,30,buff);
// u8g2_DrawStr(&u8g2, 0, 40, "spo2");
// sprintf(buff,"%d%%",IRDATA);
// u8g2_DrawStr(&u8g2,80,40,buff);
// u8g2_SendBuffer(&u8g2);
while (1)
{
flag = ~flag;
if(flag != 0)
{
MXC_GPIO_OutSet(gpio_out.port, gpio_out.mask);
printf("LED FLAG IS %d,R is OFF\n", flag);
MXC_Delay(1000000); //时间不能很短,否则会出错
}
else
{
MXC_GPIO_OutClr(gpio_out.port, gpio_out.mask);
printf("LED FLAG IS %d,R is ON\n", flag);
MXC_Delay(1000000);
}
max30102_get(&heartData, &spo2Data);
printf("Heart Rate:%d bpm, SpO2:%d%% \n", heartData,spo2Data );
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2, 0, 30, "HR");
sprintf(buff,"%4d",heartData);
u8g2_DrawStr(&u8g2,50,30,buff);
u8g2_DrawStr(&u8g2, 0, 40, "spo2");
sprintf(buff,"%d%%",spo2Data);
u8g2_DrawStr(&u8g2,50,40,buff);
u8g2_SendBuffer(&u8g2);
}
}
//max30102.c
int max30102_get(uint8_t *HeartRate, uint8_t *spo2Data)
{
for (int i = 0; i < BUFFER_LENTH; i++)
{
while (MAX30102_INT == 1) ; // 等待中断引脚
max30102_read_fifo(&aun_red_buffer[i], &aun_ir_buffer[i]);
}
maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, BUFFER_LENTH, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid); // 传入500个心率和血氧数据计算传感器检测结论,反馈心率和血氧测试结果
if ((1 == ch_hr_valid) && (1 == ch_spo2_valid) && (n_heart_rate < 120) && (n_sp02 < 101))
{
*HeartRate = n_heart_rate;
*spo2Data = n_sp02;
return 1; // 有效数据
}
return 0;
}
我要赚赏金
