本次Let's Do的项目使用的是ADI公司的MAX78000作为主控,使用max30102进行数据采集并在OLED上显示相关信息。
过程贴通过一个硬件I2C,一个模拟I2C进行两个设备的显示,成果贴将修改成共用I2C模式。

点灯任务比较简单,就不在这边再进行复述,具体可以看第二期-智能手环DIY开发环境搭建
OLED的驱动和心率血氧的读取主要是学习I2C的使用,特别是一个I2C通过不同地址选取不同设备。
mxc_i2c_req_t req; req.i2c = MXC_I2C1; // 根据你的硬件选择 req.addr = SSD1306_ADDR;或者MAX30102_ADDR
下面是MAX30102相关读取命令代码
// ---------- MAX30102 寄存器 ----------
#define MAX30102_ADDR 0x57 // 7-bit I2C 地址
#define REG_INT_STATUS_1 0x00
#define REG_INT_ENABLE_1 0x02
#define REG_FIFO_WR_PTR 0x04
#define REG_OVF_COUNTER 0x05
#define REG_FIFO_RD_PTR 0x06
#define REG_FIFO_DATA 0x07
#define REG_MODE_CONFIG 0x09
#define REG_SPO2_CONFIG 0x0A
#define REG_LED1_PA 0x0C // RED LED
#define REG_LED2_PA 0x0D // IR LED
#define REG_TEMP_INTEGER 0x1F
#define REG_TEMP_FRACTION 0x20
#define REG_PART_ID 0xFF
#define MA4_SIZE 4
#define HAMMING_SIZE 5
uint32_t red_buffer[BUFFER_SIZE];
uint32_t ir_buffer[BUFFER_SIZE];
int buffer_index = 0;
// I2C 使用 I2C1
#define I2C_INST MXC_I2C1
// ---------------- I2C 基础读写函数 ----------------
int max30102_write_reg(uint8_t reg, uint8_t value)
{
uint8_t data[2] = {reg, value};
mxc_i2c_req_t req;
req.i2c = I2C_INST;
req.addr = MAX30102_ADDR;
req.tx_buf = data;
req.tx_len = 2;
req.rx_buf = NULL;
req.rx_len = 0;
req.restart = 0;
req.callback = NULL;
return MXC_I2C_MasterTransaction(&req);
}
int max30102_read_reg(uint8_t reg, uint8_t *value)
{
mxc_i2c_req_t req;
int err;
req.i2c = I2C_INST;
req.addr = MAX30102_ADDR;
req.tx_buf = ®
req.tx_len = 1;
req.rx_buf = NULL;
req.rx_len = 0;
req.restart = 1; // Repeated START
req.callback = NULL;
err = MXC_I2C_MasterTransaction(&req);
if (err != E_NO_ERROR)
return err;
req.tx_buf = NULL;
req.tx_len = 0;
req.rx_buf = value;
req.rx_len = 1;
req.restart = 0;
req.callback = NULL;
return MXC_I2C_MasterTransaction(&req);
}
int max30102_read_multi(uint8_t reg, uint8_t *buf, int len)
{
mxc_i2c_req_t req;
int err;
req.i2c = I2C_INST;
req.addr = MAX30102_ADDR;
req.tx_buf = ®
req.tx_len = 1;
req.rx_buf = NULL;
req.rx_len = 0;
req.restart = 1;
req.callback = NULL;
err = MXC_I2C_MasterTransaction(&req);
if (err != E_NO_ERROR)
return err;
req.tx_buf = NULL;
req.tx_len = 0;
req.rx_buf = buf;
req.rx_len = len;
req.restart = 0;
req.callback = NULL;
return MXC_I2C_MasterTransaction(&req);
}
// ---------------- MAX30102 初始化 ----------------
int max30102_init(void)
{
int ret;
uint8_t part_id;
MXC_I2C_Shutdown(I2C_INST);
MXC_I2C_Init(I2C_INST, 1, 0); // master mode
MXC_I2C_SetFrequency(I2C_INST, 400000); // 400kHz
ret = max30102_read_reg(REG_PART_ID, &part_id);
if (ret != E_NO_ERROR)
{
printf("I2C read failed\n");
return ret;
}
if (part_id != 0x15)
{
printf("MAX30102 not found! Part ID: 0x%02X\n", part_id);
return -1;
}
printf("MAX30102 detected, Part ID: 0x%02X\n", part_id);
max30102_write_reg(REG_MODE_CONFIG, 0x40);
MXC_Delay(MXC_DELAY_MSEC(10));
max30102_write_reg(REG_MODE_CONFIG, 0x03); // SpO2 模式
max30102_write_reg(REG_SPO2_CONFIG, 0x27); // 18-bit, 100Hz
max30102_write_reg(REG_LED1_PA, 0x24); // 红光 ~7mA
max30102_write_reg(REG_LED2_PA, 0x24); // IR ~7mA
return 0;
}
// ---------------- 读取 FIFO 数据 ----------------
int max30102_read_fifo(uint32_t *red, uint32_t *ir)
{
uint8_t buf[6];
int ret = max30102_read_multi(REG_FIFO_DATA, buf, 6);
if (ret != E_NO_ERROR)
return ret;
*red = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2];
*ir = ((uint32_t)buf[3] << 16) | ((uint32_t)buf[4] << 8) | buf[5];
*red &= 0x3FFFF; // 18-bit
*ir &= 0x3FFFF;
return 0;
}最后再处理一下显示
if (hr_valid && heart_rate > 40 && heart_rate < 180)
{
printf("Heart Rate = %d BPM, ", heart_rate);
SSD1306_Print(0, 0, "Let's Do EEPW");
SSD1306_Print(0, 2, "HR:");
SSD1306_Print(30, 2, " ");
SSD1306_PrintInt(30, 2, heart_rate);
SSD1306_Print(80, 2, "BPM");
}
else
{
printf("Heart Rate = --- , ");
SSD1306_Print(0, 0, "Let's Do EEPW");
SSD1306_Print(0, 2, "HR: ---");
SSD1306_Print(80, 2, "BPM");
}
// 打印血氧
if (spo2_valid && spo2 > 70 && spo2 <= 100)
{
printf("SpO2 = %d%%\n", spo2);
SSD1306_Print(0, 4, "SpO2:");
SSD1306_Print(40,4, " ");
SSD1306_PrintInt(40, 4, spo2);
SSD1306_Print(80, 4, "%");
}
else
{
printf("SpO2 = ---\n");
SSD1306_Print(0, 4, "SpO2: ---");
SSD1306_Print(80, 4, "%");
}演示视频:
总结:
通过本次项目,学习了ADI的单片机,包括环境搭建,外设使用,也学习了I2C复用,很感谢EEPW提供的学习机会,官方老师的教程也很详细,再次感谢老师的付出。
项目代码:
我要赚赏金
