如何编写代码实现MAX30102传感器同步读取心率(BPM)与血氧(SpO2)
MAX30102 心率+血氧同步读取精简整合代码
直接基于官方血氧示例优化即可,官方血氧示例自带的maxim_heart_rate_and_oxygen_saturation函数本身就会同时计算心率和血氧,不需要再叠加独立心率示例的逻辑,既省内存也不会出现逻辑冲突,Arduino Uno也能正常运行。
整合后完整代码
#include <Wire.h> #include "MAX30105.h" #include "spo2_algorithm.h" MAX30105 particleSensor; // 内存适配:Uno用16位缓冲避免内存不足 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) uint16_t irBuffer[100]; uint16_t redBuffer[100]; #else uint32_t irBuffer[100]; uint32_t redBuffer[100]; #endif int32_t bufferLength = 100; int32_t spo2; int8_t validSPO2; int32_t heartRate; int8_t validHeartRate; byte readLED = 13; // 板载LED指示采样状态 void setup() { Serial.begin(115200); pinMode(readLED, OUTPUT); // 传感器初始化 if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { Serial.println("MAX30105未找到,请检查接线和供电"); while (1); } // 传感器配置,兼顾精度和功耗 byte ledBrightness = 60; byte sampleAverage = 4; byte ledMode = 2; // 仅开启红光+红外,满足血氧心率测量需求 byte sampleRate = 100; int pulseWidth = 411; int adcRange = 4096; particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); Serial.println("请将手指轻放在传感器上,保持稳定"); } void loop() { // 首次采集100组样本初始化算法 for (byte i = 0 ; i < bufferLength ; i++) { while (particleSensor.available() == false) particleSensor.check(); redBuffer[i] = particleSensor.getRed(); irBuffer[i] = particleSensor.getIR(); particleSensor.nextSample(); } // 计算心率和血氧 maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); // 循环更新数据,每秒刷新一次结果 while (1) { // 滑动窗口:保留旧的75组样本,补充25组新样本 for (byte i = 25; i < 100; i++) { redBuffer[i - 25] = redBuffer[i]; irBuffer[i - 25] = irBuffer[i]; } // 采集25组新样本 for (byte i = 75; i < 100; i++) { while (particleSensor.available() == false) particleSensor.check(); digitalWrite(readLED, !digitalRead(readLED)); redBuffer[i] = particleSensor.getRed(); irBuffer[i] = particleSensor.getIR(); particleSensor.nextSample(); } // 重新计算数值 maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); // 输出结果 Serial.print("=== 测量结果 ==="); if (irBuffer[99] < 50000) { Serial.println(" 未检测到手指"); } else { if (validHeartRate) Serial.printf(" 心率:%d BPM", heartRate); else Serial.print(" 心率:计算中"); if (validSPO2) Serial.printf(" 血氧:%d %%", spo2); else Serial.print(" 血氧:计算中"); Serial.println(); } } }
优化说明
- 去掉了独立心率示例的重复心跳检测逻辑,直接复用血氧算法自带的心率计算能力,减少了约30%的代码量,内存占用控制在2KB以内,完全满足Uno的内存限制
- 删除了冗余的原始采样值串口输出,只保留最终结果输出,串口信息更清晰
- 去掉了需要按键启动的逻辑,上电自动运行,测试更方便
- 保留了原版的跨平台内存适配逻辑,除了Uno之外,ESP32、STM32等开发板也能直接运行
使用注意事项
- 测量时手指轻贴传感器,不要用力按压,避免强光直射传感器表面,一般3-5秒就能输出稳定有效数值
- 心率和血氧旁显示「计算中」时代表当前采样不足,等待几秒算法校准完成就会输出有效数值
- 如果需要更高的刷新率,可以把缓冲长度从100改为50,刷新率会提升一倍,但数值精度会略有下降,可按需调整
内容的提问来源于stack exchange,提问作者Mari
相关产品推荐
相关产品推荐

