Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Sensors & Modules

MAX30102 Pulse Oximeter: SpO2 and Heart Rate Arduino

MAX30102 Pulse Oximeter: SpO2 and Heart Rate Arduino

March 11, 2026 /Posted byJayesh Jain / 0

Table of Contents

  • What Is the MAX30102 Sensor?
  • How Pulse Oximetry and SpO2 Measurement Work
  • MAX30102 Module Pinout and Specifications
  • Wiring MAX30102 to Arduino via I2C
  • Library Setup and Installation
  • Basic Heart Rate Sketch
  • Full SpO2 + Heart Rate Project
  • Adding an OLED Display
  • Calibration and Accuracy Considerations
  • Low-Power Mode for Battery Projects
  • Troubleshooting Common Issues
  • Frequently Asked Questions

Wearable health monitoring was once the exclusive domain of medical-grade equipment costing thousands of rupees. The MAX30102 pulse oximeter and heart rate sensor has changed that completely. For under ₹200, you get a fully integrated optical biosensor that can measure both blood oxygen saturation (SpO2) and heart rate — and connect it directly to an Arduino in minutes.

This tutorial covers everything from the physics of pulse oximetry to a complete working Arduino project that displays SpO2 percentage and BPM on an OLED screen. Whether you are building a fitness band prototype, a patient monitoring POC, or simply exploring biosensors, this guide has you covered.

What Is the MAX30102 Sensor?

The MAX30102 is a highly integrated biosensor IC from Maxim Integrated (now part of Analog Devices). It combines two LEDs (red at 660 nm and infrared at 880 nm), a photodetector, optical elements, and low-noise analog signal processing in a single tiny 5.6 mm × 3.3 mm surface-mount package.

The IC is specifically designed for reflective photoplethysmography (PPG) — measuring the tiny changes in light absorption caused by pulsing blood flow through the skin. By analysing these light fluctuations, it calculates both:

  • Heart rate (BPM): The frequency of the pulse waveform directly corresponds to heartbeats per minute
  • SpO2 (blood oxygen saturation): Oxygenated and deoxygenated haemoglobin absorb red and infrared light differently; the ratio of these absorptions reveals oxygen saturation percentage

The MAX30102 communicates via I2C at a fixed address of 0x57, making it one of the easiest biosensors to interface with any microcontroller that has I2C support — which includes virtually every Arduino, ESP8266, ESP32, STM32, and Raspberry Pi.

How Pulse Oximetry and SpO2 Measurement Work

Understanding the physics here helps you get better readings and troubleshoot problems effectively.

Photoplethysmography (PPG): Blood absorbs light. When the heart beats, it forces a pulse of blood through the capillaries in your fingertip. This pulse briefly increases the total volume of blood in the tissue, which absorbs slightly more light. The MAX30102’s photodetector captures these tiny intensity variations in reflected light to construct the PPG waveform.

SpO2 calculation: Haemoglobin (Hb) and oxyhaemoglobin (HbO2) have different absorption spectra. Oxygenated haemoglobin absorbs more infrared light but less red light. Deoxygenated haemoglobin does the opposite. By measuring the AC/DC ratio of the red channel versus the infrared channel — a value called the ratio of ratios (R) — the sensor estimates SpO2 using a calibration equation:

SpO2 ≈ −45.060 × R² + 30.354 × R + 94.845

This empirical equation is derived from calibration against laboratory co-oximeters. It is accurate to within ±2% for SpO2 values between 70% and 100% under ideal conditions — comparable to consumer pulse oximeters.

Why finger placement matters: The PPG signal quality depends heavily on having a clean optical path. Motion artefacts, ambient light leakage, and insufficient pressure on the sensor all degrade the signal. The MAX30102 module typically has a small cavity where you rest your fingertip — ensure your finger covers the entire sensor area and remains still during measurement.

MAX30102 Module Pinout and Specifications

Most MAX30102 breakout modules expose 6–8 pins. The essential ones are:

Pin Description
VIN Power supply: 1.8 V – 5.5 V (module has onboard 1.8 V regulator)
GND Ground
SDA I2C data line
SCL I2C clock line
INT Interrupt output (active LOW) — fires when FIFO data is ready
RD Red LED current control (on some modules, connected to a header)

Key specifications:

  • Supply voltage: 1.8 V – 5.5 V (VIN; most modules have a built-in 3.3 V / 1.8 V LDO)
  • I2C address: 0x57 (fixed)
  • LED wavelengths: 660 nm (red), 880 nm (IR)
  • ADC resolution: 18-bit
  • Sample rates: 50 Hz to 3200 Hz configurable
  • FIFO depth: 32 samples
  • Shutdown current: 0.7 µA
  • Operating temperature: −40 °C to +85 °C

