Monitorización Precisa de Frecuencia Cardíaca y SpO₂ con Oxímetro MAX30102 en Arduino
Componentes y Suministros
| Arduino UNO | × | 1 |
| Pantalla OLED 128x32 (Adafruit) | × | 1 |
| Zumbador (Buzzer) | × | 1 |
| MAX30102 Oxímetro de Pulso y Sensor Frecuencia Cardíaca Alta Sensibilidad (Maxim Integrated) | × | 1 |
Sobre el Proyecto
Introducción
Hola, en este tutorial interconectaremos el MAX30102: módulo de oximetría de pulso y monitor de frecuencia cardíaca con placa Arduino UNO, y luego haremos un proyecto para medir BPM usando este módulo + pantalla OLED y un zumbador.
Los BPM son "latidos por minuto" y en reposo suelen ser 65–75 en persona normal, los atletas pueden tener menos. El SpO₂ es el nivel de saturación de oxígeno, y en persona normal está por encima del 95 %.
El MAX30102 se encuentra en distintos módulos; yo tengo versión WAVGAT, no hay problema mientras el IC sea MAX30102.
Componentes
Aquí lo que voy a usar:




Pruebas
Los códigos usados en el tutorial son claros y son solo ejemplos de la librería SparkFun_MAX3010x.
Para el código que hice para OLED y Buzzer, es una versión modificada del ejemplo "HeartRate", que pide poner el dedo en el sensor.

Una vez pones el dedo, mantente tranquilo un rato hasta que empieces a oír los "Bips" del zumbador sincronizados con tus latidos o la animación en el OLED se sincronice, y entonces podrás leer un BPM correcto.
Nota: En el código imprimo el BPM Promedio, ya que promedia 4 BPMs es más preciso; dale un tiempo.

Crear Mapas de Bits (Bitmaps) para el OLED
El corazón (pequeño) que se ve es una imagen bitmap; cada vez que el sensor detecta un latido cambiamos a otro corazón (grande) bitmap por un momento, dando la impresión de un latido junto con el bip del zumbador.
Aquí están los dos bitmaps en el código que llamamos luego:

Para crearlos: busque una imagen (negro con fondo blanco) de lo que quiera ver en pantalla, cuidando el tamaño. Mi pantalla es 128x32 px y las imágenes son menores (32x32 px y 24x21 px).

Descargue LCD Assistant y ábralo (pasos abajo):





Y aquí tiene sus "números" (array de bytes):

