Overview
The MAX30102 is an integrated pulse oximetry and heart rate sensor module that communicates over I2C. It contains red and infrared LEDs along with a photodetector to measure blood oxygen saturation (SpO2) and heart rate through your fingertip. The module runs on 1.8V-5V and works with Arduino, Raspberry Pi, ESP32, and Pico — making it a go-to choice for wearable health monitors, fitness trackers, and biomedical prototyping projects.
This pre-soldered breakout board includes onboard voltage regulators and pull-up resistors, so you can connect it directly to your microcontroller’s I2C bus with just four wires. The MAX30102 uses an 18-bit ADC for high-resolution readings and draws under 600 uA during active measurement, dropping to just 0.7 uA in standby mode.
At a Glance
Specifications
| Parameter | Value |
| Operating Voltage (Module) | 1.8V - 5V (onboard regulators) |
| IC Supply Voltage | 1.8V |
| LED Supply Voltage | 3.3V |
| Active Current | < 600 uA |
| Standby Current | 0.7 uA |
| Red LED Wavelength | 660 nm |
| IR LED Wavelength | 880 nm |
| ADC Resolution | 18-bit |
| Sample Rate | 50 - 3200 samples/sec |
| Communication | I2C (address 0x57) |
| I2C Speed | Up to 400 kHz |
| Operating Temperature | -40 to +85 C |
| Dimensions (Module) | 18 x 13 mm |
Pinout Diagram
The MAX30102 module has 8 pins across two rows. Bottom row (pins 1-4): GND, SCL, SDA, VIN — these are the four pins you connect to your microcontroller. Top row (pins 5-8): INT (interrupt output, active-low, optional), IRD (IR LED cathode driver), RD (Red LED cathode driver), GND. The IRD and RD pins are used internally by the module’s LED drivers — you do not need to connect them for normal operation.
Wiring Guide
Arduino Wiring
The MAX30102 module has onboard voltage regulators, so it can be powered from the Arduino 5V or 3.3V pin. Connect it to the Arduino’s hardware I2C pins (A4/A5 on the Uno). The INT pin is optional but useful for interrupt-driven reading.
| MAX30102 Pin | Arduino Pin |
|---|---|
| VIN | 3.3V or 5V |
| GND | GND |
| SCL | A5 (SCL) |
| SDA | A4 (SDA) |
| INT | Digital Pin 2 (optional) |
ESP32 Wiring
The ESP32 uses 3.3V I2C logic, which is compatible with the MAX30102 module. The default I2C pins on the ESP32 are GPIO 21 (SDA) and GPIO 22 (SCL). Power the module from the ESP32’s 3.3V pin.
| MAX30102 Pin | ESP32 Pin |
|---|---|
| VIN | 3.3V |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
| INT | GPIO 19 (optional) |
Raspberry Pi Wiring
The Raspberry Pi has dedicated I2C pins on GPIO 2 (SDA) and GPIO 3 (SCL). The MAX30102 module can be powered from the Pi’s 3.3V pin. Make sure I2C is enabled in raspi-config before using the sensor.
| MAX30102 Pin | Raspberry Pi Pin |
|---|---|
| VIN | Pin 1 (3.3V) |
| GND | Pin 6 (GND) |
| SCL | Pin 5 (GPIO 3 / SCL) |
| SDA | Pin 3 (GPIO 2 / SDA) |
| INT | Pin 7 (GPIO 4) (optional) |
sudo raspi-config, go to Interface Options, and enable I2C. Then reboot. You can verify the sensor is detected by running sudo i2cdetect -y 1 — you should see address 0x57.
Raspberry Pi Pico Wiring
The Pico has two I2C buses. We’ll use I2C bus 0 on GP0 (SDA) and GP1 (SCL). The MAX30102 module can be powered from the Pico’s 3V3 pin.
| MAX30102 Pin | Pico Pin |
|---|---|
| VIN | 3V3 (Pin 36) |
| GND | GND |
| SCL | GP1 (Pin 2) |
| SDA | GP0 (Pin 1) |
| INT | GP2 (Pin 4) (optional) |
Code Examples
Arduino
// MAX30102 Heart Rate Sensor - Arduino Example
// Uses the SparkFun MAX3010x library
// Install: Arduino Library Manager -> search "SparkFun MAX3010x"
// I2C Pins: A4 (SDA), A5 (SCL)
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"
MAX30105 particleSensor;
const byte RATE_SIZE = 4;
byte rates[RATE_SIZE];
byte rateSpot = 0;
long lastBeat = 0;
float beatsPerMinute;
int beatAvg;
void setup() {
Serial.begin(9600);
Serial.println("MAX30102 Heart Rate Sensor");
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("MAX30102 not found. Check wiring.");
while (1);
}
Serial.println("Place your finger on the sensor.");
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A);
particleSensor.setPulseAmplitudeGreen(0);
}
void loop() {
long irValue = particleSensor.getIR();
if (checkForBeat(irValue) == true) {
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
// Calculate average BPM
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
Serial.print("IR=");
Serial.print(irValue);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.println(beatAvg);
if (irValue < 50000)
Serial.println("No finger detected");
}
Raspberry Pi (Python)
#!/usr/bin/env python3
# MAX30102 Heart Rate Sensor - Raspberry Pi Example
# Install: pip3 install max30102 smbus2
# I2C Pins: GPIO 2 (SDA), GPIO 3 (SCL)
# Enable I2C first: sudo raspi-config -> Interface Options -> I2C
from max30102 import MAX30102
import time
# Initialize the sensor on I2C bus 1
sensor = MAX30102(bus=1)
# Check if sensor is connected
if not sensor.check():
print("MAX30102 not found. Check wiring.")
exit(1)
print("MAX30102 Heart Rate Sensor")
print("Place your finger on the sensor...")
print("Press Ctrl+C to stop")
try:
while True:
# Read a batch of samples from the sensor
red, ir = sensor.read_sequential()
if len(ir) > 0:
# Calculate average IR value (used for finger detection)
avg_ir = sum(ir) / len(ir)
if avg_ir < 50000:
print("No finger detected")
else:
print("IR: {:.0f}, Red: {:.0f}".format(
sum(ir) / len(ir),
sum(red) / len(red)
))
time.sleep(0.1)
except KeyboardInterrupt:
print("\nMeasurement stopped by user")
finally:
sensor.shutdown()
Raspberry Pi Pico (MicroPython)
# MAX30102 Heart Rate Sensor - Pico MicroPython Example
# Install library: import mip; mip.install("github:n-undertaker/micropython-max30102")
# I2C Pins: GP0 (SDA), GP1 (SCL)
from machine import Pin, I2C, SoftI2C
from max30102 import MAX30102
import time
# Initialize I2C bus
i2c = SoftI2C(sda=Pin(0), scl=Pin(1), freq=400000)
# Scan for devices to verify connection
devices = i2c.scan()
print("I2C devices found:", [hex(d) for d in devices])
# Initialize the MAX30102 sensor
sensor = MAX30102(i2c=i2c)
# Check sensor is responding
if sensor.i2c_address not in devices:
print("MAX30102 not found. Check wiring.")
raise SystemExit
# Configure the sensor
sensor.setup_sensor()
print("MAX30102 Heart Rate Sensor")
print("Place your finger on the sensor...")
while True:
# Check if new data is available
sensor.check()
if sensor.available():
# Read red and IR values
red = sensor.pop_red_from_storage()
ir = sensor.pop_ir_from_storage()
if ir < 50000:
print("No finger detected")
else:
print("IR: {}, Red: {}".format(ir, red))
time.sleep_ms(10)
ESP32 (MicroPython)
# MAX30102 Heart Rate Sensor - ESP32 MicroPython Example
# Install library: import mip; mip.install("github:n-undertaker/micropython-max30102")
# I2C Pins: GPIO 21 (SDA), GPIO 22 (SCL)
from machine import Pin, SoftI2C
from max30102 import MAX30102
import time
# Initialize I2C bus (ESP32 default I2C pins)
i2c = SoftI2C(sda=Pin(21), scl=Pin(22), freq=400000)
# Scan for devices
devices = i2c.scan()
print("I2C devices found:", [hex(d) for d in devices])
# Initialize the MAX30102 sensor
sensor = MAX30102(i2c=i2c)
if sensor.i2c_address not in devices:
print("MAX30102 not found. Check wiring.")
raise SystemExit
# Configure the sensor
sensor.setup_sensor()
print("MAX30102 Heart Rate Sensor")
print("Place your finger on the sensor...")
while True:
sensor.check()
if sensor.available():
red = sensor.pop_red_from_storage()
ir = sensor.pop_ir_from_storage()
if ir < 50000:
print("No finger detected")
else:
print("IR: {}, Red: {}".format(ir, red))
time.sleep_ms(10)