3

I have found code that can blink an LED on Arduino according to Heart Beat. I am using AD8232 as a sensor for Heart Rate.

Code for it is:

//  Variables
int PulseSensorPurplePin = 0; // Pulse Sensor PURPLE WIRE connected to ANALOG PIN 0
int LED13 = 13; // The on-board Arduino LED
int Signal; // holds the incoming raw data. Signal value can range from 0-1024
int Threshold = 550; // Determine which Signal to "count as a beat", and which to ingore.

void setup() {
  pinMode(LED13, OUTPUT); // pin that will blink to your heartbeat
  Serial.begin(9600); // Sets up Serial Communication at certain speed.
}

void loop() {
  Signal = analogRead(PulseSensorPurplePin); // Read the PulseSensor's value.
  // Assign this value to the "Signal" variable.
  Serial.println(Signal); // Send the Signal value to Serial Plotter.
  if(Signal > Threshold) {
    // If the signal is above "550", then "turn-on" Arduino's on-Board LED.
    digitalWrite(LED13, HIGH);
  } else {
    digitalWrite(LED13, LOW); //  Else, the signal must be below "550", so "turn-off" this LED.
  }
  delay(10);
}

My question is: How can I get BPM?

Edited below:

Is this code for BPM correct?

int x = 0;
int LastTime = 0;
bool BPMTiming = false;
bool BeatComplete = false;
int BPM = 0;    
#define UpperThreshold 518
#define LowerThreshold 490    
int LED13 = 44; // The on-board Arduino LED
int Signal; // holds the incoming raw data. Signal value can range from 0-1024

