Source: https://mokxi.com/learn/arduino-max30102
Updated: 2026-11-02

Learn

# Heart rate and SpO2 with a MAX30102 on an Arduino

Intermediate

Written by the Mokxi team, updated November 2, 2026

Start building free Open the editor

Or see every lesson.

- 465 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Click to open it in the editor

A MAX30102 on I2C, read with the SparkFun library, on a simulated ATmega328P. Drag the sliders on the sensor, or press F.

The MAX30102 is the small sensor in most hobby pulse oximeters. It shines a red and an infrared LED into a fingertip and measures how much light comes back. Each heartbeat pushes a little more blood into the finger, which soaks up a little more light, so the reading dips once a beat. How far apart the dips are gives the heart rate; how deep the red dip is next to the infrared one gives the blood oxygen, SpO2.

The circuit above is an Uno with a MAX30102 on I2C, running the SparkFun library and its SpO2 algorithm. The sliders on the sensor are the person: the heart rate and the oxygen level. The F button puts the finger on or takes it off. A new reading prints every four seconds. This is for learning how the sensor works, not for checking anyone’s health.

## What you need

- An Arduino Uno
- A MAX30102 breakout board
- Four jumper wires

## Wiring

Part and pin | Goes to | Note

MAX30102 VIN | 5 V | The board makes the 1.8 V and 3.3 V it needs

MAX30102 GND | GND |

MAX30102 SDA | A4 | I2C address 0x57; the board has pull-ups

MAX30102 SCL | A5 |

MAX30102 INT | Not connected | This sketch polls instead

## From light to a pulse

The sensor takes samples of both colors, red and infrared, many times a second and stores them in a small queue, its FIFO. The sketch empties the queue into two arrays of 100 samples each. At 25 samples a second, that is four seconds of light, enough to hold several heartbeats.

Then one function call does the math: maxim_heart_rate_and_oxygen_saturation(), from Maxim’s reference code, which the SparkFun library ships as spo2_algorithm.h. It finds the dips, works out the time between them, and compares the size of the red and infrared ripples. It hands back the heart rate, the SpO2 and a valid flag for each.

## The sketch, step by step

sensor.begin(Wire, I2C_SPEED_FAST) finds the chip. sensor.setup(20, 4, 2, 100, 411, 4096) sets it up: LED brightness 20, which is about 4 milliamps; 4 samples averaged into one; red and infrared on; 100 samples a second before averaging, so 25 after; the longest pulse width; and the 4096 nA range.

The LEDs are kept dim on purpose. The Uno has 2 KB of RAM, and two arrays of 100 samples as 32-bit numbers would take 800 bytes of it. At 4 mA every reading fits in 16 bits, so the arrays are uint16_t and take 400.

loop() fills both arrays, calls the algorithm, and prints. With no finger it says "Place your finger on the sensor".

The loop, from the pulse oximeter

## Why the numbers jump

The next line, with the sliders at 72 beats a minute and 98 percent, says "heart rate 75 bpm, SpO2 98 %". The algorithm measures the time between beats in whole samples, a twenty-fifth of a second each, and rounds down. A beat every 20.8 samples counts as 20, and 25 x 60 / 20 is 75.

Set the heart rate to 120 and the oxygen to 88 and the readings go "heart rate 115 bpm, SpO2 88 %", then "heart rate 125 bpm, SpO2 87 %". At 120 a beat is 12.5 samples, which rounds to 13 or 12: 115 or 125. To get a steadier number, average several readings, or use a faster sample rate.

## What the simulation leaves out

The pulse here is drawn, not recorded: a clean dip once a beat, with no noise, no moving finger and no room light. The oxygen level comes from SpO2 = 110 - 25 R, the simple straight-line calibration most hobby notes use; real oximeters are calibrated against blood samples for each design. A real fingertip that moves or presses too hard gives far messier readings than these.

So the code here is real and runs as it will on the bench, but treat a hobby MAX30102 as a way to learn, never as a medical measurement.

## Common mistakes

No sensor found. Pull the SDA wire in this circuit and the sketch prints "MAX30105 was not found. Please check wiring/power." The SparkFun library is named after the MAX30105 but reads the MAX30102 too.

Storing 18-bit samples in 16-bit arrays with the LEDs bright. The samples overflow and the math is nonsense. Keep the LED current low, or use 32-bit arrays on a board with more RAM.

Too few samples. The algorithm needs several beats; four seconds at 25 a second is the usual window.

Pressing hard. Squeezing the sensor pushes the blood out of the fingertip and flattens the pulse.

Mixing it up with the MAX30100. The older chip has different registers and needs a different library.

## Questions

How do I connect a MAX30102 to an Arduino Uno?

VIN to 5 V, GND to GND, SDA to A4 and SCL to A5. The breakout has its own regulators and pull-up resistors, and the chip answers at I2C address 0x57.

Which library should I use for the MAX30102?

The SparkFun MAX3010x library. Include MAX30105.h for the sensor, spo2_algorithm.h for heart rate and SpO2, or heartRate.h for a beat-by-beat heart rate. Mokxi includes all three.

Why does my MAX30102 heart rate jump around?

The algorithm counts whole samples between beats, so at 25 samples a second it can only report certain values, and motion and light add noise on a real finger. Discard the first reading and average several.

Is a MAX30102 accurate enough to use as a medical device?

No. Hobby boards are not calibrated or tested as medical devices. Use one to learn how pulse oximetry works.

Related

## Keep going

I2C Explained: Addresses, Acknowledges and Pull-Ups Arduino DS18B20 Temperature Sensor: Wiring and Code Arduino OLED Display (SSD1306) Tutorial Arduino Science Fair Projects With a Real Hypothesis Arduino Pulse Sensor: Heart Rate on an OLED How the MAX30102 is modeled The simpler analog pulse sensor The Arduino Uno simulator The project page, with the full sketch Intermediate

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
