Pulse oximeter project

This project involves the development of a pulse oximeter that can measure and display the following health parameters:

  • SpO2 (Blood Oxygen Saturation)
  • Heart Rate (BPM)
  • Plethysmograph Waveform (Pleth)
  • Perfusion Index (PI)

The system should be capable of recording and saving these measurements to both an SD card and a Bluetooth-connected mobile application. It must include three physical buttons with the following functionalities:

  1. Save Button – Saves the current measurement data.
  2. Delete Button – Deletes previously stored data from the SD card.
  3. Reset Button – Resets the current measurement session and clears average calculations.

Hardware Components:

  • MAX30102 Pulse Oximeter Sensor
  • SSD1306 128x64 OLED Display
  • SD Card Module
  • HC-06 Bluetooth Module
  • 5V Buzzer
  • 3 Push Buttons (Save, Delete, Reset)

The OLED display will visually show the real-time data, including a waveform for the pleth signal, while the buzzer may provide audio feedback (e.g., for heartbeat detection). Data transmission to the mobile app is done via the HC-06 Bluetooth module.

When is your assignment due to be handed in ?

How far have you got with it ?

6 month project i am able to measure the SPO2 and HR the only part left is the SD card module and Andriod app

Great, the rest is relatively easy.
Can you post your existing code here <in CODE tags> ?


#include "ssd1306h.h"
#include "MAX30102.h"
#include "Pulse.h"
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <avr/sleep.h>
#include <Wire.h>

// Routines to clear and set bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


SSD1306 oled;
MAX30102 sensor;
Pulse pulseIR;
Pulse pulseRed;
MAFilter bpm;

#define LED LED_BUILTIN
#define BUTTON 3
#define OPTIONS 7

static const uint8_t heart_bits[] PROGMEM = { 0x00, 0x00, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0xfe, 0xff,
                                        0xfe, 0xff, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f,
                                        0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
                                        0x00, 0x00 };

//spo2_table is approximated as  -45.060*ratioAverage* ratioAverage + 30.354 *ratioAverage + 94.845 ;
const uint8_t spo2_table[184] PROGMEM =
        { 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 99, 99, 99, 99,
          99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
          100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 97, 97,
          97, 97, 96, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91,
          90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81,
          80, 80, 79, 78, 78, 77, 76, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67,
          66, 66, 65, 64, 63, 62, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50,
          49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29,
          28, 27, 26, 25, 23, 22, 21, 20, 19, 17, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5,
          3, 2, 1 } ;
// 'logo', 128x64px
const unsigned char bmp_logo [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x47, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xbf, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x00, 0x03, 0xe0, 0x20, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x01, 0xfe, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0x00, 0x10, 0x00, 0x10, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00, 0x10, 0x00, 0x10, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x10, 0x00, 0x10, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x18, 0x00, 0x10, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xf0, 0x10, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x10, 0x10, 0x08, 0x21, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x08, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x80,
0x00, 0x0f, 0xc0, 0x7c, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80,
0x00, 0x0f, 0x00, 0x38, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80,
0x00, 0x0e, 0x00, 0x30, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80,
0x00, 0x0c, 0x00, 0x30, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0x00, 0x1c, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0x00, 0x1c, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0x00, 0x1c, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0x00, 0x0e, 0x00, 0xf8, 0x00, 0x70, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0x00, 0x0e, 0x00, 0xfc, 0x00, 0xf0, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x07, 0x07, 0xaf, 0x00, 0xf0, 0x01, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x07, 0xdf, 0x27, 0xe3, 0xe0, 0x01, 0x40, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x03, 0xff, 0x27, 0xff, 0xc0, 0x01, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x01, 0xff, 0x27, 0xff, 0xc0, 0x01, 0x10, 0x00, 0x80, 0x00, 0x00, 0x1c, 0x00, 0x08, 0x00,
0x00, 0x00, 0x0e, 0x23, 0xe6, 0x00, 0x01, 0x08, 0x00, 0x80, 0x00, 0x00, 0x12, 0x00, 0x08, 0x00,
0x00, 0x01, 0xc7, 0x27, 0xe0, 0xc0, 0x01, 0x08, 0x00, 0x80, 0x00, 0x00, 0x22, 0x00, 0x08, 0x00,
0x00, 0x01, 0xc7, 0xff, 0xe1, 0xc0, 0x01, 0x04, 0xc0, 0x80, 0x02, 0x04, 0x42, 0x00, 0x08, 0x00,
0x00, 0x01, 0xc7, 0xff, 0xe1, 0xc0, 0x01, 0x07, 0x00, 0x40, 0x82, 0x08, 0x44, 0x00, 0x00, 0x00,
0x00, 0x01, 0xc6, 0xee, 0xe1, 0xc0, 0x01, 0x79, 0x00, 0x40, 0x82, 0x10, 0x5c, 0x00, 0x00, 0x00,
0x00, 0x01, 0xc0, 0x06, 0x01, 0x80, 0x03, 0x81, 0x80, 0x40, 0x82, 0x10, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0xe0, 0x58, 0x01, 0x80, 0x04, 0x80, 0x40, 0x20, 0x82, 0x10, 0x20, 0x80, 0x00, 0x00,
0x00, 0x00, 0xe2, 0x00, 0x03, 0x80, 0x00, 0x80, 0x40, 0x20, 0x81, 0x20, 0x13, 0x00, 0x00, 0x00,
0x00, 0x00, 0xec, 0xc8, 0x6f, 0x80, 0x00, 0x80, 0x20, 0x20, 0x81, 0x20, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0xcc, 0xff, 0x00, 0x00, 0x80, 0x20, 0x20, 0x81, 0x40, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0xff, 0xde, 0xff, 0x00, 0x00, 0x80, 0x20, 0x20, 0x80, 0xc0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00, 0x80, 0x30, 0x20, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};


