Meça a freqüência cardíaca e SpO2 com MAX30102

Tempo de leitura: 6 minutes

Olá, neste tutorial vamos fazer a interface do MAX30102: módulo de oximetria de pulso e monitor de frequência cardíaca com placa Arduino UNO, e então fazer um projeto para medir BPM usando este módulo + display OLED e um Buzzer.

BPM são os “batimentos por minuto” e ficam em torno de 65-75 em repouso para uma pessoa normal, o atletismo pode ter menos que isso, e a SpO2 é o nível de saturação de oxigênio, e para uma pessoa normal está acima de 95%.

O MAX30102 pode ser encontrado em diferentes módulos, tenho uma versão WAVGAT, não é problema desde que o IC seja MAX30102.

 

Componentes

Aqui estão as coisas que vou usar

  • Arduino UNO × 1
  • Adafruit OLED 128×32 × 1
  • Buzzer × 1
  • MAX30102 Oxímetro de pulso de alta sensibilidade e sensor de frequência cardíaca

 

Testes:

Os códigos que usei no tutorial são bastante claros e são apenas exemplos da biblioteca Sparkfun MAX3010x.

Para o código que fiz para o OLED e o Buzzer, é uma versão modificada do exemplo “HeartRate”, ele pede que você coloque o dedo no sensor.

Depois de colocar o dedo, mantenha a calma por um tempo, até começar a ouvir os “Bips” da campainha sincronizados com seus batimentos cardíacos ou a animação OLED sincronizada com ele, e então você pode ler um BPM correto.

N.B: No código eu realmente imprimo o BPM médio, uma vez que ele faz a média de 4 BPMs, é mais preciso dar um tempo.

 

Faça bitmaps para o OLED

O coração (pequeno) que você vê é uma imagem de bitmap, e toda vez que o sensor detecta uma batida cardíaca, nós mudamos para outra imagem de bitmap de coração (grande) por um tempo e dá a impressão de um coração batendo junto com um bipe da campainha.

Aqui estão os dois bitmaps no código que chamamos mais tarde no código

Para fazer isso, procure uma imagem (preto com fundo branco) para o que você quiser ver na tela só não se esqueça do tamanho, o que estou usando é 128×32 px e as fotos são menores que isso (32×32 px) e (24×21 px)

Baixe o LCD Assistant e abra-o (alguns passos abaixo)

E aqui estão seus “números”

E aqui está como chamei no código

display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE);

Que significa

display.drawBitmap(Starting x pos, Starting y pos, Bitmap name, Width, Height, Color);

E como você pode ver no código, um é chamado quando um dedo é detectado e o outro quando um batimento cardíaco é detectado.

E aqui você vai fazer o que quiser.

 

Esquemas

Wiring_MAX30102_OLED_Buzzer
Ambos os módulos têm interface i²c, se você estiver usando uma campainha de 2 pinos (-) com GND e (+) com um resistor, então D3

 

Código

/* Este código funciona com MAX30102 + 128x32 OLED i2c + Buzzer e Arduino UNO
 * Mostra o BPM médio na tela, com uma animação e um som de campainha
 * toda vez que um pulso do coração é detectado
 * É uma versão modificada do exemplo da biblioteca HeartRate
 * Consulte www.surtrtech.com para mais detalhes ou o canal SurtrTech no YouTube
 */
  
#include <Adafruit_GFX.h>        //OLED libraries
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include "MAX30105.h"           //MAX3010x library
#include "heartRate.h"          //Algoritmo de cálculo de freqüência cardíaca

MAX30105 particleSensor;

const byte RATE_SIZE = 4; // Aumente para obter mais média. 4 é bom.
byte rates[RATE_SIZE]; // Matriz de freqüência cardíaca
byte rateSpot = 0;
long lastBeat = 0; // Hora em que ocorreu a última batida
float beatsPerMinute;
int beatAvg;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET    -1 // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Declarando o nome de exibição (display)

static const unsigned char PROGMEM logo2_bmp[] =
{ 0x03, 0xC0, 0xF0, 0x06, 0x71, 0x8C, 0x0C, 0x1B, 0x06, 0x18, 0x0E, 0x02, 0x10, 0x0C, 0x03, 0x10,              // Logo2 e Logo3 são duas imagens bmp que são exibidas no OLED se chamadas
0x04, 0x01, 0x10, 0x04, 0x01, 0x10, 0x40, 0x01, 0x10, 0x40, 0x01, 0x10, 0xC0, 0x03, 0x08, 0x88,
0x02, 0x08, 0xB8, 0x04, 0xFF, 0x37, 0x08, 0x01, 0x30, 0x18, 0x01, 0x90, 0x30, 0x00, 0xC0, 0x60,
0x00, 0x60, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x04, 0x00,  };