void setup() {
  pinMode(LED13, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int value = analogRead(0);
  if (value > UpperThreshold) {
    if (BeatComplete) {
      BPM = millis() - LastTime;
      BPM = int(60 / (float(BPM) / 1000));
      BPMTiming = false;
      BeatComplete = false;
    }
    if (BPMTiming == false) {
      LastTime = millis();
      BPMTiming = true;
    }
  }
  if ((value < LowerThreshold) & (BPMTiming))
    BeatComplete = true;
    // display bpm
  Serial.print(BPM);
  Serial.println(" BPM");
  x++;
  Signal = analogRead(0); // Read the PulseSensor's value.
  // Assign this value to the "Signal" variable.
  if (Signal > UpperThreshold) {
    // If the signal is above "550", then "turn-on" Arduino's on-Board LED.
    digitalWrite(LED13, HIGH);
  } else {
    digitalWrite(LED13, LOW); //  Else, the signal must be below "550", so "turn-off" this LED.
  }
}
0

1 Answer 1

2

If you know the interval between heart beats, you can calculate the frequency using the formula: frequency = 1 / time. Now if you take the frequency and multiply it by 60, you should get BPM.

I don't have one of the sensors you are using so I connected a potentiometer to pin A0 to test this code.

    int UpperThreshold = 518;
    int LowerThreshold = 490;
    int reading = 0;
    float BPM = 0.0;
    bool IgnoreReading = false;
    bool FirstPulseDetected = false;
    unsigned long FirstPulseTime = 0;
    unsigned long SecondPulseTime = 0;
    unsigned long PulseInterval = 0;

    void setup(){
      Serial.begin(9600);
    }

    void loop(){

      reading = analogRead(0); 

      // Heart beat leading edge detected.
      if(reading > UpperThreshold && IgnoreReading == false){
        if(FirstPulseDetected == false){
          FirstPulseTime = millis();
          FirstPulseDetected = true;
        }
        else{
          SecondPulseTime = millis();
          PulseInterval = SecondPulseTime - FirstPulseTime;
          FirstPulseTime = SecondPulseTime;
        }
        IgnoreReading = true;
      }

      // Heart beat trailing edge detected.
      if(reading < LowerThreshold){
        IgnoreReading = false;
      }  

      BPM = (1.0/PulseInterval) * 60.0 * 1000;

      Serial.print(reading);
      Serial.print("\t");
      Serial.print(PulseInterval);
      Serial.print("\t");
      Serial.print(BPM);
      Serial.println(" BPM");
      Serial.flush();

      // Please don't use delay() - this is just for testing purposes.
      delay(50);  
    }

Updated answer in response to your comments below:

The sketch is reading the data and sending the data to the serial monitor every 50ms because of the delay(50). What if we changed that to 1000 ms? The serial monitor would update once per second which would be more "human readable". The problem with that idea is for heart rates faster than 60 BPM, the reading would be inaccurate. I don't have a sensor to test with but I'm guessing a 1 second delay would make the code inoperable.

Before we add more complexity to this sketch we really should get rid of that delay. It would be nice to have one "timer" that we could use to update the BPM calculation and a second "timer" to update the serial monitor every second, or half second, or what ever you want it to be.

We can do that without any libraries using millis(). Here is an updated sketch using millis() for timers. This sketch has the blinking of the on board LED added to it. I'm using an Uno so you'll have to change LED_BUILTIN to what ever pin number you are using.

int UpperThreshold = 518;
int LowerThreshold = 490;
int reading = 0;
float BPM = 0.0;
bool IgnoreReading = false;
bool FirstPulseDetected = false;
unsigned long FirstPulseTime = 0;
unsigned long SecondPulseTime = 0;
unsigned long PulseInterval = 0;
const unsigned long delayTime = 10;
const unsigned long delayTime2 = 1000;
const unsigned long baudRate = 9600;
unsigned long previousMillis = 0;
unsigned long previousMillis2 = 0;

void setup(){
  Serial.begin(baudRate);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop(){

  // Get current time
  unsigned long currentMillis = millis();

  // First event
  if(myTimer1(delayTime, currentMillis) == 1){

    reading = analogRead(0); 

    // Heart beat leading edge detected.
    if(reading > UpperThreshold && IgnoreReading == false){
      if(FirstPulseDetected == false){
        FirstPulseTime = millis();
        FirstPulseDetected = true;
      }
      else{
        SecondPulseTime = millis();
        PulseInterval = SecondPulseTime - FirstPulseTime;
        FirstPulseTime = SecondPulseTime;
      }
      IgnoreReading = true;
      digitalWrite(LED_BUILTIN, HIGH);
    }

    // Heart beat trailing edge detected.
    if(reading < LowerThreshold && IgnoreReading == true){
      IgnoreReading = false;
      digitalWrite(LED_BUILTIN, LOW);
    }  

    // Calculate Beats Per Minute.
    BPM = (1.0/PulseInterval) * 60.0 * 1000;
  }

  // Second event
  if(myTimer2(delayTime2, currentMillis) == 1){
    Serial.print(reading);
    Serial.print("\t");
    Serial.print(PulseInterval);
    Serial.print("\t");
    Serial.print(BPM);
    Serial.println(" BPM");
    Serial.flush();
  }
}

// First event timer
int myTimer1(long delayTime, long currentMillis){
  if(currentMillis - previousMillis >= delayTime){previousMillis = currentMillis;return 1;}
  else{return 0;}
}

// Second event timer
int myTimer2(long delayTime2, long currentMillis){
  if(currentMillis - previousMillis2 >= delayTime2){previousMillis2 = currentMillis;return 1;}
  else{return 0;}
}

The code compile size with delay is 4,732 vs the millis timers at 4,682 (with the LED code removed). Two timers for less than the price of one delay :)

The LED will remain on for the duration of the heart beat reading above the LowerThreshold. If you want to have it on longer or decide how long it should be on for, I won't write the code for you but I will give you a hint. You can copy myTimer1() again and make a third timer.

2
  • Thank you very much for reply and for editing my question, the code you provided works flawlessly, but i have a LED connected to pin 44, I want to indicate that LED for every Heart Beat, that means when beat happens that LED should blink.. and another thing is : for the first few seconds in the Serial monitor, BPM is showing more than 500 of values - Sometimes it's going to 1000's as well, how to avoid this.? See my Edit.. Aug 23, 2017 at 10:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.