int getVCC() {
  //reads internal 1V1 reference against VCC
  #if defined(__AVR_ATmega1284P__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  // For ATmega1284
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  // For ATmega328
  #endif
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA, ADSC));
  uint8_t low = ADCL;
  unsigned int val = (ADCH << 8) | low;
  //discard previous result
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA, ADSC));
  low = ADCL;
  val = (ADCH << 8) | low;
 
  return (((long)1024 * 1100) / val)/100; 
}

void print_digit(int x, int y, long val, char c=' ', uint8_t field = 3,const int BIG = 2)
    { 
    uint8_t ff = field;
    do {
        char ch = (val!=0) ? val%10+'0': c;
        oled.drawChar( x+BIG*(ff-1)*6, y, ch, BIG);
        val = val/10;
        --ff;
    } while (ff>0);
}


/*
*   Record, scale  and display PPG Wavefoem
*/
const uint8_t MAXWAVE = 72;

class Waveform {
  public:
    Waveform(void) {wavep = 0;}

      void record(int waveval) {
        waveval = waveval/8;         // scale to fit in byte  缂╂斁浠ラ€傚悎瀛楄妭
        waveval += 128;              //shift so entired waveform is +ve 
        waveval = waveval<0? 0 : waveval;
        waveform[wavep] = (uint8_t) (waveval>255)?255:waveval;
        wavep = (wavep+1) % MAXWAVE;
      }
 
      void scale() {
        uint8_t maxw = 0;
        uint8_t minw = 255;
        for (int i=0; i<MAXWAVE; i++) {
          maxw = waveform[i]>maxw?waveform[i]:maxw;
          minw = waveform[i]<minw?waveform[i]:minw;
        }
        uint8_t scale8 = (maxw-minw)/4 + 1;  //scale * 8 to preserve precision
        uint8_t index = wavep;
        for (int i=0; i<MAXWAVE; i++) {
          disp_wave[i] = 31-((uint16_t)(waveform[index]-minw)*8)/scale8;
          index = (index + 1) % MAXWAVE;
        }
      }

void draw(uint8_t X) {
  for (int i=0; i<MAXWAVE; i++) {
    uint8_t y = disp_wave[i];
    oled.drawPixel(X+i, y);
    if (i<MAXWAVE-1) {
      uint8_t nexty = disp_wave[i+1];
      if (nexty>y) {
        for (uint8_t iy = y+1; iy<nexty; ++iy) 
        oled.drawPixel(X+i, iy);
        }
        else if (nexty<y) {
          for (uint8_t iy = nexty+1; iy<y; ++iy) 
          oled.drawPixel(X+i, iy);
          }
       }
    }
}

private:
    uint8_t waveform[MAXWAVE];
    uint8_t disp_wave[MAXWAVE];
    uint8_t wavep = 0;
   
} wave;