static const unsigned char PROGMEM logo3_bmp[] =
{ 0x01, 0xF0, 0x0F, 0x80, 0x06, 0x1C, 0x38, 0x60, 0x18, 0x06, 0x60, 0x18, 0x10, 0x01, 0x80, 0x08,
0x20, 0x01, 0x80, 0x04, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x08, 0x03,
0x80, 0x00, 0x08, 0x01, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1C, 0x01, 0x80, 0x00, 0x14, 0x00,
0x80, 0x00, 0x14, 0x00, 0x80, 0x00, 0x14, 0x00, 0x40, 0x10, 0x12, 0x00, 0x40, 0x10, 0x12, 0x00,
0x7E, 0x1F, 0x23, 0xFE, 0x03, 0x31, 0xA0, 0x04, 0x01, 0xA0, 0xA0, 0x0C, 0x00, 0xA0, 0xA0, 0x08,
0x00, 0x60, 0xE0, 0x10, 0x00, 0x20, 0x60, 0x20, 0x06, 0x00, 0x40, 0x60, 0x03, 0x00, 0x40, 0xC0,
0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x30, 0x0C, 0x00,
0x00, 0x08, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x00  };


void setup() {  
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Iniciar o display OLED
  display.display();
  delay(3000);
  // Initialize sensor
  particleSensor.begin(Wire, I2C_SPEED_FAST); // Use a porta I2C padrão, velocidade de 400 kHz
  particleSensor.setup(); // Configure o sensor com as configurações padrão
  particleSensor.setPulseAmplitudeRed(0x0A); // Coloque o LED vermelho em baixo para indicar que o sensor está funcionando

}

void loop() {
 long irValue = particleSensor.getIR();    // A leitura do valor IR nos permitirá saber se há um dedo no sensor ou não
                                           // Também detectando um batimento cardíaco
 if(irValue > 7000){                                           // Se um dedo for detectado
    display.clearDisplay();                                   // Limpar a tela
    display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE);       // Desenhe a primeira imagem bmp (pequeno coração)
    display.setTextSize(2);                                   // Perto dele exibe o BPM médio, você pode exibir o BPM se quiser
    display.setTextColor(WHITE); 
    display.setCursor(50,0);                
    display.println("BPM");             
    display.setCursor(50,18);                
    display.println(beatAvg); 
    display.display();
    
  if (checkForBeat(irValue) == true)                        // Se um batimento cardíaco for detectado
  {
    display.clearDisplay();                                //Limpar a tela
    display.drawBitmap(0, 0, logo3_bmp, 32, 32, WHITE);    //Desenhe a segunda imagem (coração maior)
    display.setTextSize(2);                                //E ainda exibe o BPM médio
    display.setTextColor(WHITE);             
    display.setCursor(50,0);                
    display.println("BPM");             
    display.setCursor(50,18);                
    display.println(beatAvg); 
    display.display();
    tone(3,1000);                                        //E soar a campainha por 100ms você pode diminuir vai ficar melhor
    delay(100);
    noTone(3);                                          //Desative a campainha para ter o efeito de um "bip"
    //We sensed a beat!
    long delta = millis() - lastBeat;                   //Medir a duração entre duas batidas
    lastBeat = millis();

    beatsPerMinute = 60 / (delta / 1000.0);           //Calculando o BPM

    if (beatsPerMinute < 255 && beatsPerMinute > 20)  //Para calcular a média, armazenamos alguns valores (4) e, em seguida, fazemos algumas contas para calcular a média
    {
      rates[rateSpot++] = (byte)beatsPerMinute; //Armazene esta leitura na matriz
      rateSpot %= RATE_SIZE; //Variável de embrulho

      // Faça a média das leituras
      beatAvg = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        beatAvg += rates[x];
      beatAvg /= RATE_SIZE;
    }
  }

  }
  if (irValue < 7000){       // Se nenhum dedo for detectado, ele informa ao usuário e coloca o BPM médio em 0 ou ele será armazenado para a próxima medida
     beatAvg=0;
     display.clearDisplay();
     display.setTextSize(1);                    
     display.setTextColor(WHITE);             
     display.setCursor(30,5);                
     display.println("Please Place "); 
     display.setCursor(30,15);
     display.println("your finger ");  
     display.display();
     noTone(3);
  }
}