DIY Pulse Oximeter
2190 21
Sohom DIY

DIY Pulse Oximeter

I decided to make a 'Pulse Oximeter' because in this pandemic situation we need this device...

Description:-

I decided to make a 'Pulse Oximeter' because in this pandemic situation we need this device a lot. It helps us to measure the BPM(Beats Per Minute) and the percentage of Spo2 of our Body. I used Arduino Nano as the brain of the system. Besides this, I also used a Max 30100 Sensor to measure the BPM and Spo2 with the help of its Optical sensor(IR and red LED combined with a photodetector). Also to monitor the BPM and Spo2 I used a 0.96 inch OLED Display.

Project Used Hardware

Pulse Oximeter Hardware

Arduino Nano, Max 30100 Sensor, 0.96 inch OLED Display

Project Used Software

Arduino

Project Hardware Software Selection

1. Reason for selecting 'Arduino Nano': I could use any kind of microcontroller like Arduino UNO, Raspberry Pi Pico, Node MCU and so on. But I found the Arduino Nano cheaper and smaller than the other ones. Also, it get the job done properly. So I used this one. 2. Reason for selecting 'MAX 30100': I used MAX 30100 as the main sensor because it properly maintains the purpose of the device. Because other infrared sensors doesn't work like a charm like this at this price point. 3. Reason for selecting '0.96 inch OLED Display': First of all this display is small because I wanted to make it portable. Also, this sensor is very easy to work with. Besides these, I also used a Power Bank to power it up. Also, a Lithium Battery could get the job done. And I used the Arduino software because it's the official software of Arduino and also this software is very easy to work with.

Circuit Diagram

Oximeter-Circuit-Diagram

Code

#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define ENABLE_MAX30100 1
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 //64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
#define OLED_RESET 4 // 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#if ENABLE_MAX30100
#define REPORTING_PERIOD_MS 5000
// PulseOximeter is the higher level interface to the sensor
// it offers:
// * beat detection reporting
// * heart rate calculation
// * SpO2 (oxidation level) calculation
PulseOximeter pox;
#endif
uint32_t tsLastReport = 0;
int xPos = 0;
// Callback (registered below) fired when a pulse is detected
void onBeatDetected()
{
Serial.println("Beat!");
heart_beat(&xPos);
}
void setup()
{
Serial.begin(115200);
Serial.println("SSD1306 128x64 OLED TEST");
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
//display.display();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(20, 18);
// Display static text
display.print("Pulse OxiMeter");
int temp1 = 0;
int temp2 = 40;
int temp3 = 80;
heart_beat(&temp1);
heart_beat(&temp2);
heart_beat(&temp3);
xPos = 0;
display.display();
delay(2000); // Pause for 2 seconds
display.cp437(true);
display.clearDisplay();
Serial.print("Initializing pulse oximeter..");
#if ENABLE_MAX30100
// 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);
display_data(0, 0);
#endif
}
void loop()
{
#if ENABLE_MAX30100
// Make sure to call update as fast as possible
pox.update();
int bpm = 0;
int spo2 = 0;
// 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:");
bpm = pox.getHeartRate();
spo2 = pox.getSpO2();
Serial.println(bpm);
//Serial.print("bpm / SpO2:");
Serial.println(spo2);
//Serial.println("%");
tsLastReport = millis();
display_data(bpm, spo2);
}
#endif
drawLine(&xPos);
}
void display_data(int bpm, int spo2) {
display.fillRect(0, 18, 127, 15, BLACK);
//if(bpm ==0 && spo2==0){
// display.setTextSize(1);
// display.setTextColor(WHITE);
//display.setCursor(0, 18);
// Display static text
// display.print("Fingure Out");
//}
display.fillRect(0, 18, 127, 15, BLACK);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 18);
// Display static text
display.print("BPM ");
display.setTextSize(2);
display.print(bpm);
display.display();
display.setTextSize(1);
 display.setTextColor(WHITE);
