SSD1306 no muestra datos spo2 MAX30102

Buenas grupo,

estoy tratando de hacer que las lecturas de ritmo cardiaco y de spo2 tomadas mediante el sensor MAX30102 se muestren por mi OLED. Sin embargo, esto nunca ocurre.

He ido probando a depurar el código escribiendo mensajes en la OLED en distintos lugares del código, y siempre me lo imprime salvo cuando entro el el while(1) que se encarga de imprimir por serial los valores tomados del sensor, concretamente en esta parte del código:

while (1)
  {
    if(x==0){
    escribir_texto(0,0,"Hasta aquí llego",1);
  }
    //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
    for (byte i = 25; i < 100; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for (byte i = 75; i < 100; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data

      digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample

      //send samples and calculation result to terminal program through UART
      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(irBuffer[i], DEC);

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);
      escribir_texto(16,16, heartRate, 2);
      
 

      
      Serial.print(F(", HRvalid="));
      Serial.print(validHeartRate, DEC);
      

      Serial.print(F(", SPO2="));
      Serial.print(spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(validSPO2, DEC);
    }

El código completo es el siguiente:

/*
  Optical SP02 Detection (SPK Algorithm) using the MAX30105 Breakout
  By: Nathan Seidle @ SparkFun Electronics
  Date: October 19th, 2016
  https://github.com/sparkfun/MAX30105_Breakout

  This demo shows heart rate and SPO2 levels.

  It is best to attach the sensor to your finger using a rubber band or other tightening 
  device. Humans are generally bad at applying constant pressure to a thing. When you 
  press your finger against the sensor it varies enough to cause the blood in your 
  finger to flow differently which causes the sensor readings to go wonky.

  This example is based on MAXREFDES117 and RD117_LILYPAD.ino from Maxim. Their example
  was modified to work with the SparkFun MAX30105 library and to compile under Arduino 1.6.11
  Please see license file for more info.

  Hardware Connections (Breakoutboard to Arduino):
  -5V = 5V (3.3V is allowed)
  -GND = GND
  -SDA = A4 (or SDA)
  -SCL = A5 (or SCL)
  -INT = Not connected
 
  The MAX30105 Breakout can handle 5V or 3.3V I2C logic. We recommend powering the board with 5V
  but it will also run at 3.3V.
*/

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"
#include <lcdgfx.h>

//Objeto pantalla OLED
int8_t ResetPin =  -1;         //Cambiar por -1 si no hay pin de reset
int8_t Dir_Pantalla = 0x3C;   //Cambiar por 0x3C si esta direccion no funciona
DisplaySSD1306_128x64_I2C display(ResetPin, { - 1, Dir_Pantalla, -1, -1, 0});

//Objeto sensor
MAX30105 particleSensor;

#define MAX_BRIGHTNESS 255

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
//To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
uint16_t irBuffer[100]; //infrared LED sensor data
uint16_t redBuffer[100];  //red LED sensor data
#else
uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100];  //red LED sensor data
#endif

int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int32_t valor_pulso;
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid

byte pulseLED = 11; //Must be on PWM pin
byte readLED = 13; //Blinks with each data read

int x=0;//Variable de depuración

void setup()
{
  Serial.begin(115200); // initialize serial communication at 115200 bits per second:
  display.begin();
  display.fill(0x00);
  x=0;
//  display.display();

  pinMode(pulseLED, OUTPUT);
  pinMode(readLED, OUTPUT);

  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println(F("MAX30105 was not found. Please check wiring/power."));
    while (1);
  }

  Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
  while (Serial.available() == 0) ; //wait until user presses a key
  Serial.read();

  byte ledBrightness = 60; //Options: 0=Off to 255=50mA
  byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 4096; //Options: 2048, 4096, 8192, 16384

  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}

