Home ARDUINO How to Build DIY Heart Rate Monitor with Arduino

How to Build DIY Heart Rate Monitor with Arduino

In this article, we will discuss pulse sensor and Arduino Uno and build a full responsive Heart Rate Monitor using character LCD, Amped Pulse Sensor Amped and Arduino Compatible Plug and Play Heart Rate Sensors.

It can be used by students, artists, athletes, manufacturers, games and mobile developers who can easily incorporate live heart rate data into their projects.

The pulse sensor adds amplification and noise cancellation circuitry to the hardware. Obviously faster and easier to obtain reliable pulse readings. Pulse Sensor Amps can use 3V or 5V Arduino.

I am going to share a project that is very handy people can make at home. You can monitor your heart rate at home and I want to share it on the guide and on youtube so that people can have a cheap DIY reliable heart rate monitor. Go to the next step in schematics, codes, and parts lists.

Specification of project

Diameter = 0.625″ (~16mm)

Overall thickness = 0.125″ (~3mm)

Working Voltage = 3V to 5V

Working Current = ~4mA at 5V

Collect the Hardware

For this project, you just need few things such as

  • Arduino Uno Board.

How to Build DIY Heart Rate Monitor with Arduino

  • Pulse Sensor Arduino

How to Build DIY Heart Rate Monitor with Arduino

  • Jumper Wires

How to Build DIY Heart Rate Monitor with Arduino

  • LCD

How to Build DIY Heart Rate Monitor with Arduino

  • Potentiometer 10K
  • 2 LEDs
  • Breadboard

How to Build DIY Heart Rate Monitor with Arduino

Wired Up Everything

Connect the wired as mention below

How to Build DIY Heart Rate Monitor with Arduino

How to Build DIY Heart Rate Monitor with Arduino

Connect Pulse Sensor to Arduino Uno Board as following:

  • to +5V
  • to GND

S tO A0

Connect LCD to Arduino Uno Board as following:

VSS to GND

VDD to +5

RS to 12

RW to GND

E to D11

D4 to D5

D5 to D4

D6 to D3

D7 to D2

A/VSS to +5V

K/VDD to GND

Connect 10K Potentiometer to LCD as following (refer image for potentiometer pinout) :

GND to GND

Data to v0

VCC to +5V

Connect LED to Arduino as follows:

LED1 (RED, blinkPin) to D13

LED2 (GREEN, fadeRate) to D8

Final Connection

So final connection will look like this

How to Build DIY Heart Rate Monitor with Arduino

How to Build DIY Heart Rate Monitor with Arduino

Upload the Source Code

After the wired up everything connects it up to your computer upload the source code Arduino so if you are very new to Arduino programming then I will suggest you to read my previous article for beginner, here Beginner guide for Arduino

Add the zip library from here Github

Upload code via Arduino ide

How to Build DIY Heart Rate Monitor with Arduino

How to Build DIY Heart Rate Monitor with Arduino

////////////////Technical Ustaad /////////////////////////

#include <LiquidCrystal.h>

 

//  Variables

int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0

int blinkPin = 13;                // pin to blink led at each beat

int fadePin = 8;                  // pin to do fancy classy fading blink at each beat

int fadeRate = 0;                 // used to fade LED on with PWM on fadePin

 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

 

// Volatile Variables, used in the interrupt service routine!

volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS

volatile int Signal;                // holds the incoming raw data

volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded!

volatile boolean Pulse = false;     // “True” when User’s live heartbeat is detected. “False” when not a “live beat”.

volatile boolean QS = false;        // becomes true when Arduoino finds a beat.

 

// Regards Serial OutPut  — Set This Up to your needs

static boolean serialVisual = true;   // Set to ‘false’ by Default.  Re-set to ‘true’ to see Arduino Serial Monitor ASCII Visual Pulse

 

volatile int rate[10];                      // array to hold last ten IBI values

volatile unsigned long sampleCounter = 0;          // used to determine pulse timing

volatile unsigned long lastBeatTime = 0;           // used to find IBI

volatile int P = 512;                      // used to find peak in pulse wave, seeded

volatile int T = 512;                     // used to find trough in pulse wave, seeded

volatile int thresh = 525;                // used to find instant moment of heart beat, seeded

volatile int amp = 100;                   // used to hold amplitude of pulse waveform, seeded

volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM

volatile boolean secondBeat = false;      // used to seed rate array so we startup with reasonable BPM

 

void setup()

{

  pinMode(blinkPin,OUTPUT);         // pin that will blink to your heartbeat!

  pinMode(fadePin,OUTPUT);          // pin that will fade to your heartbeat!

  Serial.begin(115200);             // we agree to talk fast!

  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS

                                    // IF YOU ARE POWERING The Pulse Sensor AT VOLTAGE LESS THAN THE BOARD VOLTAGE,

                                    // UN-COMMENT THE NEXT LINE AND APPLY THAT VOLTAGE TO THE A-REF PIN

                                    //   analogReference(EXTERNAL);  

}

 

 

//  Where the Magic Happens

void loop()

{

   serialOutput(); 

  

  if (QS == true) // A Heartbeat Was Found

    {    

      // BPM and IBI have been Determined

      // Quantified Self “QS” true when arduino finds a heartbeat

      fadeRate = 255; // Makes the LED Fade Effect Happen, Set ‘fadeRate’ Variable to 255 to fade LED with pulse

      serialOutputWhenBeatHappens(); // A Beat Happened, Output that to serial.    

      QS = false; // reset the Quantified Self flag for next time   

    }

    

  ledFadeToBeat(); // Makes the LED Fade Effect Happen

  delay(20); //  take a break

}

 

void ledFadeToBeat()

{

   fadeRate -= 15;                         //  set LED fade value

   fadeRate = constrain(fadeRate,0,255);   //  keep LED fade value from going into negative numbers!

   analogWrite(fadePin,fadeRate);          //  fade LED

}

 

void interruptSetup()

{    

  // Initializes Timer2 to throw an interrupt every 2mS.

  TCCR2A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE

  TCCR2B = 0x06;     // DON’T FORCE COMPARE, 256 PRESCALER

  OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE

  TIMSK2 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A

  sei();             // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED     

}

 

void serialOutput()

{   // Decide How To Output Serial.

 if (serialVisual == true)

  { 

     arduinoSerialMonitorVisual(‘-‘, Signal);   // goes to function that makes Serial Monitor Visualizer

  }

 else

  {

      sendDataToSerial(‘S’, Signal);     // goes to sendDataToSerial function

   }       

}

 

void serialOutputWhenBeatHappens()

{   

 if (serialVisual == true) //  Code to Make the Serial Monitor Visualizer Work

   {           

     Serial.print(“*** Heart-Beat Happened *** “);  //ASCII Art Madness

     Serial.print(“BPM: “);

     Serial.println(BPM);

     lcd.clear();

     lcd.print(“BPM: “);

     lcd.print(BPM);

   }

 else

   {

     sendDataToSerial(‘B’,BPM);   // send heart rate with a ‘B’ prefix

     sendDataToSerial(‘Q’,IBI);   // send time between beats with a ‘Q’ prefix

   }  

}

 

void arduinoSerialMonitorVisual(char symbol, int data )

{   

  const int sensorMin = 0;      // sensor minimum, discovered through experiment

  const int sensorMax = 1024;    // sensor maximum, discovered through experiment

  int sensorReading = data; // map the sensor range to a range of 12 options:

  int range = map(sensorReading, sensorMin, sensorMax, 0, 11);

  // do something different depending on the

  // range value:

  switch (range)

  {

    case 0:    

      Serial.println(“”);     /////ASCII Art Madness

      break;

    case 1:  

      Serial.println(“—“);

      break;

    case 2:   

      Serial.println(“——“);

      break;

    case 3:   

      Serial.println(“———“);

      break;

    case 4:  

      Serial.println(“————“);

      break;

    case 5:  

      Serial.println(“————–|-“);

      break;

    case 6:  

      Serial.println(“————–|—“);

      break;

    case 7:  

      Serial.println(“————–|——-“);

      break;

    case 8: 

      Serial.println(“————–|———-“);

      break;

    case 9:   

      Serial.println(“————–|—————-“);

      break;

    case 10:  

      Serial.println(“————–|——————-“);

      break;

    case 11:  

      Serial.println(“————–|———————–“);

      break;

  }

}

 

 

void sendDataToSerial(char symbol, int data )

{

   Serial.print(symbol);

   Serial.println(data);               

}

 

