一、 前言
在上一篇评测中,我们体验了 ST NUCLEO-U385RG 的基础开发流程。既然这是一颗搭载了 Arm Cortex-M33 内核、主频高达 160MHz 的高性能低功耗 MCU,只用来点灯未免太大材小用了。
本次评测中,我将会用我们上一次调试好的I2C连接MAX30102 心率模块,通过STM32U385强大的能力,实现HRV(心率变异性)压力分析。这也就是说,首先在MCU内实现简单的IIR数字滤波,清洗PPG信号,再利用FPU实时计算SDNN指标,量化“压力/放松”状态。然后我们同样通过I2C连接一块SSD1306驱动的OLED屏,实现“心电扫描”与“大字数据”的双模式无缝切换。
二、 处理原始数据
MAX30102 输出的原始 PPG 信号通常包含极大的直流偏置(DC Offset)和高频噪声(环境光、手指微颤)。如果直接绘图,波形会满屏乱飘且全是锯齿。所以为了解决问题,我们需要对信号进行一定的处理。
得益于STM32U385标配了FPU,在代码中,我们只需给常数加上f后缀(如 0.95f),编译器就会直接调用Cortex-M33的硬件指令,将原本耗时几十个周期的运算压缩到 1-2 个周期 完成。
我采用了一个二阶级联的 IIR 滤波器方案:
float PPG_Signal_Process(uint32_t input) {
// 利用 FPU 进行浮点乘加运算,效率极高
// 高通去直流
v_dc = 0.95f * v_dc + 0.05f * (float)input;
float ac = (float)input - v_dc;
// 低通滤波
v_filtered = 0.85f * v_filtered + 0.15f * ac;
return v_filtered;
}
三、 HRV 压力分析
心率(BPM)只能反映跳得有多快,而HRV(心率变异性) 才能揭示当下的精神状态。HRV的计算方式是计算相邻两次心跳间隔的标准差,这就要求我们频繁进行平方、求和和开方等复杂运算,借助STM32U385的算力,我们可以在每次心跳间隙实时完成计算,无需由上位机处理。
void Calculate_HRV(float new_rr_interval) {
// 存入环形缓冲区
rr_intervals[rr_index] = new_rr_interval;
rr_index++;
if (rr_index >= RR_BUF_SIZE) {
rr_index = 0;
rr_filled = 1; // 标记已填满
}
if (rr_filled == 0) return;
// 计算均值
float sum = 0.0f;
for (int i = 0; i < RR_BUF_SIZE; i++) {
sum += rr_intervals[i];
}
float mean = sum / (float)RR_BUF_SIZE;
// 计算方差
float sum_squared_diff = 0.0f;
for (int i = 0; i < RR_BUF_SIZE; i++) {
float diff = rr_intervals[i] - mean;
sum_squared_diff += (diff * diff);
}
// 计算标准差
current_hrv = sqrtf(sum_squared_diff / (float)RR_BUF_SIZE);
}
四、 其它软件架构
在开发过程中通过示波器观察发现:如果简单地在 while(1) 里跑循环,当切换到不刷新屏幕的模式时,循环频率会飙升到数千赫兹,导致滤波器参数失效,数据失真。所以我们强制核心算法每20ms运行一次。同时,利用板载 User Button实现波形模式和大字模式的切换。
五、 效果展示与总结
将代码烧录进 NUCLEO-U385RG 后,系统的响应速度非常灵敏,完全感受不到复杂浮点运算带来的延迟。
图1 波形模式
图2 大字模式
通过这个项目,我对ST NUCLEO-U385RG的性能有了更深层次的理解,它具有160MHz主频和FPU,非常适合用来边缘计算,实现一些信号的DSP处理,同时配合HAL库和CubeMX,我们可以专注于算法逻辑,而无需在底层寄存器配置上浪费过多时间。