void loop()
{
  
  bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps

  //read the first 100 samples, and determine the signal range
  for (byte i = 0 ; i < bufferLength ; i++)
  {
  
    while (particleSensor.available() == false) //do we have new data?
      particleSensor.check(); //Check the sensor for new data

    redBuffer[i] = particleSensor.getRed();
    irBuffer[i] = particleSensor.getIR();
    particleSensor.nextSample(); //We're finished with this sample so move to next sample

    Serial.print(F("red="));
    Serial.print(redBuffer[i], DEC);
    Serial.print(F(", ir="));
    Serial.println(irBuffer[i], DEC);
    
  }
  
  //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  while (1)
  {
    if(x==0){
    escribir_texto(0,0,"Hasta aquí llego",1);
  }
    //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
    for (byte i = 25; i < 100; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for (byte i = 75; i < 100; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data

      digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample

      //send samples and calculation result to terminal program through UART
      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(irBuffer[i], DEC);

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);
      escribir_texto(16,16, heartRate, 2);
      
 

      
      Serial.print(F(", HRvalid="));
      Serial.print(validHeartRate, DEC);
      

      Serial.print(F(", SPO2="));
      Serial.print(spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(validSPO2, DEC);
    }

    //After gathering 25 new samples recalculate HR and SP02
    maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
  }
  x++;
}

void escribir_texto(byte x_pos, byte y_pos, char *text, byte text_size) {
  display.setFixedFont(ssd1306xled_font6x8);///Seleccionamos una fuente
  if (text_size == 1) {
    display.printFixed (x_pos,  y_pos, text, STYLE_NORMAL);
  }
  else if (text_size == 2) {
    display.printFixedN (x_pos, y_pos, text, STYLE_NORMAL, FONT_SIZE_2X);
  }
}

La pantalla OLED la tengo conectada a 5V, y el sensor MAX30102 a 3,3V

Gracias de antemano. Un saludo.

While es un un ciclo infinito. A menos que tengas algo que salga del mismo justamente te vas a quedar ahi por siempre.
Es lo mismo que loop().
Coloca un flag y cuando consideres que se ha completado la acción dentro del while(flag) pones el flag en false y con ello retornará al resto del loop.

// defines como bool
bool flag = true;
// en donde esta while pones
while(flag) {
  // acá todo lo que ya tienes
  // cumplidas las instrucciones pones
  flag = false; // con esto while(FALSE) se termina
}

Buenos días Surbyte. En el ciclo while(1) es donde muestro las medidas que se van tomando y las medidas procesadas. Entiendo que se repetirá infinitamente, pero creo que en dentro de ese bucle ya está haciendo su función.
Por eso trato de imprimir en la oled los datos procesados (frecuencia cardiaca y la saturación de oxígeno) en el bucle.
Sin embargo, en este bucle, nada de lo que mande a escribir a la oled llega a hacerlo.
Aún así he probado la solución que propones y ha pasado lo mismo. Por puerto serial imprime bien los valores pero en la oled nada. Dejo el código modificado:

/*
  Optical SP02 Detection (SPK Algorithm) using the MAX30105 Breakout
  By: Nathan Seidle @ SparkFun Electronics
  Date: October 19th, 2016
  https://github.com/sparkfun/MAX30105_Breakout

  This demo shows heart rate and SPO2 levels.

  It is best to attach the sensor to your finger using a rubber band or other tightening 
  device. Humans are generally bad at applying constant pressure to a thing. When you 
  press your finger against the sensor it varies enough to cause the blood in your 
  finger to flow differently which causes the sensor readings to go wonky.

  This example is based on MAXREFDES117 and RD117_LILYPAD.ino from Maxim. Their example
  was modified to work with the SparkFun MAX30105 library and to compile under Arduino 1.6.11
  Please see license file for more info.

  Hardware Connections (Breakoutboard to Arduino):
  -5V = 5V (3.3V is allowed)
  -GND = GND
  -SDA = A4 (or SDA)
  -SCL = A5 (or SCL)
  -INT = Not connected
 
  The MAX30105 Breakout can handle 5V or 3.3V I2C logic. We recommend powering the board with 5V
  but it will also run at 3.3V.
*/

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"
#include <lcdgfx.h>

//Objeto pantalla OLED
int8_t ResetPin =  -1;         //Cambiar por -1 si no hay pin de reset
int8_t Dir_Pantalla = 0x3C;   //Cambiar por 0x3C si esta direccion no funciona
DisplaySSD1306_128x64_I2C display(ResetPin, { - 1, Dir_Pantalla, -1, -1, 0});

//Objeto sensor
MAX30105 particleSensor;

#define MAX_BRIGHTNESS 255

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
//To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
uint16_t irBuffer[100]; //infrared LED sensor data
uint16_t redBuffer[100];  //red LED sensor data
#else
uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100];  //red LED sensor data
#endif

