In this article, we are going to interface a Pulse Sensor with Arduino. The pulse sensor we are going to use is a plug and play heart rate sensor. This sensor is quite easy to use and operate. Place your finger on top of the sensor and it will sense the heartbeat by measuring the change in light from the expansion of capillary blood vessels.

Pin Out – Pulse Sensor

The pulse sensor has three pins which are as described below:

  • GND: Ground Pin
  • VCC: 5V or 3V Pin
  • A0: Analog Pin

There is also a LED in the center of this sensor module which helps in detecting the heartbeat. Below the LED, there is a noise elimination circuitry which is supposed to keep away the noise from affecting the readings.

heartbeat sensor

Working – Pulse Sensor

When a heartbeat occurs blood is pumped through the human body and gets squeezed into the capillary tissues. The volume of these capillary tissues increases as a result of the heartbeat. But in between the heartbeats (the time  between two consecutive heartbeats,) this volume inside capillary tissues decreases. This change in volume between the heartbeats affects the amount of light that will transmit through these tissues. This change is very small but we can measure it with the help of Arduino.

The pulse sensor module has a light which helps in measuring the pulse rate. When we place the finger on the pulse sensor, the light reflected will change based on the volume of blood inside the capillary blood vessels. During a heartbeat, the volume inside the capillary blood vessels will be high. This affects the reflection of light and the light reflected at the time of a heartbeat will be less compared to that of the time during which there is no heartbeat (during the period of time when there is no heartbeat or the time period in between heartbeats, the volume inside the capillary vessels will be lesser. This will lead higher reflection of light). This variation in light transmission and reflection can be obtained as a pulse from the ouptput of pulse sensor. This pulse can be then coditioned to measure heartbeat and then programmed accordingly to read as heartbeat count.

Circuit Diagram – Pulse Sensor to Arduino

Pulse Sensor Arduino

Connect the pulse sensor with Arduino as follows

  • GND pin of pulses sensor to GND of Arduino
  • VCC of pulse sensor to 5V of Arduino
  • A0 of pulse sensor to A0 of Arduino

After that, connect the LED to pin 13 and GND of Arduino as shown in the figure below. The LED will blink according to the heart beat.

Code/Program 

int sensor_pin = 0;                

int led_pin = 13;                  

volatile int heart_rate;          

volatile int analog_data;              

volatile int time_between_beats = 600;            

volatile boolean pulse_signal = false;    

volatile int beat[10];         //heartbeat values will be sotred in this array    

volatile int peak_value = 512;          

volatile int trough_value = 512;        

volatile int thresh = 525;              

volatile int amplitude = 100;                 

volatile boolean first_heartpulse = true;      

volatile boolean second_heartpulse = false;    

volatile unsigned long samplecounter = 0;   //This counter will tell us the pulse timing

volatile unsigned long lastBeatTime = 0;



void setup()

{

  pinMode(led_pin,OUTPUT);        

  Serial.begin(115200);           

  interruptSetup();                  

}



void loop()

{ 

      Serial.print("BPM: ");

      Serial.println(heart_rate);

      delay(200); //  take a break

}



void interruptSetup()

{    

  TCCR2A = 0x02;  // This will disable the PWM on pin 3 and 11

  OCR2A = 0X7C;   // This will set the top of count to 124 for the 500Hz sample rate

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

  TIMSK2 = 0x02;  // This will enable interrupt on match between OCR2A and Timer

  sei();          // This will make sure that the global interrupts are enable

}


ISR(TIMER2_COMPA_vect)

{ 

  cli();                                     

  analog_data = analogRead(sensor_pin);            

  samplecounter += 2;                        

  int N = samplecounter - lastBeatTime;      


  if(analog_data < thresh && N > (time_between_beats/5)*3)

    {     

      if (analog_data < trough_value)

      {                       

        trough_value = analog_data;

      }

    }


  if(analog_data > thresh && analog_data > peak_value)

    {        

      peak_value = analog_data;

    }                          



   if (N > 250)

  {                            

    if ( (analog_data > thresh) && (pulse_signal == false) && (N > (time_between_beats/5)*3) )

      {       

        pulse_signal = true;          

        digitalWrite(led_pin,HIGH);

        time_between_beats = samplecounter - lastBeatTime;

        lastBeatTime = samplecounter;     



       if(second_heartpulse)

        {                        

          second_heartpulse = false;   

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

          {            

            beat[i] = time_between_beats; //Filling the array with the heart beat values                    

          }

        }


        if(first_heartpulse)

        {                        

          first_heartpulse = false;

          second_heartpulse = true;

          sei();            

          return;           

        }  


      word runningTotal = 0;  


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

        {               

          beat[i] = beat[i+1];

          runningTotal += beat[i];

        }


      beat[9] = time_between_beats;             

      runningTotal += beat[9];   

      runningTotal /= 10;        

      heart_rate = 60000/runningTotal;

    }                      

  }




  if (analog_data < thresh && pulse_signal == true)

    {  

      digitalWrite(led_pin,LOW); 

      pulse_signal = false;             

      amplitude = peak_value - trough_value;

      thresh = amplitude/2 + trough_value; 

      peak_value = thresh;           

      trough_value = thresh;

    }


  if (N > 2500)

    {                          

      thresh = 512;                     

      peak_value = 512;                 

      trough_value = 512;               

      lastBeatTime = samplecounter;     

      first_heartpulse = true;                 

      second_heartpulse = false;               

    }


  sei();                                

}