int  beatAvg;
int  SPO2, SPO2f;
int  voltage;
bool filter_for_graph = false;
bool draw_Red = false;
uint8_t pcflag =0;
uint8_t istate = 0;
uint8_t sleep_counter = 0;

void button(void){
    pcflag = 1;
}

void checkbutton(){
    if (pcflag && !digitalRead(BUTTON)) {
      istate = (istate +1) % 4;
      filter_for_graph = istate & 0x01;
      draw_Red = istate & 0x02;
      EEPROM.write(OPTIONS, filter_for_graph);
      EEPROM.write(OPTIONS+1, draw_Red);
    }
    pcflag = 0;
}



void Display_5(){
   if(pcflag && !digitalRead(BUTTON)){
     draw_oled(5);
     delay(1100);
   }
   pcflag = 0;


}

void go_sleep() {
    oled.fill(0);
    oled.off();
    delay(20);
    sensor.off();
    delay(20);
    cbi(ADCSRA, ADEN);  // disable adc
    delay(10);
    pinMode(0,INPUT);
    pinMode(2,INPUT);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    
    sleep_mode();  // sleep until button press
    // cause reset
    setup();
}

void draw_oled(int msg) {
    oled.firstPage();
    do{
    switch(msg){
        case 0:  oled.drawStr(10,0,F("Device error"),1);
                 break;
        case 1:  oled.drawStr(13,10,F("PLACE"),1);
                 oled.drawStr(10,20,F("Hand"),1);
                 oled.drawChar(100,0,voltage/10+'0');
                 oled.drawChar(106,0,'.');
                 oled.drawChar(112,0,voltage%10+'0');
                 oled.drawChar(118,0,'V');
                 oled.drawStr(84,14,F("SPO2"),1);
                 if (draw_Red)
                    oled.drawStr(84,24,F("Red"),1);
                 else
                    oled.drawStr(84,24,F("IR"),1);
                 if (filter_for_graph)
                    oled.drawStr(108,24,F("IP"),1);
                 else
                    oled.drawStr(108,24,F("Raw"),1);
                 break;
        case 2:  print_digit(86,0,beatAvg);
                 wave.draw(8);
                 print_digit(98,16,SPO2f,' ',3,1);
                 oled.drawChar(116,16,'%');
                 print_digit(98,24,SPO2,' ',3,1);
                 oled.drawChar(116,24,'%');
                 break;
        case 3:  oled.drawStr(0,9,F("Pulse "),1);
                 oled.drawStr(0,20,F("Oximeter"),1);
                 //oled.drawXBMP(6,8,16,16,heart_bits);
               
                 break;
        case 4:  oled.drawStr(28,12,F("OFF IN"),1);
                 oled.drawChar(76,12,10-sleep_counter/10+'0');
                 oled.drawChar(82,12,'*');
                 break;
        case 5:  oled.drawStr(0,4,F("BMP:"),1);
                 print_digit(25,0,beatAvg);
                 oled.drawStr(0,15,F("SpO2:%"),1);
                 print_digit(25,15,SPO2);
                 oled.drawXBMP(106,8,16,16,heart_bits);
                 break;
        }
    } while (oled.nextPage());
}

