Funpack第六期-MAX32660-EVSYS评估板
利用 MAX32660 + MAX30102 + OLED12864 完成了心率测量显示的任务。
硬件资料
MAX32660-EVSYS评估板
评估板最核心的是MAX32660微控制器,属于美信DARWIN产品系列,是一款超低功耗、性价比突出、集成度非常高的32位控制器。
MAX30102
用于可穿戴健康设备的高灵敏度脉搏血氧仪和心率传感器
主要特征
- LED反射方案中提供心率监测仪和脉搏血氧仪生物传感器(光电容积法)
- 微小、5.6mm x 3.3mm x 1.55mm、14引脚光模块
- 集成玻璃盖,实现最优、可靠的性能
- 使移动设备以极低功耗工作
- 可编程采样率和LED电流,节省功耗
- 低功耗心率监测仪(< 1mW)
- 超低关断电流(0.7µA,典型值)
- 快速数据输出
- 高采样率
- 可靠的运动伪影抑制
- 高SNR
- -40°C至+85°C工作温度范围
应用/用途
- 辅助健身设备
- 智能电话
- 平板电脑
- 可穿戴设备
SSD1306 OLED 12864
OLED 屏幕作为一种新型的显示技术,其自身可以发光,亮度,对比度高,功耗低,在当下备受追捧。
该屏幕有 I2C 和 SPI 两种接口,这里使用 SPI 接口,并且使用了 u8g2 软件包。
软件
RT-Thread
MAX32660 目前已经移植到了 RT-Thread 上,我基于 RT-Thread 的 I2C 框架来控制 MAX30102,SPI 框架来控制 ssd1306 显示屏。
心率算法
我移植了 Arduino 里的 MAX30102 软件包,对接了其用 I2C 读写寄存器的接口。
static rt_bool_t maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data)
{
uint8_t buf[2];
struct rt_i2c_msg msg;
rt_size_t err;
buf[0] = uch_addr;
buf[1] = uch_data;
msg.addr = MAX30102_ADDR;
msg.flags = RT_I2C_WR;
msg.buf = buf;
msg.len = ARRAY_SIZE(buf);
if ((err = rt_i2c_transfer(i2c_bus, &msg, 1)) != 1)
{
LOG_E("I2c write failed (err: %d).", err);
return RT_FALSE;
}
return RT_TRUE;
}
static rt_bool_t maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *data, uint16_t len)
{
RT_ASSERT(data);
struct rt_i2c_msg msg_buf[2];
rt_size_t err;
msg_buf[0].addr = MAX30102_ADDR;
msg_buf[0].flags = RT_I2C_WR;
msg_buf[0].buf = &uch_addr;
msg_buf[0].len = 1;
msg_buf[1].addr = MAX30102_ADDR;
msg_buf[1].flags = RT_I2C_RD;
msg_buf[1].buf = data;
msg_buf[1].len = len;
if ((err = rt_i2c_transfer(i2c_bus, msg_buf, 2)) != 2)
{
LOG_E("I2c read failed (err: %d).", err);
return RT_FALSE;
}
return RT_TRUE;
}
然后从 MAX30102 里读出来的数据是红光强度的 AD 值,我们利用这个 AD 值进行算法处理,得到我们最终的心率值。
心率算法采用的是前项差分和动态阈值的方法,该心率算法的详细描述可参考:Maxim设计指南 | 基于前项差分和动态阈值的PPG心率测量算法。
这里列出一张我当时数据处理之后的图片,这里每一个波谷就代表一次心脏跳动。
心率算法实现不算复杂,而且我已经做了一个 sensor 软件包贡献给 RT-Thread 了,内部集成了心率算法,直接使用就行,代码仓库为:https://github.com/Jackistang/max30102_rtt。
RTC
我使用 RT-Thread 的软件 RTC 实现了时钟计数,在程序运行前设置系统时间,这里只是设置了一个初始值。
set_date(2021, 3, 21);
set_time(18, 20, 00);
然后再需要显示时钟字符串的时候,调用接口 `daytime()` 即可得到字符串。
#define DAYTIME_LEN 10
/**
* @brief Get the format time Hour:Min:Sec from time_t.
* @param time A pointer to timer_t.
* @return Hour:Min:Sec format time string.
*/
char *daytime(time_t *time)
{
static char buf[DAYTIME_LEN];
int blank = 0, i = 0;
char *t = ctime(time);
while (*t != '\0' && i < DAYTIME_LEN) {
if (*t == ' ')
blank++;
if (blank == 3) {
buf[i++] = *t;
}
t++;
}
return buf;
}
now = time(NULL);
u8g2.setFont(u8g2_font_6x12_tf);
u8g2.drawStr(10, 10, daytime(&now));
u8g2.sendBuffer();
心得体会
十分感谢 Funpack 活动,感谢硬禾学堂和 Digi-Key ,我通过这期任务接触到了美信 MAX32660 这款优秀的开发板,也成功地挑战自己,利用 MAX30102 完成了心率测量的功能,收获颇多,十分感谢。
项目源代码太大,不能上传网址,所以放到网盘里了。
链接:https://pan.baidu.com/s/1wt0nK14F-82BPKIwrFFREA
提取码:5jhe
复制这段内容后打开百度网盘手机App,操作更方便哦