Wiring MAX30102 to Arduino via I2C

The MAX30102 uses I2C, so you only need 4 wires:

MAX30102 Pin Arduino Uno/Nano ESP8266 (NodeMCU) ESP32
VIN 5 V 3.3 V 3.3 V
GND GND GND GND
SDA A4 D2 (GPIO4) GPIO21
SCL A5 D1 (GPIO5) GPIO22

The INT pin is optional for basic projects — leave it unconnected if you plan to poll the sensor in your main loop. For interrupt-driven or low-power designs, connect INT to a GPIO configured as an external interrupt input.

Most MAX30102 modules include onboard 4.7 kΩ pull-up resistors on SDA and SCL. If your module does not, add them externally between each I2C line and VIN.

Library Setup and Installation

The best library for the MAX30102 on Arduino is the SparkFun MAX3010x Pulse and Proximity Sensor Library by SparkFun Electronics. It is well-maintained, includes heart rate and SpO2 algorithms, and works with Arduino, ESP8266, and ESP32.

Install it via the Arduino Library Manager:

  1. Open Arduino IDE → Sketch → Include Library → Manage Libraries
  2. Search for MAX3010x
  3. Install the library by SparkFun Electronics

Alternatively, install via PlatformIO:

lib_deps = sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library

The library includes several example sketches under File → Examples → SparkFun MAX3010x Pulse and Proximity Sensor Library. Start with the Example1_GettingStarted sketch to verify your wiring before writing custom code.

Basic Heart Rate Sketch

This minimal sketch uses the SparkFun library’s built-in beat detection algorithm to read heart rate from the IR channel:

#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(115200);
  Serial.println("MAX30102 Heart Rate Monitor");

  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("MAX30102 not found. Check wiring.");
    while (1);
  }

  particleSensor.setup();  // default settings
  particleSensor.setPulseAmplitudeRed(0x0A);   // low power indicator
  particleSensor.setPulseAmplitudeGreen(0);    // disable green LED
}

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;
      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, 1);
  Serial.print(" Avg BPM="); Serial.println(beatAvg);

  if (irValue < 50000) Serial.println(" -- No finger detected");
}

Open Serial Monitor at 115200 baud. Place your fingertip firmly over the sensor. You will see IR values jump above 50,000 when a finger is detected, followed by BPM readings that stabilise after 4–5 heartbeats (the moving average window size).

Full SpO2 + Heart Rate Project

For SpO2 measurement, the SparkFun library includes the spo2_algorithm which uses both red and IR channels. This more complex example averages samples over a 100-reading window for stable results:

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"

MAX30105 particleSensor;

#define MAX_BRIGHTNESS 255
#define BUFFER_LENGTH  100

uint32_t irBuffer[BUFFER_LENGTH];
uint32_t redBuffer[BUFFER_LENGTH];

int32_t  spo2;
int8_t   validSPO2;
int32_t  heartRate;
int8_t   validHeartRate;

void setup() {
  Serial.begin(115200);

  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("MAX30102 not found!");
    while (1);
  }

  // Configure sensor for SpO2 mode
  byte ledBrightness = 60;   // 0–255; higher = more IR/red light
  byte sampleAverage = 4;    // 1, 2, 4, 8, 16, 32
  byte ledMode       = 2;    // 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  byte sampleRate    = 100;  // samples/second: 50,100,200,400,800,1000,1600,3200
  int  pulseWidth    = 411;  // µs: 69, 118, 215, 411
  int  adcRange      = 4096; // 2048, 4096, 8192, 16384

  particleSensor.setup(ledBrightness, sampleAverage, ledMode,
                       sampleRate, pulseWidth, adcRange);
}