void setup(void) {
  pinMode(LED, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  filter_for_graph = EEPROM.read(OPTIONS);
  draw_Red = EEPROM.read(OPTIONS+1);
  oled.init();
  oled.fill(0x00);
  draw_oled(3);
  delay(8000);
  if (!sensor.begin())  {
    draw_oled(0);
    while (1);
  }
  sensor.setup();
  attachInterrupt(digitalPinToInterrupt(BUTTON),button, CHANGE);
}

long lastBeat = 0;    //Time of the last beat
long displaytime = 0; //Time of the last display update
bool led_on = false;


void loop()  {
 
    sensor.check();
    long now = millis();   //start time of this cycle
    if (!sensor.available()) return;
    uint32_t irValue = sensor.getIR();
    uint32_t redValue = sensor.getRed();
    sensor.nextSample();
    if (irValue<30000) {
        voltage = getVCC();
        checkbutton();
        draw_oled(sleep_counter<=50 ? 1 : 60); // finger not down message
        //? : 鏄笁鍏冭繍绠楃锛屾暣涓〃杈惧紡鏍规嵁鏉′欢杩斿洖涓嶅悓鐨勫€硷紝濡傛灉x>y涓虹湡鍒欒繑鍥瀤锛屽鏋滀负鍋囧垯杩斿洖y锛屼箣鍚�=璧嬪€肩粰z銆傜浉褰撲簬:if(x>y)z=x;elsez=y
        delay(200);
        ++sleep_counter;
        if (sleep_counter>100) {
          go_sleep();
          sleep_counter = 0;
        }
    } else {
        sleep_counter = 0;
        // remove DC element绉婚櫎鐩存祦鍏冧欢
        int16_t IR_signal, Red_signal;
        bool beatRed, beatIR;
        if (!filter_for_graph) {//鍥惧舰杩囨护鍣�
           IR_signal =  pulseIR.dc_filter(irValue) ;
           Red_signal = pulseRed.dc_filter(redValue);
           beatRed = pulseRed.isBeat(pulseRed.ma_filter(Red_signal));
           beatIR =  pulseIR.isBeat(pulseIR.ma_filter(IR_signal));       
        } else {
           IR_signal =  pulseIR.ma_filter(pulseIR.dc_filter(irValue)) ;
           Red_signal = pulseRed.ma_filter(pulseRed.dc_filter(redValue));
           beatRed = pulseRed.isBeat(Red_signal);
           beatIR =  pulseIR.isBeat(IR_signal);
        }
        // invert waveform to get classical BP waveshape
        wave.record(draw_Red ? -Red_signal : -IR_signal );
        // check IR or Red for heartbeat    
        if (draw_Red ? beatRed : beatIR){
            long btpm = 60000/(now - lastBeat);
            if (btpm > 0 && btpm < 200) beatAvg = bpm.filter((int16_t)btpm);
            lastBeat = now;
            digitalWrite(LED, HIGH);
            led_on = true;
            // compute SpO2 ratio
            long numerator   = (pulseRed.avgAC() * pulseIR.avgDC())/256;
            long denominator = (pulseRed.avgDC() * pulseIR.avgAC())/256;
            int RX100 = (denominator>0) ? (numerator * 100)/denominator : 999;
            // using formula
            SPO2f = (10400 - RX100*17+50)/100; 
            // from table
            if ((RX100>=0) && (RX100<184))
              SPO2 = pgm_read_byte_near(&spo2_table[RX100]);
        }
        // update display every 50 ms if fingerdown
        if (now-displaytime>50) {
            displaytime = now;
            wave.scale();
            draw_oled(2);
           
        }
        Display_5();


    }
    // flash led for 25 ms
    if (led_on && (now - lastBeat)>25){
        digitalWrite(LED, LOW);
        led_on = false;
     }
}

I don't see where you mentioned the host microcontroller?

your wiring must be fairly complex - upload a schematic - did you build a PCB?

you may have been able to do the complete project using a ESP32-Cheap-Yellow-Display - if I remember the MAX30102 Pulse Oximeter Sensor uses a I2C interface so easy to connect
may have even plotted some graphs of sensor readings over time

I AM USING ARDUINO nano .OLED ssd1306 and Max302100. simple connection what is added is the button that will the modes

but esp32 i have .i am unable to program it actually the code giving me a challenge

you may find once you add the SD reader and HC-06 you could overload the Nano power supply
HC-06 is Bluetooth Classic - if you require BLE use HM-10
are you implementing your own app? if so which IDE?

a ESP32 has onboard Bluetooth Classic and BLE (plus WiFi) so should be simpler and less wiring than HC-06

Your I2C connections never connect to the Nano. Ground is not connected from the two devices to the Nano. Some devices you mentioned are not in the drawing. Do you have an original wiring diagram to follow? Do you need help making a drawing of the connections? Your instructor should have given you the information on connections and wiring diagrams.

I am thinking of using it the one I have is Esp32 esp 32-s Node. My challenge is to get the code of Max30102, Oled with esp32

for the OLED have a look at LiquidCrystal_I2C library

also have a look at DFRobot_MAX30102 library

test each device in a separate program before attempting to build the complete program