Así los llamé en el código:
display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE);
Significa:
display.drawBitmap(Pos x inicial, Pos y inicial, Nombre bitmap, Ancho, Alto, Color);
En el código uno se llama cuando se detecta dedo y el otro cuando se detecta latido.
¡Ya puede hacer lo que quiera!
Código
- MAX_BPM_OLED_Buzzer.ino
MAX_BPM_OLED_Buzzer.ino Arduino
Modificado desde la librería SparkFun MAX3010x
/* Este código funciona con MAX30102 + OLED 128x32 i2c + Buzzer y Arduino UNO
* Muestra el BPM Promedio en pantalla, con animación y sonido buzzer
* cada vez que se detecta un pulso cardíaco
* Versión modificada del ejemplo HeartRate de la librería
* Consulte www.surtrtech.com para más detalles o canal SurtrTech YouTube */
#include <Adafruit_GFX.h> // Librerías OLED
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include "MAX30105.h" // Librería MAX3010x
#include "heartRate.h" // Algoritmo cálculo frecuencia cardíaca
MAX30105 particleSensor;
const byte RATE_SIZE = 4; // Aumente para más promediado. 4 está bien.
byte rates[RATE_SIZE]; // Array de frecuencias cardíacas
byte rateSpot = 0;
long lastBeat = 0; // Tiempo del último latido
float beatsPerMinute;
int beatAvg;
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Bitmap corazón pequeño (24x21)
static const unsigned char PROGMEM logo2_bmp[] = {
0x03, 0xC0, 0xF0, 0x06, 0x71, 0x8C, 0x0C, 0x1B, 0x06, 0x18, 0x0E, 0x02,
0x10, 0x0C, 0x03, 0x10, 0x04, 0x01, 0x10, 0x04, 0x01, 0x10, 0x40, 0x01,
0x10, 0x40, 0x01, 0x10, 0xC0, 0x03, 0x08, 0x88, 0x02, 0x08, 0xB8, 0x04,
0xFF, 0x37, 0x08, 0x01, 0x30, 0x18, 0x01, 0x90, 0x30, 0x00, 0xC0, 0x60,
0x00, 0x60, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x0E, 0x00,
0x00, 0x04, 0x00
};
// Bitmap corazón grande (32x32)
static const unsigned char PROGMEM logo3_bmp[] = {
0x01, 0xF0, 0x0F, 0x80, 0x06, 0x1C, 0x38, 0x60, 0x18, 0x06, 0x60, 0x18,
0x10, 0x01, 0x80, 0x08, 0x20, 0x01, 0x80, 0x04, 0x40, 0x00, 0x00, 0x02,
0x40, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x01,
0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1C, 0x01, 0x80, 0x00, 0x14, 0x00,
0x80, 0x00, 0x14, 0x00, 0x80, 0x00, 0x14, 0x00, 0x40, 0x10, 0x12, 0x00,
0x40, 0x10, 0x12, 0x00, 0x7E, 0x1F, 0x23, 0xFE, 0x03, 0x31, 0xA0, 0x04,
0x01, 0xA0, 0xA0, 0x0C, 0x00, 0xA0, 0xA0, 0x08, 0x00, 0x60, 0xE0, 0x10,
0x00, 0x20, 0x60, 0x20, 0x06, 0x00, 0x40, 0x60, 0x03, 0x00, 0x40, 0xC0,
0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00,
0x00, 0x30, 0x0C, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00,
0x00, 0x03, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x00
};
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(3000);
// Inicializar sensor
particleSensor.begin(Wire, I2C_SPEED_FAST);
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A); // LED rojo bajo para indicar sensor activo
}
void loop() {
long irValue = particleSensor.getIR(); // Valor IR permite saber si hay dedo en sensor
// También detecta latido
if(irValue > 7000) { // Si se detecta dedo
display.clearDisplay();
display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE); // Dibuja corazón pequeño
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(50,0);
display.println("BPM");
display.setCursor(50,18);
display.println(beatAvg);
display.display();
if (checkForBeat(irValue) == true) { // Si se detecta latido
display.clearDisplay();
display.drawBitmap(0, 0, logo3_bmp, 32, 32, WHITE); // Dibuja corazón grande
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(50,0);
display.println("BPM");
display.setCursor(50,18);
display.println(beatAvg);
display.display();
tone(3,1000); // Suena buzzer 100 ms (reducir si quiere)
delay(100);
noTone(3); // Apaga buzzer para efecto "bip"
// Detectamos latido
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0); // Calcular BPM
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
// Promedio de lecturas
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++) beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
}
if (irValue < 7000) { // Si no hay dedo
beatAvg = 0; // Reset promedio o se guardaría para siguiente medida
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(30,5);
println("Por favor coloque ");
display.setCursor(30,15);
println("su dedo ");
display.display();
noTone(3);
}
}
Librería SparkFun MAX3010x
https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
Adafruit SSD1306
https://github.com/adafruit/Adafruit_SSD1306
Librería Adafruit GFX
https://github.com/adafruit/Adafruit-GFX-Library
Esquemas
Ambos módulos usan interfaz I²C. Si usa zumbador de 2 pines: (-) a GND y (+) con resistencia a D3.

Proceso de manufactura
- Sistema de control de acceso integrado con QR, RFID y verificación de temperatura
- Conectar múltiples sensores DS18B20 1‑Wire a Raspberry Pi para monitorización precisa de temperatura
- Construye un sistema aeropónico automatizado con Raspberry Pi y sensor de humedad
- Sistema de Monitorización Remota de Frecuencia Cardíaca con Alertas AWS IoT
- Construya un robot con Raspberry Pi y Python: Guía completa
- Integración de sensor termopar con Arduino Portenta H7 usando MAX6675
- Construye un Juego Giroscópico en Tiempo Real con Arduino Nano y Sensor MPU-6050
- Monitor de Frecuencia Cardíaca IoT en Tiempo Real con Arduino y MAX30100
- Construye un Monitor de Frecuencia Cardíaca Preciso con Fotoresistencia y Arduino
- Proyecto de electroplacado de cobre: Construye un sistema inteligente con Arduino UNO
- Maximice el espacio del taller con Visual Components, Matterport y automatización ProFeeder X