Time between two impulses(Heartbeats)

Hello community,

I am a newbie and I want to measure the time between impulses of heartbeats, via a pulsesensor, and display it on the Serial Monitor. Underneath you will see my code. I uploaded it on my Arduino Uno but I only get 0´s in the Serial Monitor. Can someone explain to me where my error lies? I appreciate every help from every forum-user.

Thank you very much in advance

Best regards Kosta

int AnalogPin = A0;

int Signal;                
int Threshold = 500;            


volatile unsigned long last;
volatile unsigned long timediff;


void setup() {

  pinMode(AnalogPin,INPUT);        
   Serial.begin(9600);        

}


void loop() {

  Signal = analogRead(AnalogPin);  

   //Serial.println(Signal);                 


  if (Signal > Threshold) {

    
     volatile unsigned long current = millis();
     last = current;
    
     timediff = current - last;
 
    
  }

   Serial.println(timediff);

delay(200);


}

Yes, the error is in these three lines.

If you set last to be the same as current the difference between the two will always be zero in the next line.
Most probably you wanted to put the last = current line after the timeDiff line.

Hello pylon,

thank you very much for taking your time and helping me, I appreciate it.

Best regards

Kosta

There's another problem.

You don't want the above code to run all the time that the signal is higher than the threshold, which is what this line says:

if (Signal > Threshold) {

You only want the code to run once for each heartbeat, at the moment the signal crosses the threshold. To do that, your code needs to remember the signal level last time it was read.

Hello PaulRB,

you mean that I have to detect the current and previous highest peak every time and calculate the timedifference between them or did I understood it wrong? Thank you for your notification.

Best regards Kosta

Not quite. You don't need to detect the peaks. You only need to detect the moment when the signal first rises above your threshold, on each heartbeat. Right now, your code to calculate time difference will run repeatedly while the signal is above that threshold, so it could run many times, perhaps hundreds of times, for each heartbeat.

Maybe I can observe the waveformsignal with its highest peak and than set a new value for the threshold, so that I can remove the underneath of the treshold values. Is it ok like this?

Thank you very much for your help PaulRB. Best regards

How can I do this PaulRB? Can you help me with the programming-part?

Thank you very much in advance. Best Regards

You could try using a boolean variable so that it goes true when it crosses the threshold.

Something like

int Signal, previousSignal;
...

void loop() {

  Signal = analogRead(AnalogPin);  

   //Serial.println(Signal);                 


  if (Signal > Threshold && previousSignal <= Threshold) {
    
     timediff = millis() - last;
 
     Serial.println(timediff);

     last += timediff;

  }

  previousSignal = Signal;
   
  delay(200);

}

Here is a nice step-by-step explanation how to handle the heartbeat sensor

https://create.arduino.cc/projecthub/Johan_Ha/from-ky-039-to-heart-rate-0abfca

It also explains how to get rid of the influence of artificial light (50 or 60 Hz signals).

The final software there is not easy to understand for a newbie, but you can study it and come back with questions!

There is another software/explanation available here

https://sensorkit.joy-it.net/en/sensors/ky-039

where there is less information but the code might be easier to understand.

I have modified the software from the first link I gave to you.

It is broken down now from one big chunk into several smaller routines and I changed the name "ptr" to "index" because ptr might be misinterpreted as a pointer but is actually only an index to an array.

What you can see is that interpreting the sensor data is not as easy as people usually think when they start handling raw data. And you can learn how to calculate an average on-the-fly.

To be frank: It is not a code I would design this way because it uses and modifies global variables all over the place. To split it up into some (hopefully) understandable routines was all I could do on short term.

You may still investigate how it works but should not take it as an example for writing code: The original is even harder to understand and - even broken up - it is not supporting easy debugging and maintenance.

Still hope it helps you at little bit further ... :wink:

(Almost nothing is really useless, in minimum it can be used as a bad example ...) :wink:

#define samp_siz 4
#define rise_threshold 5
// Pulse Monitor Test Script

int sensorPin = 0;
float reads[samp_siz], sum;
long int now, index;
float last, reader, start;
float first, second, third, before, print_value;
bool rising;
int rise_count;
int n;
long int last_beat;

void MeasureData() {
  // calculate an average of the sensor
  // during a 20 ms period (this will eliminate
  // the 50 Hz noise caused by electric light
  n = 0;
  start = millis();
  reader = 0.;
  do
  {
    reader += analogRead (sensorPin);
    n++;
    now = millis();
  }
  while (now < start + 20);
}
void CalcNewAverage() {
  reader /= n;  // we got an average
  // Add the newest measurement to an array
  // and subtract the oldest measurement from the array
  // to maintain a sum of last measurements
  sum -= reads[index];
  sum += reader;
  reads[index] = reader;
  last = sum / samp_siz;
}

void HandleRisingCurve() {
  // Ok, we have detected a rising curve, which implies a heartbeat.
  // Record the time since last beat, keep track of the two previous
  // times (first, second, third) to get a weighed average.
  // The rising flag prevents us from detecting the same rise
  // more than once.
  rising = true;
  first = millis() - last_beat;
  last_beat = millis();
  // Calculate the weighed average of heartbeat rate
  // according to the three last beats
  print_value = 60000. / (0.4 * first + 0.3 * second + 0.3 * third);
  Serial.print(print_value);
  Serial.print('\n');
  third = second;
  second = first;
}

void HandleFallingCurve() {
  // Ok, the curve is falling
  rising = false;
  rise_count = 0;
}

void HandleTheCurve() {
  // now last holds the average of the values in the array
  // check for a rising curve (= a heart beat)
  if (last > before)
  {
    rise_count++;
    if (!rising && rise_count > rise_threshold) {HandleRisingCurve();};
  }
  else {HandleFallingCurve();};
}

void PrepareNextRound() {
  before = last;
  index++;
  index %= samp_siz;
}

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < samp_siz; i++)
    reads[i] = 0;
  sum = 0;
  index = 0;
}

void loop ()
{
  MeasureData();
  CalcNewAverage();
  HandleTheCurve();
  PrepareNextRound();
}

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