ISR(TIMER2_COMPA_vect) //triggered when Timer2 counts to 124

  cli();                                      // disable interrupts while we do this

  Signal = analogRead(pulsePin);              // read the Pulse Sensor

  sampleCounter += 2;                         // keep track of the time in mS with this variable

  int N = sampleCounter – lastBeatTime;       // monitor the time since the last beat to avoid noise

                                              //  find the peak and trough of the pulse wave

  if(Signal < thresh && N > (IBI/5)*3) // avoid dichrotic noise by waiting 3/5 of last IBI

    {     

      if (Signal < T) // T is the trough

      {                       

        T = Signal; // keep track of lowest point in pulse wave

      }

    }

 

  if(Signal > thresh && Signal > P)

    {          // thresh condition helps avoid noise

      P = Signal;                             // P is the peak

    }                                        // keep track of highest point in pulse wave

 

  //  NOW IT’S TIME TO LOOK FOR THE HEART BEAT

  // signal surges up in value every time there is a pulse

  if (N > 250)

  {                                   // avoid high frequency noise

    if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) )

      {       

        Pulse = true;                               // set the Pulse flag when we think there is a pulse

        digitalWrite(blinkPin,HIGH);                // turn on pin 13 LED

        IBI = sampleCounter – lastBeatTime;         // measure time between beats in mS

        lastBeatTime = sampleCounter;               // keep track of time for next pulse

 

        if(secondBeat)

        {                        // if this is the second beat, if secondBeat == TRUE

          secondBeat = false;                  // clear secondBeat flag

          for(int i=0; i<=9; i++) // seed the running total to get a realisitic BPM at startup

          {            

            rate[i] = IBI;                     

          }

        }

 

        if(firstBeat) // if it’s the first time we found a beat, if firstBeat == TRUE

        {                        

          firstBeat = false;                   // clear firstBeat flag

          secondBeat = true;                   // set the second beat flag

          sei();                               // enable interrupts again

          return;                              // IBI value is unreliable so discard it

        }  

      // keep a running total of the last 10 IBI values

      word runningTotal = 0;                  // clear the runningTotal variable   

 

      for(int i=0; i<=8; i++)

        {                // shift data in the rate array

          rate[i] = rate[i+1];                  // and drop the oldest IBI value

          runningTotal += rate[i];              // add up the 9 oldest IBI values

        }

 

      rate[9] = IBI;                          // add the latest IBI to the rate array

      runningTotal += rate[9];                // add the latest IBI to runningTotal

      runningTotal /= 10;                     // average the last 10 IBI values

      BPM = 60000/runningTotal;               // how many beats can fit into a minute? that’s BPM!

      QS = true;                              // set Quantified Self flag

      // QS FLAG IS NOT CLEARED INSIDE THIS ISR

    }                      

  }

 

  if (Signal < thresh && Pulse == true)

    {   // when the values are going down, the beat is over

      digitalWrite(blinkPin,LOW);            // turn off pin 13 LED

      Pulse = false;                         // reset the Pulse flag so we can do it again

      amp = P – T;                           // get amplitude of the pulse wave

      thresh = amp/2 + T;                    // set thresh at 50% of the amplitude

      P = thresh;                            // reset these for next time

      T = thresh;

    }

 

  if (N > 2500)

    {                           // if 2.5 seconds go by without a beat

      thresh = 512;                          // set thresh default

      P = 512;                               // set P default

      T = 512;                               // set T default

      lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date       

      firstBeat = true;                      // set these to avoid noise

      secondBeat = false;                    // when we get the heartbeat back

    }

 

  sei();                                   // enable interrupts when youre done!

}// end isr

/////////////////////////////////////////////////////////

 

DONE!
Now just open the terminal of Arduino UNO by pressing “Ctrl”+ “Shift” + “M” keys simultaneously in 115200 port as shown in figure

How to Build DIY Heart Rate Monitor with Arduino

How to Build DIY Heart Rate Monitor with Arduino

 

NOTE : DO NOT connect the Pulse Sensor to your body while your computer or arduino is being powered from the mains AC line. That goes for charging laptops and DC power supplies.

How to Build DIY Heart Rate Monitor with Arduino

How to Build DIY Heart Rate Monitor with Arduino

Here is the test video for this project

Build DYI Heart Rate Monitor with Arduino UNO and pulse sensor