Description
MAX30100 Pulse Oximeter
The MAX30100 Pulse Oximeter is a medical device designed to measure blood oxygen saturation levels, heart rate, and pulse strength. It uses a non-invasive technique to determine oxygen saturation in the blood.
This module features a pair of Light Emitting Diodes (LEDs) that emit monochromatic red light at a wavelength of 660nm and infrared light at 940nm.
When the LEDs emit light, it passes through the finger and is absorbed by the oxygenated blood. The remaining light is reflected through the finger and detected by a photodiode. The detector processes the signals and generates the output.
The MAX30100 sensor communicates using the I2C serial communication protocol.
MAX30100 module Specification
- The operating voltage of the MAX30100 module ranges from 1.7V to 3.3V.
- It has a supply current of 1200µA.
- The module operates within a temperature range of -40°C to +85°C.
- The LED current can range from 0mA to 50mA.
- The LED pulse width can vary from 200µs to 1.6ms.
MAX30100 Sensor Pinout
MAX30100 Pin Description
- VIN: Power supply pin, connected to a voltage in the specified range.
- GND: Ground pin, connected to the supply ground.
- SCL: Serial Clock pin for I2C communication.
- SDA: Serial Data pin for I2C communication.
- INT: Active Low Interrupt pin.
- IR LED (IRD): Cathode pin for the infrared LED and LED driver connection.
- Red LED (RD): Cathode pin for the red LED and LED driver connection.
MAX30100 Hardware Connection with Arduino
Arduino interfacing diagram with MAX30100
Read Heart Rate using MAX30100 and Arduino
To measure heart rate (BPM) and oxygen saturation (SpO2) using the MAX30100, we will utilize the I2C communication protocol and display the readings on the Arduino IDE’s Serial Monitor.
For interfacing with the sensor, we will use the MAX30100lib library by OXullo Intersecans, which can be installed from the Arduino IDE Library Manager. To do this:
- Open the Arduino IDE.
- Navigate to Sketch -> Include Library -> Manage Libraries….
- In the Library Manager, search for “max30100” in the search box.
- Install the MAX30100lib library.
The Library Manager window will open. Type MAX30100 into the search box and click the Install button to install version 1.2.1 or higher.
Now, open an example from the MAX30100lib library. To do this, navigate to File -> Examples -> MAX30100lib -> MAX30100_Minimal in the Arduino IDE.
Here, we are using the same example as shown below.
Code for MAX30100 with Arduino
/*
Arduino-MAX30100 oximetry / heart rate integrated sensor library
Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define REPORTING_PERIOD_MS 1000
// PulseOximeter is the higher level interface to the sensor
// it offers:
// * beat detection reporting
// * heart rate calculation
// * SpO2 (oxidation level) calculation
PulseOximeter pox;
uint32_t tsLastReport = 0;
// Callback (registered below) fired when a pulse is detected
void onBeatDetected()
{
Serial.println("Beat!");
}
void setup()
{
Serial.begin(115200);
Serial.print("Initializing pulse oximeter..");
// Initialize the PulseOximeter instance
// Failures are generally due to an improper I2C wiring, missing power supply
// or wrong target chip
if (!pox.begin()) {
Serial.println("FAILED");
for(;;);
} else {
Serial.println("SUCCESS");
}
// The default current for the IR LED is 50mA and it could be changed
// by uncommenting the following line. Check MAX30100_Registers.h for all the
// available options.
// pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
// Register a callback for the beat detection
pox.setOnBeatDetectedCallback(onBeatDetected);
}
void loop()
{
// Make sure to call update as fast as possible
pox.update();
// Asynchronously dump heart rate and oxidation levels to the serial
// For both, a value of 0 means "invalid"
if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
Serial.print("Heart rate:");
Serial.print(pox.getHeartRate());
Serial.print("bpm / SpO2:");
Serial.print(pox.getSpO2());
Serial.println("%");
tsLastReport = millis();
}
}
Now, upload the code to the Arduino board.
Once the upload is complete, open the Serial Monitor and set the baud rate to 115200 to view the output.
Output on the serial monitor
MAX30100 Not Working? Let’s see how to fix it.
The MAX30100 module is quite popular among hobbyists, but it has a significant design flaw. Let’s explore how to resolve this issue.
There are two methods to fix this problem, both of which we have tested in our lab, and are outlined below.
Method 1(Tested)
Disconnect the 4.7kΩ pull-up resistors from the 1.8V supply by cutting the trace along the red line.
Next, connect all the 4.7kΩ resistors to the 3.3V supply by linking them with a piece of wire along the yellow line, as shown in the diagram below.
The images below show the connections before and after the modification.
Method 2 (Tested)
The second method involves removing all the 4.7kΩ pull-up resistors and using external pull-up resistors on the SCL, SDA, and INT signal lines instead.
After removing the resistors, connect the MAX30100 module to the Arduino as shown in the diagram below.
Arduino interfacing diagram with MAX30100 for Method 2
Let’s understand the code
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
Next, we will define the delay using REPORTING_PERIOD_MS and create an object pox for the PulseOximeter class.
#define REPORTING_PERIOD_MS 1000
PulseOximeter pox;
A variable tsLastReport is created with the data type uint32_t to store the timestamp of the last beat.
uint32_t tsLastReport = 0;
In the onBeatDetected() function, we will print “Beat” when the sensor detects a finger placed above it.
void onBeatDetected()
{
Serial.println("Beat!");
}
In the setup() function, we set the baud rate to 115200.
We also use an if condition to detect the module and print its status.
Serial.begin(115200);
if (!pox.begin()) {
Serial.println("FAILED");
for(;;);
} else {
Serial.println("SUCCESS");
}
}
This is the important function used to set the IR LED current with the setIRLedCurrent() function.
The following code sets the current of the IR LED to 7.6mA:
pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
The default IR LED current in the library is set to 50mA, which can cause issues such as the LED not turning on or displaying a “FAILED” message on the serial monitor. In such cases, you should reduce the LED current to a lower value.
Here are some alternative values you can use with the setIRLedCurrent() function:
- MAX30100_LED_CURR_0MA
- MAX30100_LED_CURR_4_4MA
- MAX30100_LED_CURR_7_6MA
- MAX30100_LED_CURR_11MA
- MAX30100_LED_CURR_14_2MA
- MAX30100_LED_CURR_17_4MA
- MAX30100_LED_CURR_20_8MA
- MAX30100_LED_CURR_24MA
- MAX30100_LED_CURR_27_1MA
- MAX30100_LED_CURR_30_6MA
- MAX30100_LED_CURR_33_8MA
- MAX30100_LED_CURR_37MA
- MAX30100_LED_CURR_40_2MA
- MAX30100_LED_CURR_43_6MA
- MAX30100_LED_CURR_46_8MA
- MAX30100_LED_CURR_50MA
Note that a brighter LED can penetrate deeper into your skin. Therefore, you can adjust the LED current based on your requirements.
An important function called setOnBeatDetectedCallback() is used in the setup() function.
This function registers the callback function that will be triggered when a beat is detected.
pox.setOnBeatDetectedCallback(onBeatDetected);
In the loop() function, we use the update() function to get the latest data from the sensor.
pox.update();
Functions like getHeartRate() and getSpO2() are used to retrieve the heart rate and SpO2 percentage data from the sensor.
The sensor data will be printed on the Serial Monitor every second since REPORTING_PERIOD_MS is set to 1000.
We use the millis() function instead of the delay() function because millis() runs continuously and executes instructions after a specific time in milliseconds, while delay() halts the execution of the code for a set period.
Finally, we will print the heart rate and SpO2 values on the Serial Monitor.
if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
Serial.print("Heart rate:");
Serial.print(pox.getHeartRate());
Serial.print("bpm / SpO2:");
Serial.print(pox.getSpO2());
Serial.println("%");
tsLastReport = millis();
}