display.setCursor(64, 18);
// Display static text
display.print("Spo2% ");
display.setTextSize(2);
display.println(spo2);
display.display();
}
void drawLine(int *x_pos) {
// Draw a single pixel in white
display.drawPixel(*x_pos, 8, WHITE);
display.drawPixel((*x_pos)++, 8, WHITE);
display.drawPixel((*x_pos)++, 8, WHITE);
display.drawPixel((*x_pos)++, 8, WHITE);
display.drawPixel((*x_pos), 8, BLACK); // -----
//Serial.println(*x_pos);
display.fillRect(*x_pos, 0, 31, 16, BLACK);
display.display();
//delay(1);
if (*x_pos >= SCREEN_WIDTH) {
*x_pos = 0;
}
}
void heart_beat(int *x_pos) {
/************************************************/
//display.clearDisplay();
display.fillRect(*x_pos, 0, 30, 15, BLACK);
// Draw a single pixel in white
display.drawPixel(*x_pos + 0, 8, WHITE);
display.drawPixel(*x_pos + 1, 8, WHITE);
display.drawPixel(*x_pos + 2, 8, WHITE);
display.drawPixel(*x_pos + 3, 8, WHITE);
display.drawPixel(*x_pos + 4, 8, BLACK); // -----
//display.display();
//delay(1);
display.drawPixel(*x_pos + 5, 7, WHITE);
display.drawPixel(*x_pos + 6, 6, WHITE);
display.drawPixel(*x_pos + 7, 7, WHITE); // .~.
//display.display();
//delay(1);
display.drawPixel(*x_pos + 8, 8, WHITE);
display.drawPixel(*x_pos + 9, 8, WHITE); // --
//display.display();
//delay(1);
/******************************************/
display.drawPixel(*x_pos + 10, 8, WHITE);
display.drawPixel(*x_pos + 10, 9, WHITE);
display.drawPixel(*x_pos + 11, 10, WHITE);
display.drawPixel(*x_pos + 11, 11, WHITE);
//display.display();
//delay(1);
/******************************************/
display.drawPixel(*x_pos + 12, 10, WHITE);
display.drawPixel(*x_pos + 12, 9, WHITE);
display.drawPixel(*x_pos + 12, 8, WHITE);
display.drawPixel(*x_pos + 12, 7, WHITE);
//display.display();
//delay(1);
display.drawPixel(*x_pos + 13, 6, WHITE);
display.drawPixel(*x_pos + 13, 5, WHITE);
display.drawPixel(*x_pos + 13, 4, WHITE);
display.drawPixel(*x_pos + 13, 3, WHITE);
 //display.display();
//delay(1);
display.drawPixel(*x_pos + 14, 2, WHITE);
display.drawPixel(*x_pos + 14, 1, WHITE);
display.drawPixel(*x_pos + 14, 0, WHITE);
display.drawPixel(*x_pos + 14, 0, WHITE);
//display.display();
//delay(1);
/******************************************/
display.drawPixel(*x_pos + 15, 0, WHITE);
display.drawPixel(*x_pos + 15, 1, WHITE);
display.drawPixel(*x_pos + 15, 2, WHITE);
display.drawPixel(*x_pos + 15, 3, WHITE);
//display.display();
//delay(1);
display.drawPixel(*x_pos + 15, 4, WHITE);
display.drawPixel(*x_pos + 15, 5, WHITE);
display.drawPixel(*x_pos + 16, 6, WHITE);
display.drawPixel(*x_pos + 16, 7, WHITE);
//display.display();
//delay(1);
display.drawPixel(*x_pos + 16, 8, WHITE);
display.drawPixel(*x_pos + 16, 9, WHITE);
display.drawPixel(*x_pos + 16, 10, WHITE);
display.drawPixel(*x_pos + 16, 11, WHITE);
//display.display();
//delay(1);
display.drawPixel(*x_pos + 17, 12, WHITE);
display.drawPixel(*x_pos + 17, 13, WHITE);
display.drawPixel(*x_pos + 17, 14, WHITE);
display.drawPixel(*x_pos + 17, 15, WHITE);
//display.display();
//delay(1);
display.drawPixel(*x_pos + 18, 15, WHITE);
display.drawPixel(*x_pos + 18, 14, WHITE);
display.drawPixel(*x_pos + 18, 13, WHITE);
display.drawPixel(*x_pos + 18, 12, WHITE);
//display.display();
//delay(1);
display.drawPixel(*x_pos + 19, 11, WHITE);
display.drawPixel(*x_pos + 19, 10, WHITE);
display.drawPixel(*x_pos + 19, 9, WHITE);
display.drawPixel(*x_pos + 19, 8, WHITE);
//display.display();
//delay(1);
/****************************************************/
display.drawPixel(*x_pos + 20, 8, WHITE);
display.drawPixel(*x_pos + 21, 8, WHITE);
//display.display();
//delay(1);
/****************************************************/
display.drawPixel(*x_pos + 22, 7, WHITE);
display.drawPixel(*x_pos + 23, 6, WHITE);
display.drawPixel(*x_pos + 24, 6, WHITE);
display.drawPixel(*x_pos + 25, 7, WHITE);
//display.display();
//delay(1);
/************************************************/
display.drawPixel(*x_pos + 26, 8, WHITE);
display.drawPixel(*x_pos + 27, 8, WHITE);
display.drawPixel(*x_pos + 28, 8, WHITE);
display.drawPixel(*x_pos + 29, 8, WHITE);
 display.drawPixel(*x_pos + 30, 8, WHITE); // -----
*x_pos = *x_pos + 30;
display.display();
delay(1);
}