Heartbeatvalues are not stable

Dear Arduino community,

I am working on a project and I have the next issue: As you can see in the code, when I am inserting into the Serial Monitor two different values, one for "pulsbreite" and one for "pulsbreite1" working with the LED ("ledgelb"), the heartbeat-values are not stable. They are going up and down and will not display the correct heartbeat value. I am using a heartbeat sensor from PulseSensor.com

Can someone help me with this issue? Is it better to create an Interrupt with the following code:

 digitalWrite(ledgelb, HIGH);                                         
        delay(pulsbreite);                                                    
        digitalWrite(ledgelb, LOW);                                            
        delay(pulsbreite1);

       


        Serial.print(Zeit1);                                                   
        Serial.println(" ms");
        Serial.print(BPM);
        Serial.println("Hz");
        Serial.print(pulsbreite);
        Serial.println(" ms");
        Serial.print(pulsbreite1);
        Serial.println(" ms");
        Serial.println("\n");
        return BPM;

Here is the whole code:


#include <Wire.h>
#include <math.h>
#include "rgb_lcd.h"
#include "PWM.h"

              



volatile int rate[10];                             
volatile unsigned long sampleCounter = 0;          
volatile unsigned long lastBeatTime = 0;           
volatile int P = 512;                              
volatile int T = 512;                              
volatile int thresh = 525;                          
volatile int amp = 100;                              
volatile boolean firstBeat = true;                  
volatile boolean secondBeat = true;                 
word runningTotal;

int blinkPin = 13;
int AnalogPin = 0;
int IBI = 600;
int Pulse = false;

int Signal;
float Rwert;

volatile unsigned long Zeit1;

const int ledrot = 13;
const int ledgelb = 12;
const int ledgruen = 11;

int BPM;
int BPM1 = 60;
int testzeit;
int pulsbreite;
int pulsbreite1;
int N;



void setup() {

  Serial.begin(9600);

  pinMode(ledrot, OUTPUT);                                                                   
  pinMode(ledgelb, OUTPUT);                                                                   
  pinMode(ledgruen, OUTPUT);                                                                                                                  

  Serial.println("<Arduino is ready>");

  delay(1000);                                                                               

}




void loop() {

  Rwert = ((Signal * 5.0) / 1023) * 1000;
  testzeit = (60000 / BPM1);

  if (Serial.available() > 0) {

    pulsbreite = Serial.parseInt();
    pulsbreite1 = Serial.parseInt();

    if (Serial.read() == '\n') {

    }
  }

  cli();                                      // disable interrupts while we do this
  Signal = analogRead(AnalogPin);              // read the Pulse Sensor

  sampleCounter += 2;                         // keep track of the time in mS with this variable
  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 (firstBeat) {                       // if it's the first time we found a beat, if firstBeat == TRUE
        firstBeat = false;                 // clear firstBeat flag
        return;                            // IBI value is unreliable so discard it
      }
      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;
        }
      }

      // keep a running total of the last 10 IBI values
      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!
      int QS = true;                              // set Quantified Self flag
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
      Zeit1 = (runningTotal - ((0.1) * runningTotal));          

      digitalWrite(ledrot, HIGH);
      Serial.print(BPM);
      Serial.println(" Hz");
      Serial.print(runningTotal);
      Serial.println(" ms");
      Serial.print(Rwert);
      Serial.println(" mV");
      Serial.print(Zeit1);
      Serial.println(" ms");
      Serial.print(BPM1);
      Serial.println(" Hz");
      Serial.print(testzeit);
      Serial.println(" ms");
      Serial.print("\n");
      digitalWrite(ledrot, LOW);


      if (Zeit1 < testzeit) {                            

        
          sei();
                                                               
        digitalWrite(ledgelb, HIGH);                                         
        delay(pulsbreite);                                                    
        digitalWrite(ledgelb, LOW);                                            
        delay(pulsbreite1);

       


        Serial.print(Zeit1);                                                   
        Serial.println(" ms");
        Serial.print(BPM);
        Serial.println("Hz");
        Serial.print(pulsbreite);
        Serial.println(" ms");
        Serial.print(pulsbreite1);
        Serial.println(" ms");
        Serial.println("\n");
        return BPM;
        
        cli();



      }


    }
  }


  

  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 = 525;                          // 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 = true;                     // when we get the heartbeat back
  }
  delay(60);
  sei();                                     // enable interrupts when youre done!

}

Thank you very much in advance

Best regards

Kosta

Seek medical help.

Certainly not.
Never delay or do Serial I/o in interrupt context

My heartbeat is doing fine and the code is displaying the BPM right until I type in the values for the two parameters (pulsbreite, pulsbreite1) in the delay. Than the heartbeat values start to go up and down.

Best regards

Kosta

That would be the mistake. This is another, far more serious one, because all the timing functions stop working, and with many MCUs, so does serial I/O;

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

Hello jremington,

I removed the cli(); in the beginning of the void loop() and the sei(); in the end of the void loop() and I get better results. I left the sei(); after if (Zeit1 < testzeit) and the cli(); after return BPM;.
Is there anything I can do to optimize the code to work better?

Thank you very much for your help and time

Best regards

Kosta

Why? Those actions are not necessary, and the cli() actually halts many of the normal Arduino functions.

Do not use them unless you are required to do so (there are such cases, but this is not one of them).

Edit: in looking through the code, it has many other problems, such as this one, which seriously affects the timing. I'm quite sure that if you look around, you can find a much better example to work with.

  Serial.begin(9600);

Which baudrate would you recommend?

Hi,
Is there a reason you are not using the library and examples for the PulseSensor?

There is even an example that gives you direct heart beats per minute.

Tom... :grinning: :+1: :coffee: :australia:

1 Like

Hello TomGeorge,

thank you very much for the link. I will try the different examples out.

Have a nice day

Best regards

Kosta

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.