MAX30102 Pulse Oximeter with an ESP32 DevKit V1

A pulse oximeter and heart-rate sensor: red and infrared LEDs, a photodetector and an 18-bit ADC behind one window, read over I2C.

MAX30102 Pulse Oximeter, A pulse oximeter and heart-rate sensor: red and infrared LEDs, a photodetector and an 18-bit ADC behind one window, read over I2C.
In short

The MAX30102 module takes the ESP32 DevKit V1's 3V3 on VIN and talks I2C on GPIO21 (SDA) and GPIO22 (SCL) at 400 kHz, which the sketch asks with I2C_SPEED_FAST. Its address is 0x57.

Wiring the MAX30102 Pulse Oximeter to the ESP32 DevKit V1

Pin by pin.

MAX30102 Pulse OximeterESP32 DevKit V1
VIN3V3
GNDGND
SDAGPIO21 (D21)
SCLGPIO22 (D22)

What to know on the ESP32 DevKit V1

  • The chip's I2C runs up to 400 kHz, and the ESP32's I2C controllers support fast mode at 400 kbit/s, so the sketch's I2C_SPEED_FAST works on GPIO21 and GPIO22 without changes.Maxim MAX30102 datasheet 19-7740 Rev 1, p. 5; Espressif ESP32 Series Datasheet v5.3, p. 37
  • Do not add a ZS-042 DS3231 module to the same ESP32 bus without care: its AT24C32 EEPROM also answers at 0x57. Put one of them on the ESP32's second I2C controller.Maxim MAX30102 datasheet 19-7740 Rev 1, p. 5; Espressif ESP32 Series Datasheet v5.3, p. 4
  • The chip's FIFO holds 32 samples. If Wi-Fi or other work keeps the ESP32 busy, read the FIFO often enough at your sample rate or samples are lost, and the beat detection misses beats.Maxim MAX30102 datasheet 19-7740 Rev 1, p. 14

MAX30102 Pulse Oximeter code for the ESP32 DevKit V1

Compiled for esp32:esp32:esp32 on 2026-10-30.

Libraries: sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library
// MAX30102 Pulse Oximeter on ESP32 DevKit V1: wiring and a free simulation at https://www.tinkered.ai/components/max30102/esp32
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"

MAX30105 sensor;
const byte RATE_SIZE = 4;
byte rates[RATE_SIZE];
byte rateSpot = 0;
long lastBeat = 0;
float beatsPerMinute = 0;
int beatAvg = 0;

void setup() {
  Serial.begin(115200);
  if (!sensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("MAX30102 not found");
    while (1) delay(10);
  }
  sensor.setup();                     // 6.4 mA LEDs, 4 averaged at 400 sps, 411 us, 4096 nA
  sensor.setPulseAmplitudeRed(0x0A);  // red dimmed: heart rate uses the IR channel
  sensor.setPulseAmplitudeGreen(0);
}

void loop() {
  long ir = sensor.getIR();
  if (checkForBeat(ir)) {
    long delta = millis() - lastBeat;
    lastBeat = millis();
    beatsPerMinute = 60 / (delta / 1000.0);
    if (beatsPerMinute < 255 && beatsPerMinute > 20) {
      rates[rateSpot++] = (byte)beatsPerMinute;
      rateSpot %= RATE_SIZE;
      beatAvg = 0;
      for (byte x = 0; x < RATE_SIZE; x++) beatAvg += rates[x];
      beatAvg /= RATE_SIZE;
    }
  }
  Serial.print("IR=");
  Serial.print(ir);
  Serial.print(" BPM=");
  Serial.print(beatsPerMinute);
  Serial.print(" Avg=");
  Serial.print(beatAvg);
  if (ir < 50000) Serial.print(" (no finger)");
  Serial.println();
}

MAX30102 Pulse Oximeter on the ESP32 DevKit V1: questions

Can I use the MAX30102 with the ESP32 at 3.3 V?

Yes. The module's VIN takes the board's 3V3 or 5 V, and the page uses 3V3. Its I2C lines then idle at a level the ESP32 reads safely.

Why does the MAX30100 library not find my sensor on the ESP32?

It is written for another chip with other registers. Use the SparkFun MAX3010x library, which drives the MAX30102 (part ID 0x15, Maxim datasheet, p. 11).

Keep going

For AI assistants

This guide as plain Markdown. /components/max30102/esp32.md

What will you build with it?