int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int32_t valor_pulso;
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid

byte pulseLED = 11; //Must be on PWM pin
byte readLED = 13; //Blinks with each data read

bool y=true;



void setup()
{
  Serial.begin(115200); // initialize serial communication at 115200 bits per second:
  display.begin();
  display.fill(0x00);
//  display.display();

  pinMode(pulseLED, OUTPUT);
  pinMode(readLED, OUTPUT);

  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println(F("MAX30105 was not found. Please check wiring/power."));
    while (1);
  }

  Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
  while (Serial.available() == 0) ; //wait until user presses a key
  Serial.read();

  byte ledBrightness = 60; //Options: 0=Off to 255=50mA
  byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 4096; //Options: 2048, 4096, 8192, 16384

  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}

void loop()
{
  if(y){
    bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps

  //read the first 100 samples, and determine the signal range
  for (byte i = 0 ; i < bufferLength ; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
      particleSensor.check(); //Check the sensor for new data

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample

      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.println(irBuffer[i], DEC);
    
    }
    y=false;
  }
  
  bool x=true;
  //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  while (x)
  { 
    escribir_texto(0,0,"Hasta aquí llego",1);
    
    //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
    for (byte i = 25; i < 100; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for (byte i = 75; i < 100; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data

      digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample

      //send samples and calculation result to terminal program through UART
      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(irBuffer[i], DEC);

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);
      escribir_texto(0,24,"Hasta aquí llego",1);
      escribir_texto(16,16, heartRate, 2);
      
 

      
      Serial.print(F(", HRvalid="));
      Serial.print(validHeartRate, DEC);
      

      Serial.print(F(", SPO2="));
      Serial.print(spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(validSPO2, DEC);
    }
  
    //After gathering 25 new samples recalculate HR and SP02
    maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

     x=false;
  }
 
}

void escribir_texto(byte x_pos, byte y_pos, char *text, byte text_size) {
  display.setFixedFont(ssd1306xled_font6x8);///Seleccionamos una fuente
  if (text_size == 1) {
    display.printFixed (x_pos,  y_pos, text, STYLE_NORMAL);
  }
  else if (text_size == 2) {
    display.printFixedN (x_pos, y_pos, text, STYLE_NORMAL, FONT_SIZE_2X);
  }
}

He seguido haciendo algunas pruebas y me he dado cuenta de que al usar la función sprintf() para convertir el uint16_t en un string, el program se queda parado y no llega a dar más lecturas. Lo que he modificado respecto al código anterior ha sido lo siguiente:

void loop()
{
  if(y){
    bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps

  //read the first 100 samples, and determine the signal range
  for (byte i = 0 ; i < bufferLength ; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
      particleSensor.check(); //Check the sensor for new data

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample

      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      escribir_texto(0,0,"Hasta aquí llego",1);
      Serial.print(F(", ir="));
      Serial.println(irBuffer[i], DEC);
      uint16_t myInt = irBuffer[i];
      char *IRBUFFER;
      sprintf(IRBUFFER,"%u", myInt);
      escribir_texto(0,16, IRBUFFER ,1);
    }
    y=false;
  }
  

estas usando para presentar datos a tu procedimiento

void escribir_texto(byte x_pos, byte y_pos, char *text, byte text_size) {

pero pones que se le debe enviar un puntero de chars y sin embargo lo primero que veo que quieres presentar es

 escribir_texto(16, 16, heartRate, 2);

pero heartRate es uint32_t o sea unsigned long
Eso deberias convertirlo de este modo

char *tmp;
sprintf(tmp, "%lu", heartRate);
escribir_texto(16, 16, tmp, 2);

repite esto con los demas si son uint32_t también.
Si son uint8_t (validSPO2 y validHeartRate) entonces usa

char *tmp;
sprintf(tmp, "%u", validHeartRate);

He realizado la prueba y ocurre lo mismo que lo que describo en la edición del comentario anterior.
La Oled se queda en negro cuando llega a la instrucción de sprintf(), y la transmisión de datos por puerto serial se detiene justo antes de mostrar el valor HR. Tras esto, vuelve a pedirme que presione una tecla para continuar.

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);
      char *tmp;
      sprintf(tmp, "%lu", heartRate);
      escribir_texto(16, 16, tmp, 2);

Buenas tardes.

Tras una charla con @Surbyte llegamos a la conclusión de que el problema se encontraba en la memoria que consumía el algoritmo de cálculo de la saturación de oxigeno. Esto sumado al peso de la librería que estaba usando para la pantalla Oled, obstaculizaban la buena ejecución del código.
Buscamos librerías que ocupasen muy poco espacio y encontró Surbyte una que ocupa poquisimo (GitHub - greiman/SSD1306Ascii: Text only Arduino Library for SSD1306 OLED displays)
, apenas 58 bytes (2%) de la memoria dinámica y 2768 (8%) de la memoria flash.
La pega de esta librería es que unicamente se puede escribir texto con ella. La usé y conseguí mostrar los datos de frecuencia cardiaca y saturación, pero unicamente lo números. Si quería imprimir algo más, se sobrecargaba el arduino.
Por tanto, la opción final por la que opté fue la de usar una micro con mayor memoria. Como tenía una NodeMcu 12E por casa, decidí usar esta, que la memoria es muchísimo mayor. Le he añadido un par de botones, uno para resetear y otro para hacer la toma de datos.


#include <Wire.h>
#include "MAX30105.h"//Librería del sensor https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
#include "spo2_algorithm.h"//algoritmo de cálculo de spo2
#include "lcdgfx.h"//Librería de la Oled https://github.com/lexus2k/lcdgfx


DisplaySSD1306_128x64_I2C display(-1);//Objeto Oled
MAX30105 SensorPulso;//Objeto sensor de pulso

#define MAX_BRIGHTNESS 255 //Definimos el brillo del LED
#define boton D3//Pin del botón de reseteo
#define botonLectura D4//Botón que usaremos para comenzar la toma de datos



uint32_t irBuffer[100]; //aquí guardaremos los datos del led infrarrojo
uint32_t redBuffer[100];  //aquí guardaremos los datos del led 


int32_t bufferLength; //Longitud del buffer
int32_t spo2; //valor de saturación de oxigeno
int32_t heartRate; //valor de ritmo cardiaco
//Las siguientes 2 variables solo las usaremos para depuración por puerto serial. Si la Oled no funciona, pero el sensor si, lo podremos saber por serial
int8_t validSPO2; //nos indica si es válida la lectura de spo2
int8_t validHeartRate; //nos indica si es válida la lectura de ritmo cardiaco

bool x=false;//bandera que usaremos para refrescar la pantalla solo una vez en caso de que haya que cambiar el texto impreso
bool error=false;//bandera que usaremos para saber si se ha dado un error de lectura
bool unaVez=true;//bandera que usaremos para refrescar la pantalla solo una vez en caso de que haya que cambiar el texto impreso



unsigned long FreqCardiacaMax=250;//valor máximo de frecuencia cardiaca que será considerado válido y no un error de lectura
unsigned long Spo2Max=100;//valor máximo de satuaración de oxígeno que será considerado válido y no un error de lectura

int EstadoBotonReset =1;//Apagado
int EstadoBotonLectura =1;//Apagado

//Función que usaremos para controlar el reseteo por botón
void ControlReset(){
    EstadoBotonReset=digitalRead(boton);
    if(EstadoBotonReset=!EstadoBotonReset){
      ESP.reset();
    }
}

//Función que usaremos para controlar la toma de datos mediante el pulsado de un botón
void ControlLectura(){
  EstadoBotonLectura=digitalRead(botonLectura);
  if(EstadoBotonLectura!=EstadoBotonLectura){
    EstadoBotonLectura=0;
  }
}

//Función para escribir texto por display
void escribir_texto(byte x_pos, byte y_pos, char *text, byte text_size) {
  display.setFixedFont(ssd1306xled_font6x8);///Seleccionamos una fuente
  if (text_size == 1) {
    display.printFixed (x_pos,  y_pos, text, STYLE_NORMAL);
  }
  else if (text_size == 2) {
    display.printFixedN (x_pos, y_pos, text, STYLE_NORMAL, FONT_SIZE_2X);
  }
}

void setup()
{
  Serial.begin(115200);//Iniciamos el puerto serie (línea de depuración)
  
  //Definimos los pines de los botones
  pinMode(boton, INPUT);
  pinMode(botonLectura, INPUT);
  
  display.begin();//inciamos el display
  display.fill(0x00);//Limpiamos el display
  escribir_texto(0,0, "Coloque el ",2);
  escribir_texto(0,16,"   dedo", 2);
  escribir_texto(0,32, " por favor", 2);

  //Inicializamos el sensor de pulso
  if (!SensorPulso.begin(Wire, I2C_SPEED_FAST)) //usa el puerto I2C por defecto, 400kHz 
  {
    Serial.println(F("No se ha encontrado el sensor. Revise las conexiones, por favor"));
    while (1);
  }
  
  

  Serial.println(F("Introduzca el dedo en el dispositivo"));


  byte ledBrightness = 60; //brillo del led. opciones: 0=apagado hasta 255=50mA
  byte sampleAverage = 4; //promedio de muestras. opciones: 1, 2, 4, 8, 16, 32
  byte ledMode = 2; //modo del led. opciones: 1 = rojo solo, 2 = rojo + IR, 3 = rojo + IR + verde(solo disponible en los max30105
  byte sampleRate = 100; //frecuencia de muestreo. opciones: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //ancho de pulso. opciones: 69, 118, 215, 411
  int adcRange = 4096; //rango del adc. opciones: 2048, 4096, 8192, 16384

  SensorPulso.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //configuramos el sensor con las opciones elegidas
}

void loop()
{
  ControlLectura();//Esperamos que se haya pulsado el botón (indicativo de que el dispositivo está ya colocado en el dedo)
  if(EstadoBotonLectura==0){//Cuando se pulsa..
    
  bufferLength = 100; //el buffer de longitud 100 almacena 4 segundos de muestras que se ejecutan a 25 muestras por segundo

  //Leemos las primeras 100 muestras y determina el rango de la señal.
  for (byte i = 0 ; i < bufferLength ; i++)
  {
    while (SensorPulso.available() == false) //mientras no tengamos un dato nuevo..
      SensorPulso.check(); //seguimos checkeando el sensor

    redBuffer[i] = SensorPulso.getRed();//Tomamos el valor leido del led rojo y lo almacenamos en el buffer correspondiente
    irBuffer[i] = SensorPulso.getIR();//tomamos el valor leido del led infrarrojo y lo almacenamos en el buffer correspondiente
    SensorPulso.nextSample(); //una vez almacenado, pasamos a la siguiente muestra

    //Mostramos los valores leidos del led rojo e infrarrojo. Solo para depurar
    Serial.print(F("red="));
    Serial.print(redBuffer[i], DEC);
    Serial.print(F(", ir="));
    Serial.println(irBuffer[i], DEC);

    ControlReset();//llamamos a la función que controla que si mientras estamos tomando muestras se pulsa el botón de reset, se resetea el micro
    
    if(!x){//Imprimimos una sola vez por pantalla que estamos procesando las lecturas
      display.fill(0x00);
      escribir_texto(0,0, "Procesando...", 1);
      x=true;
    }
  }
  
  //Calculamos la frecuencia cardiaca y la saturación de oxigeno una vez que tenemos las primeras 100 muestras (4 segundos de muestras)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  //A partir de este momento,  tomamos muestras continuamente del sensor. La frecuencia cardiaca y la saturación de oxígeno se calculan cada segundo
  while (1)
  {
    
    if(x){//Limpiamos una vez la pantalla
      display.fill(0x00);
      x=false;
    }
    //desplazamos los datos 25 a 100 a las posiciones 0 a 75 correspondientemente 
    for (byte i = 25; i < 100; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //tomamos las 25 últimas muestras antes de calcular la frecuencia cardiaca y la saturación de oxigeno
    for (byte i = 75; i < 100; i++)
    {
      ControlReset();//En todo momento estamos atentos por si se pulsa el botón de reset
      
      while (SensorPulso.available() == false) //mientras no tengamos una nueva muestra..
        SensorPulso.check(); //..seguimos comprobando el sensor

      redBuffer[i] = SensorPulso.getRed();//Guardamos las muestras en el buffer correspondiente
      irBuffer[i] = SensorPulso.getIR();//Guardamos las muestras en el buffer correspondiente
      SensorPulso.nextSample(); //una vez almacenados vamos a por la siguiente muestra

      //mandamos los valores de los LED´s y de la frecuencia cardiaca y de la saturación de oxigeno por puerto serial a modo de depuración
      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(irBuffer[i], DEC);

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);

      Serial.print(F(", HRvalid="));
      Serial.print(validHeartRate, DEC);

      Serial.print(F(", SPO2="));
      Serial.print(spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(validSPO2, DEC);

      //Vamos a convertir los valores de frecuencia y saturación (int) y los vamos a convertir a char. De esta manera podremos trabajar con la función escribir_texto()
      char hr[20];
      sprintf(hr, "%lu", heartRate);
      char Spo2[20];
      sprintf(Spo2, "%lu", spo2);
      
      //Comprobamos que la frecuencia y la saturación no superen los límites que le hemos marcado
      if(heartRate<=FreqCardiacaMax&&spo2<Spo2Max){
       if(error){//Si provenimos de imprimir un mensaje de error..
        display.fill(0x00);//..limpiamos la pantalla
        error=false;//bajamos la bandera de que venimos de un error
        unaVez=true;//Y levantamos la bandera de que ya hemos limpiado una vez la pantalla
       }
       //Escribimos los valores de frecuencia y saturación en la pantalla oled
       escribir_texto(0,0, "Freq. card. ",2);
       escribir_texto(40,20,hr,2);        
       escribir_texto(0,33, "Saturacion", 2);
       escribir_texto(40,48, Spo2,2);
      } 

      //Si los valores de frecuencia y saturación estan por encima de los límites que hemos establecidos
      else if(heartRate>FreqCardiacaMax||spo2>=Spo2Max){
        if(unaVez){//comprobamos si provenimos de mostrar el mensaje de error o de mostrar los datos
          display.fill(0x00);//Si venimos de mostrar los datos, hay que limpiar la pantalla antes de escribir el mensaje de error
          unaVez=false;//Bajamos la bandera          
        }

        escribir_texto(0,16," ERROR  DE ",2); 
        escribir_texto(0,40,"  LECTURA",2);
        error=true;
      }
    }

    //Tras haber guardado las 25 últimas muestras, recalculamos la frecuencia cardiaca y la saturación de oxigeno
    maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
  }
}
}

Muchas gracias @Surbyte por la ayuda. Un abrazo desde España!

Me dió mucho gusto colaborar contigo.