Pulse Sensor

Hi, I'm doing my final project now and I got stuck on to get an average bpm to show it on LCD.
Do anyone knows the code to calculate the bpm and make an average?

I also couldn't figure out how to make bpm = 0 when there's no finger attached.

Thanks guys

What kind of pulse sensor are you using? What did you find when you googled Arduino and that sensor?

That one , and it frustrated me that when no finger is attached , there's still bpm detect and show on
my lcd or serial monitor.

I used the original code from this link GitHub - WorldFamousElectronics/PulseSensor_Amped_Arduino: PulseSensor Arduino code for BPM and Processing-Visualizer , and I add some code for the output on my lcd. I heard that everybody uses that code too.

I still find no code that give me about how to put an Average BPM after ten BPM detected or more.

Thanks , I really appreciated your help.

I still find no code that give me about how to put an Average BPM after ten BPM detected or more.

If I gave you a list of numbers, could you compute the average? How would YOU do it?

If you said "add the 10 numbers and divide the result by 10", you are well on your way to writing the code. If not, then you said the wrong thing.

If you are detecting a beat when your finger is not on the sensor, you are doing something wrong. If you are not clearing the display when no beat has been detected for some period of time, you are doing something else wrong.

But, you've shown no code, and no evidence of what exactly the problem is, so it is very hard to help you.


This is my code :

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int pulsePin = 0;
int blinkPin = 13;
int fadePin = 5;
int fadeRate = 0;

// 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.
volatile int detik=0, ms2=0;

// 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

void setup(){
pinMode(blinkPin,OUTPUT);
pinMode(fadePin,OUTPUT);
interruptSetup();

//setup LCD
lcd.begin (16,2);
lcd.setCursor (0,0);
lcd.print ("Synchronizing.....");
delay(5000);
lcd.clear();
detik=0;
}

void loop()
{

if (QS == true)
{
fadeRate = 255;
lcd.setCursor(0,0);
lcd.print ("BPM = ");
lcd.setCursor(6,0);
lcd.print (BPM);
lcd.print (" ");
QS = false;
}
//else { lcd.setCursor(0,0);
// lcd.print ("BPM = 0 ");}

lcd.setCursor(0,1);
lcd.print ("Time Passed = ");
lcd.setCursor(14,1);
lcd.print(detik);

ledFadeToBeat();
delay(20);
}

void ledFadeToBeat(){
fadeRate -= 15;
fadeRate = constrain(fadeRate,0,255);
analogWrite(fadePin,fadeRate);
}

This is the interrupt

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 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
}

// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE.
// Timer 2 makes sure that we take a reading every 2 miliseconds
ISR(TIMER2_COMPA_vect){ // triggered when Timer2 counts to 124
//Counter Up
ms2++;
if(ms2>500)
{
detik++;
ms2=0;
}
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 *= 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 = rate[i+1]; // and drop the oldest IBI value_
    _ runningTotal += rate*; // 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*
    I really appreciated you want to reply to me :slight_smile:_
 if (QS == true)
  {       
    fadeRate = 255;
    lcd.setCursor(0,0);
    lcd.print ("BPM = ");
    lcd.setCursor(6,0);
    lcd.print (BPM);
    lcd.print ("    ");     
    QS = false;   
  }   
//else { lcd.setCursor(0,0);
  //        lcd.print ("BPM = 0 ");}

So, if the device detects a heart beat, show the heart rate. Otherwise, leave the last measured rate displayed. Why are the last two lines commented out?

I don't use the two lines, I want to print bpm = 0 in the lcd , but it doesn't works, so I just made it a comment.

I already made it to print the bpm on the lcd, but when there's no finger the sensor print nonsense heartbeat

I think PaulS has answered your question but you could easily prove whether it's the sensor or your code (shock, horror) by displaying to the Serial Monitor the value read from the sensor.

If that is correct then it's your code writing to the LCD that is faulty. If the sensor still gives a reading when no pulse is present then you will never clear the LCD display either!

You've complicated your problem by not identifying where the problem exists (well, PaulS has but you have not followed his nudges).