void loop() {
  // Fill first 100 samples
  for (byte i = 0; i < BUFFER_LENGTH; i++) {
    while (particleSensor.available() == false)
      particleSensor.check();

    redBuffer[i] = particleSensor.getRed();
    irBuffer[i]  = particleSensor.getIR();
    particleSensor.nextSample();
  }

  maxim_heart_rate_and_oxygen_saturation(irBuffer, BUFFER_LENGTH,
    redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  // Continuous rolling window: discard first 25, shift, refill
  while (1) {
    for (byte i = 25; i < BUFFER_LENGTH; i++) {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25]  = irBuffer[i];
    }
    for (byte i = 75; i < BUFFER_LENGTH; i++) {
      while (particleSensor.available() == false)
        particleSensor.check();
      redBuffer[i] = particleSensor.getRed();
      irBuffer[i]  = particleSensor.getIR();
      particleSensor.nextSample();
    }

    maxim_heart_rate_and_oxygen_saturation(irBuffer, BUFFER_LENGTH,
      redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

    Serial.print(F("HR=")); Serial.print(heartRate, DEC);
    Serial.print(F(" valid=")); Serial.print(validHeartRate, DEC);
    Serial.print(F(" SpO2=")); Serial.print(spo2, DEC);
    Serial.print(F(" valid=")); Serial.println(validSPO2, DEC);
  }
}

A validSPO2 value of 1 means the algorithm is confident in the reading. If it returns 0, the signal quality was insufficient — usually due to motion or poor finger placement. Never act on invalid readings.

BMP280 Barometric Pressure Sensor

BMP280 Barometric Pressure and Altitude Sensor

Pair with MAX30102 to build a complete health + environment monitor measuring SpO2, HR, altitude, and pressure.

View on Zbotic

Adding an OLED Display

A 0.96-inch SSD1306 I2C OLED display is the perfect companion for the MAX30102. Both use I2C, so you add only 2 more wires (SDA and SCL share the same bus).

OLED display wiring:

  • OLED VCC → Arduino 3.3 V (most SSD1306 modules accept 3.3 V – 5 V)
  • OLED GND → Arduino GND
  • OLED SDA → Arduino A4 (same as MAX30102 SDA)
  • OLED SCL → Arduino A5 (same as MAX30102 SCL)

The SSD1306 has I2C address 0x3C (or 0x3D on some variants), which is different from the MAX30102 at 0x57 — so both devices coexist on the same bus without any configuration changes.

Add the Adafruit SSD1306 and Adafruit GFX libraries via Library Manager. The display code to overlay heart rate and SpO2 on the OLED is straightforward:

display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print("HR: "); display.print(heartRate); display.println(" BPM");
display.setCursor(0, 24);
display.print("SpO2:"); display.print(spo2); display.println(" %");
display.display();

Calibration and Accuracy Considerations

The MAX30102 is a consumer-grade sensor, not a medical-grade device. Understanding its limitations is essential:

  • Accuracy range: The SparkFun spo2_algorithm is reliable for SpO2 values between 80–100%. Below 80% (clinical hypoxia range), the algorithm’s accuracy degrades significantly.
  • Motion artefacts: Even small finger movements cause large signal spikes. Always average readings over multiple samples (100+ preferred) and check the validity flag.
  • Ambient light: Strong ambient light (especially sunlight) leaks into the sensor cavity and corrupts readings. Shade the sensor or use a covered enclosure.
  • Skin tone variation: Some studies suggest pulse oximetry accuracy varies with darker skin tones. This is a known limitation of optical pulse oximetry in general.
  • LED current adjustment: The ledBrightness parameter (0–255) in the sensor setup controls LED power. Too low and the signal is weak; too high and the ADC saturates. For most adult fingertips, 60–80 is a good starting value.

For a classroom or prototyping demonstration, the MAX30102 with the SparkFun algorithm gives readings that are impressively close to clinical oximeters (±2–3% is typical). For any safety-critical application, use a certified medical device.

Low-Power Mode for Battery Projects

The MAX30102’s 0.7 µA shutdown current makes it excellent for battery-powered wearables. To shut down the sensor between readings:

// Enter shutdown mode
particleSensor.shutDown();

// ... MCU sleeps here for several seconds ...

// Wake up the sensor and restart
particleSensor.wakeUp();
particleSensor.setup(); // re-configure

With the sensor shut down and the MCU in deep sleep, a typical Arduino + MAX30102 system draws under 20 µA — enabling months of operation from a 500 mAh LiPo battery if readings are taken every 30 seconds.

LM35 Temperature Sensor

LM35 Temperature Sensor

Add body temperature measurement alongside SpO2 and heart rate for a more comprehensive health monitor.

View on Zbotic

Troubleshooting Common Issues

“MAX30102 not found” at startup:

  • Recheck SDA/SCL wiring — swapped lines are the most common issue
  • Run an I2C scanner sketch to verify the device appears at address 0x57
  • Ensure VIN has power: the onboard LED on most modules glows red when powered

IR value stays near zero, no reading:

  • Finger is not placed over the sensor window — the sensor has a small oval window, cover it completely
  • Too much ambient light — cup your hand over the sensor

SpO2 always reads -999 or 0:

  • The algorithm returns -999 when signal quality is insufficient — this is normal until a valid reading accumulates
  • Hold finger completely still for at least 10 seconds after placing it on the sensor
  • Try increasing LED brightness: change ledBrightness from 60 to 100 or 150

Readings are wildly inconsistent:

  • Apply gentle constant pressure — pressing too hard restricts blood flow, too lightly gives a weak signal
  • Ensure the I2C bus is not overloaded with other devices sharing the same pullup resistors
GY-BME280 Precision Altimeter

GY-BME280-3.3 Precision Altimeter Sensor

Measures barometric pressure, temperature, and humidity — complement your MAX30102 health station with environmental data.

View on Zbotic

Frequently Asked Questions

Is the MAX30102 medically accurate?

The MAX30102 with SparkFun’s algorithm typically achieves ±2–3% accuracy compared to clinical pulse oximeters under ideal conditions (still finger, good perfusion, normal skin tone). This is good enough for fitness and wellness projects, but the sensor is NOT FDA-cleared or CE-marked as a medical device. Do not use it for clinical diagnosis or to make health decisions.

What is the difference between MAX30100 and MAX30102?

The MAX30100 is the older version. The MAX30102 adds a green LED channel (for ECG-style applications), has improved SpO2 accuracy, wider supply voltage range (down to 1.8 V), and a larger FIFO buffer (32 samples vs 16). The MAX30102 is strictly better in every way and is now the recommended choice for new designs.

Can I use MAX30102 with ESP8266 or ESP32?

Yes. Connect to the hardware I2C pins (ESP8266: GPIO4/GPIO5; ESP32: GPIO21/GPIO22). Power from 3.3 V. The SparkFun library works identically on these platforms with no changes to the sensor code.

Why does the sensor get warm during operation?

The LEDs generate some heat, especially at higher brightness levels. This is normal. The MAX30102 datasheet recommends keeping the LED current as low as possible for a good signal — excessive brightness saturates the photodetector and wastes power. If the module feels hot to touch, reduce ledBrightness.

Can MAX30102 measure ECG (electrocardiogram)?

No. ECG requires measuring electrical signals from the heart via electrodes placed on the skin. The MAX30102 is an optical sensor that detects blood volume changes optically. It can produce a PPG waveform that superficially resembles an ECG, but it is not an ECG. For actual ECG projects, use an AD8232 or similar ECG front-end IC.

How do I mount MAX30102 for wrist-based heart rate (like a smartwatch)?

Wrist-based PPG is significantly harder than fingertip PPG because the wrist has lower perfusion and more motion artefacts. You need a very high LED brightness (above 100), a tight-fitting band to minimise motion, and more sophisticated signal processing (often involving accelerometer-based motion cancellation). For beginner projects, stick with the fingertip placement.

Conclusion

The MAX30102 is one of the most impressive sensors available to Arduino hobbyists. In a package smaller than a fingernail, it delivers medically-meaningful measurements of heart rate and blood oxygen saturation through sophisticated optical sensing and a capable built-in ADC. With the SparkFun library and the code in this guide, you can have a working SpO2 monitor running in under an hour.

The key to reliable readings lies in understanding the sensor’s optical principles: keep the finger still, cover the entire sensor window, shield from ambient light, and average over enough samples to filter noise. With these practices, the MAX30102 delivers readings that will genuinely impress you with their accuracy for a sub-₹200 component.

From here, you can extend this project to log readings to an SD card, upload them to a cloud dashboard via WiFi, or add an alert system that buzzes a buzzer when SpO2 drops below 95%. The platform is solid — what you build on it is up to your imagination.

Shop All Sensors & Modules at Zbotic

Tags: Arduino, heart rate sensor, MAX30102, pulse oximeter, SpO2
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Portable Generator vs Solar Po...
blog portable generator vs solar power backup india comparison guide 2024 596519
blog vnh5019 motor driver shield pololu high current arduino guide 596521
VNH5019 Motor Driver Shield: P...

Related posts

Svg%3E
Read more

Encoder Module: Position and Speed Measurement with Arduino

April 1, 2026 0
A rotary encoder converts the angular position and rotation speed of a shaft into electrical signals that Arduino can count... Continue reading
Svg%3E
Read more

Infrared Obstacle Sensor: Line Follower and Object Detection

April 1, 2026 0
Infrared obstacle sensors are the building blocks of line-following robots, edge detection systems, and proximity triggers. These tiny modules emit... Continue reading
Svg%3E
Read more

Rain Sensor and Raindrop Detection Module: Arduino Guide

April 1, 2026 0
A rain sensor module detects the presence of water droplets on its surface, giving Arduino a simple signal to trigger... Continue reading
Svg%3E
Read more

LiDAR Sensor TFmini: Distance Measurement Beyond Ultrasonic

April 1, 2026 0
When ultrasonic sensors hit their limits — range too short, accuracy too coarse, outdoor sunlight causing interference — LiDAR sensors... Continue reading
Svg%3E
Read more

Pressure Sensor BMP280: Weather Station and Altitude Meter

April 1, 2026 0
The BMP280 barometric pressure sensor by Bosch measures atmospheric pressure with ±1 hPa accuracy and temperature with ±1°C precision. These... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now