Code Explanation

In the interrupt function, we have set up a timer that will throw an interrupt every other millisecond which gives us a sample rate of 500Hz and a beat to beat timing resolution of 2mS. This will disable the PWM output on the pin 3 and 11 and also will disable the tone() function. sei() ensures that the global interrupts are enabled.

TCCR2A = 0x02; 

 TCCR2B = 0x06; 

 OCR2A = 0X7C;  

 TIMSK2 = 0x02; 

 sei();

The following function runs after every 2mS. It takes reading from the pulse sensor every 2mS and increments the sample counter. The sample counter is used to keep track of the time and the N variable is used to avoid the noise.

ISR(TIMER2_COMPA_vect)

{   cli();                                     

  analog_data = analogRead(sensor_pin);             

  samplitudeleCounter += 2;                        

  int N = sampleCounter - lastBeatTime;

The following two loops will keep track of the highest and lowest values. The thresh variable is initialized at 512 which is the middle point of the analog point. This variable is used to keep track of the middle point.

if(analog_data < thresh && N > (time_between_beats/5)*3)

    {           if (analog_data < trough_value)

      {                      

        trough_value = analog_data;

     }    }

The following function will look for a heartbeat. If the output reading has passed the thresh value and 3/5 of the last time between the beats has passed, then the pulse signal will become true and the LED will become high. Then we update the variable ‘lastbeattime’ by calculating the time since the last beat.

if (N > 250)
  {                        

    if ( (analog_data > thresh) && (pulse_signal == false) && (N > (time_between_beats/5)*3) )

      {               pulse_signal = true;          

        digitalWrite(led_pin,HIGH);

        time_between_beats = sampleCounter - lastBeatTime;

        lastBeatTime = sampleCounter;

In the start, we have initialized the first beat as true and the second beat as false. So, if we have the first reading, then it gets kicked by return. While in the second reading, we seed the rate[] array which will help us in calculating the BPM. The BPM is actually derived from the average of last 10 time between beat values.

if(second_heartpulse)

        {    second_heartpulse = false;   

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

          {      beat[i] = time_between_beats; //Filling the array with the heart beat values                    

          }         }

        if(first_heartpulse)

        {                       

          first_heartpulse = false;

          second_heartpulse = true;

          sei();           

          return;           

        }

 

Then we shifted the data from the rate[] array to the ‘runningtotal’ variable. The old value will fall out and the fresh value will keep coming in every time the function will run. Then we averaged the array and calculated the BPM.

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

        {               

          beat[i] = beat[i+1];

          runningTotal += beat[i];

        }

      beat[9] = time_between_beats;             

      runningTotal += beat[9];   

      runningTotal /= 10;        

      heart_rate = 60000/runningTotal;

We calculated the beat when the pulse value was greater than the thresh value. When the pulse value is less than the thresh value, then we assume that the pulse is over and the LED will go down. After that, we update the new 50% mark for the thresh variable.

if (analog_data < thresh && pulse_signal == true)

    {  

      digitalWrite(led_pin,LOW); 

      pulse_signal = false;             

      amplitude = peak_value - trough_value;

      thresh = amplitude/2 + trough_value; 

      peak_value = thresh;           

      trough_value = thresh;

    }

If we found no beat for about 2.5mS, then the variables that we used to calculate the heart beat will be given the initial values.

if (N > 2500)

    {                          

      thresh = 512;                     

      peak_value = 512;                  

      trough_value = 512;               

      lastBeatTime = sampleCounter;     

      first_heartpulse = true;                 

      second_heartpulse = false;               

    }

So here we finish our tutorial on Interfacing Pulse Sensor to Arduino. If you have any doubts, please ask in comments.

Photographs of the Project

Demonstration Video

Author

17 Comments

  1. Anshul Chopra

    hi .. i run your code but i am not getting accurate value of BPM like it showing around 250 .Can you justify this.

  2. Chetan mathematics

    thanks allot u provided project program it runs successfully.
    i request can u make video actually how its working when did it. and by that i can compare my project.

  3. hey my BMP is coming around 160 to 190. What changes should I make in the code to get correct readings.

  4. yuvarani

    what is that peak,thresh,trough values?how did you fixed that values?

  5. Salini Singh Rajput

    Hello!! I did exactly the same way that is mentioned above. But the serial monitor shows irrelevant output.
    Is the code logically error free? Awaiting your response.

  6. vrushali harad

    can anyone explain calculation of the program mentioned above

    • Hello,
      how can I obtain more intensity from the LEDs and how to make the LEDs to be on for a longer time?

      Thanks in advice,
      Tommaso.

  7. ganesh Thakar

    Hii,
    i used the same code for the Pulse rate sensor,but when im compiling this code i get error message i.e.
    exit status 3
    Error compiling for board Arduino/Genuino Uno.
    what should i do now please suggest?

    Thanks in advance.

    • suchismita mohanty

      1.why we have taken thresh value as 525 ,peak,trough value as 512
      2.what is the unit of time between beats ?why you have taken time between beats as 600?
      3.why amplitude is 100?
      4.what is first_heartpulse is true and second _heartpulse is false?
      5.what is pulse timing?
      6.what is last beat time?how can you measure this?
      7.why there is a need of interruptSetup()? without using it can we work with pulse rate sensor?

  8. paul Machin

    interruptSetup() function not working. Says “not declared in the scope” please help. thanks