Published February 25, 2022
0
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. More ideas can be gleaned from our Arduino projects.
Also check our previous pulse oximeter project:
- MAX30102 Pulse Sensor with Arduino
- IoT Based Heart Rate Monitor
- Arduino Based Pulse Oximeter Sensor Circuit
- Arduino Pulse Sensor
Component Requirement for DIY Pulse Oximeter
Project Used Hardware
- Arduino Nano,
- Max 30100 Sensor,
- 0.96 inch OLED Display
Project Used Software
- Arduino IDE
Project Hardware Software Selection
- '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 gets the job done properly. So I used this one.
- '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.
- '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
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); }
Video