Go Down

Topic: Heart beat sensor code fails (Read 2291 times) previous topic - next topic

summerCoder22

I asked this from Seeedstudio email support and in their forum but both didn't get any response.

I simply try to connect Grove Ear-clip Heart Rate Sensor to Uno but i get wrong data out. Wiring is correct.

They have two different Sketches.

This is "Grove - Ear-clip Heart Rate Sensor Demo code" which can be downloaded from bottom of their wiki page

http://www.seeedstudio.com/wiki/Grove_-_Heart_rate_ear_clip_kit

Code: [Select]
unsigned char pin = 13;
unsigned char counter=0;
unsigned int heart_rate=0;
unsigned long temp[21];
unsigned long sub=0;
volatile unsigned char state = LOW;
bool data_effect=true;
const int max_heartpluse_duty=2000;//you can change it follow your system's request.2000 meams 2 seconds, heart rate is 60/2. System return error if the duty overtrip 2 second.
void setup()
{
  pinMode(pin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Please press the sensor with your finger.");
  delay(5000);//wait finger press ready
  array_init();
  Serial.println("Heart rate test begin.");
  attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2
}
void loop()
{
  digitalWrite(pin, state);
  //digitalWrite(12,HIGH);
  //delay(2000);
  //digitalWrite(12,LOW);
  //delay(2000); 
}
void sum()//calculate the heart rate
{
 if(data_effect)
    {
      heart_rate=1200000/(temp[20]-temp[0]);//60*20*1000/20_total_time
      Serial.print("Heart_rate_is:\t");
      Serial.println(heart_rate);
    }
   data_effect=1;//sign bit
}
void interrupt()
{
    temp[counter]=millis(); //get sys time
    state = !state;    //change LED status
    Serial.println(counter,DEC);
    Serial.println(temp[counter]);
    switch(counter)
      {
       case(0):
       sub=temp[counter]-temp[20];
       Serial.println(sub);
       break;
       default:
       sub=temp[counter]-temp[counter-1];
       Serial.println(sub);
       break;
      }
    if(sub>max_heartpluse_duty)//set 2 seconds as max heart pluse duty
      {
        data_effect=0;//sign bit
        counter=0;
        Serial.println("Heart rate measure error,test will restart!" );
        array_init();
       }
    if (counter==20&&data_effect)
    {
      counter=0;
      sum();
    }
    else if(counter!=20&&data_effect)
    counter++;
    else
    {
      counter=0;
      data_effect=1;
    }
}
void array_init()
{
  for(unsigned char i=0;i!=20;++i)
  {
    temp[i]=0;
  }
  temp[20]=millis();
}



This is from their wiki:
Code: [Select]
// Function: This program can be used to measure heart rate, the lowest pulse in the program be set to 30.
//         Use an external interrupt to measure it.
// Hardware: Grove - Ear-clip Heart Rate Sensor, Grove - Base Shield, Grove - LED
// Arduino IDE: Arduino-1.0
// Author: FrankieChu
// Date: Jan 22, 2013
// Version: v1.0
// by www.seeedstudio.com
#define LED 4//indicator, Grove - LED is connected with D4 of Arduino
boolean led_state = LOW;//state of LED, each time an external interrupt
//will change the state of LED
unsigned char counter;
unsigned long temp[21];
unsigned long sub;
bool data_effect=true;
unsigned int heart_rate;//the measurement result of heart rate

const int max_heartpluse_duty = 2000;//you can change it follow your system's request.
//2000 meams 2 seconds. System return error
//if the duty overtrip 2 second.
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(9600);
Serial.println("Please ready your chest belt.");
delay(5000);
arrayInit();
Serial.println("Heart rate test begin.");
attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2
}
void loop()
{
digitalWrite(LED, led_state);//Update the state of the indicator
}
/*Function: calculate the heart rate*/
void sum()
{
 if(data_effect)
    {
      heart_rate=1200000/(temp[20]-temp[0]);//60*20*1000/20_total_time
      Serial.print("Heart_rate_is:\t");
      Serial.println(heart_rate);
    }
   data_effect=1;//sign bit
}
/*Function: Interrupt service routine.Get the sigal from the external interrupt*/
void interrupt()
{
    temp[counter]=millis();
Serial.println(counter,DEC);
    Serial.println(temp[counter]);
    switch(counter)
{
case 0:
sub=temp[counter]-temp[20];
Serial.println(sub);
break;
default:
sub=temp[counter]-temp[counter-1];
Serial.println(sub);
break;
}
    if(sub>max_heartpluse_duty)//set 2 seconds as max heart pluse duty
{
data_effect=0;//sign bit
counter=0;
Serial.println("Heart rate measure error,test will restart!" );
arrayInit();
}
    if (counter==20&&data_effect)
    {
counter=0;
sum();
    }
    else if(counter!=20&&data_effect)
    counter++;
    else
    {
counter=0;
data_effect=1;
    }
   
}
/*Function: Initialization for the array(temp)*/
void arrayInit()
{
for(unsigned char i=0;i < 20;i ++)
{
temp[i]=0;
}
temp[20]=millis();
}


When i try to use their Sketches, log shows "Heart_rate_is: 54464" or some other big number. Output should look like this:

Quote
19
33278
1072
20
34433
1155
Heart_rate_is: 53
My log shows:

Quote
0
16
5010
0
17
5010
0
18
5010
0
19
5010
0
20
5010
0
Heart_rate_is: 54464
Then i tried interrupts, but interrupt triggered about 20 times per second:

Code: [Select]
void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);     // Pin 13 is output to which an LED is connected
  digitalWrite(13, LOW);   // Make pin 13 low, switch LED off
  pinMode(2, INPUT);    // Pin 2 is input to which a switch is connected = INT0
  attachInterrupt(0, blink1, RISING);
}

void loop() {


void blink1(){              // Interrupt service routine
  Serial.println("Beat");
  digitalWrite(13, HIGH);
}

void blink2(){              // Interrupt service routine
  digitalWrite(13, LOW);
}


I just found another code and it also shows too big numbers. I add this code to next post because this post has max 9000 characters limit.

http://gampageek.blogspot.fr/2013/01/arduino-meets-yogic-arts-seeduino-ear.html

Quote
BEAT

BEAT

BEAT

Heart Rate is:

180.00

BEAT

Heart Rate is:

188.57

BEAT

Heart Rate is:

197.14
I don't care if it uses interrupts or not as long it works.

Thanks

summerCoder22

Code: [Select]
// Arduino Meets Yogic Arts - The Relaxino!
/*  Program to measure and display heart beats on two led's (and on serial monitor for debug)
*   Green led flashes at approx freq of your heart rate when you are at or below your target,
*   if you go above this (eg 65 bpm) the red.
*   led flashes at the approx freq of your heart rate
*   You can check by feeling your pulse
*   in your neck and looking at LED - both should be in sync
*   C. Turner 16/01/2013.
 
 *  Seeed product wiki http://www.seeedstudio.com/wiki/Grove_-_Heart_rate_ear_clip_kit
*  Avaialible in UK here:  https://digitalmeans.co.uk/shop/sensors-category/sensors-medical-category/grove-ear_clip_heart_rate_sensor
*  More detailed project write-up here: http://gampageek.blogspot.co.uk/2013/01/arduino-meets-yogic-arts-seeduino-ear.html

// Sketch is provided "As is" with no guarantees, or support from the Author.
// Help with Arduino and shields can be found by joining the forum on the Arduino website: http://arduino.cc/en/

*/
unsigned char HIpin = 13;//red led = over target & use 560 Ohm resitor in series
unsigned char LOpin = 12;// green = @target heart rate or below & use 560 Ohm resitor in series
// times
unsigned long t1 = 0;
unsigned long t2 = 0;

unsigned long counter = 0; // count interrupts = beats
unsigned long secsElapsed = 0; // time for 60 beats
unsigned long myCount = 0; // heart beat count so far

float heartRate = 0; // instantaneous rate
float averageHeartRate = 0;// ave over 30 beats

boolean beatDetect = false;

void setup()
{
  pinMode(HIpin, OUTPUT);
  pinMode(LOpin, OUTPUT);


  Serial.begin(9600);
  Serial.println("Please ready your ear clip.");
  digitalWrite(HIpin, HIGH);// red led off

  delay(2000);//time to place clip, note that some people's earlobes are too thick (mine are)
 // I had to place it on the main ear. May need to play until you get sensible results.
 // change to 5000 or more if need more time.
 
  digitalWrite(HIpin, LOW);// leds off
  digitalWrite(LOpin, LOW);
 
  Serial.println("Heart rate test begin.");// debug

  t1 = millis(); // set start time.

  attachInterrupt(0, interrupt, RISING);//set interrupt 0, digital pin 2 -
  //Seed / grove heart monitor out pin is attched here.
 
}
void loop()
{

  if (beatDetect == true)// if interrupted on pin 2 ie beat was detected
  {
    //*****************************************************************************     

    Serial.println("BEAT");// debug: print BEAT on each interrupt

    if (counter > 20 )// use heart rate when 20 beats averaged
    {
      Serial.println("Heart Rate is: ");// debug
      averageHeartRate = heartRate;
      Serial.print(averageHeartRate);// debug
      Serial.println();// debug
    }
    //************************************************************************************   


    counter = counter + 1 ;

    t2 = millis(); // check time

    myCount = counter;// heart beats so far
   
    secsElapsed = (t2 - t1 ) / 1000 ; // seconds elapsed
   
    heartRate =  (float(myCount) / float(secsElapsed) ) * 60;// beats per minute
   
    beatDetect = false;// reset for next interrupt (beat)

    if (counter == 61)
    {
      counter = 0; // reset counter after 30 beats
      t1 = millis(); // reset t1 to millis()
    }


    //display the info **************************
    if (averageHeartRate != 0)
    {
// SET TARGET HEART BEAT HERE ++++++++++++++++++++++++++++++++++++++++++++++++
      if (averageHeartRate > 63)// my average resting heart rate = 65 bpm - choose your own
      {
        //HIGH target RED led
        digitalWrite(HIpin, HIGH);// red led on
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(HIpin, LOW);// red led off
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(LOpin, LOW);// green led off
      }


      if (averageHeartRate <= 63) // my average resting heart rate = 65bpm choose your own
      {   
        //LOW target green led   
        digitalWrite(LOpin, HIGH);// green led on
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(LOpin, LOW);// gree led off
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(HIpin, LOW);// red led off
      }
    }

    else if (averageHeartRate == 0)// when starting up flash both leds

    {
      digitalWrite(HIpin, HIGH);// red led on
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(HIpin, LOW);// red led off
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(LOpin, LOW);// green led off

      digitalWrite(LOpin, HIGH);// green led on
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(LOpin, LOW);// gree led off
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(HIpin, LOW);// red led off


    }

  }// end of beat detected


}


void interrupt()
{
  beatDetect = true;

}


void delay10thsOfSeconds (int multi){// delay multi x 0.1 sec

  for (int i = 1; i < (multi * 10); i++) // wait 10 = 0.1 sec
  {
    delayMicroseconds(10000);   // multi x 100 x 10000 us
  }

}

PaulS

You can not do Serial.print() in an ISR. Get rid of them.

blink2() is not an interrupt service routine.

In the last code, beatDetect is set in the ISR and read in loop(). The compiler that generates code to read the value of beatDetect does not know that beatDetect can change while loop() is running. You need to declare that beatDetect is volatile, in order for the compiler to know that that value can change while loop() is running.
The art of getting good answers lies in asking good questions.

summerCoder22

You can not do Serial.print() in an ISR. Get rid of them.

blink2() is not an interrupt service routine.

In the last code, beatDetect is set in the ISR and read in loop(). The compiler that generates code to read the value of beatDetect does not know that beatDetect can change while loop() is running. You need to declare that beatDetect is volatile, in order for the compiler to know that that value can change while loop() is running.
Thanks. So i changed

boolean beatDetect = false;

to

volatile boolean beatDetect = false;

And it still has same problem. Unfortunately since i'm newbie i don't understand rest of your instructions. :-(

PaulS

Quote
Unfortunately since i'm newbie i don't understand rest of your instructions
I find it difficult to believe that you can not figure out that you need to remove all Serial.print() statements that are in interrupt service routines.
The art of getting good answers lies in asking good questions.

summerCoder22

I find it difficult to believe that you can not figure out that you need to remove all Serial.print() statements that are in interrupt service routines.
I tried again to remove all Serial.print() from void interrupt() but it still outputs big numbers.

PaulS

Quote
but it still outputs big numbers.
So, which of the codes are you concentrating on, and what does the code look like now?
The art of getting good answers lies in asking good questions.

summerCoder22

So, which of the codes are you concentrating on, and what does the code look like now?
I just did volatile change and removed serial.prints from void interrupt() in both Seeedstudio scripts. Othervice all codes are the same.

Right now i consentrate to all scripts but i don't care which one starts to work. Thanks

PaulS

I just did volatile change and removed serial.prints from void interrupt() in both Seeedstudio scripts. Othervice all codes are the same.

Right now i consentrate to all scripts but i don't care which one starts to work. Thanks
You need to pick one and post the latest code for that one. I, for one, will not assume that you made only the changes you were supposed to, without seeing the new code.
The art of getting good answers lies in asking good questions.

summerCoder22

You need to pick one and post the latest code for that one. I, for one, will not assume that you made only the changes you were supposed to, without seeing the new code.
Here is all three codes fixed. I don't know which one i should consentrate.

Code: [Select]
// Function: This program can be used to measure heart rate, the lowest pulse in the program be set to 30.
//         Use an external interrupt to measure it.
// Hardware: Grove - Ear-clip Heart Rate Sensor, Grove - Base Shield, Grove - LED
// Arduino IDE: Arduino-1.0
// Author: FrankieChu
// Date: Jan 22, 2013
// Version: v1.0
// by www.seeedstudio.com
#define LED 4//indicator, Grove - LED is connected with D4 of Arduino
boolean led_state = LOW;//state of LED, each time an external interrupt
//will change the state of LED
unsigned char counter;
unsigned long temp[21];
unsigned long sub;
bool data_effect=true;
unsigned int heart_rate;//the measurement result of heart rate

const int max_heartpluse_duty = 2000;//you can change it follow your system's request.
//2000 meams 2 seconds. System return error
//if the duty overtrip 2 second.
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(9600);
Serial.println("Please ready your chest belt.");
delay(5000);
arrayInit();
Serial.println("Heart rate test begin.");
attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2
}
void loop()
{
digitalWrite(LED, led_state);//Update the state of the indicator
}
/*Function: calculate the heart rate*/
void sum()
{
 if(data_effect)
    {
      heart_rate=1200000/(temp[20]-temp[0]);//60*20*1000/20_total_time
      Serial.print("Heart_rate_is:\t");
      Serial.println(heart_rate);
    }
   data_effect=1;//sign bit
}
/*Function: Interrupt service routine.Get the sigal from the external interrupt*/
void interrupt()
{
    temp[counter]=millis();
// Serial.println(counter,DEC);
    // Serial.println(temp[counter]);
    switch(counter)
{
case 0:
sub=temp[counter]-temp[20];
// Serial.println(sub);
break;
default:
sub=temp[counter]-temp[counter-1];
// Serial.println(sub);
break;
}
    if(sub>max_heartpluse_duty)//set 2 seconds as max heart pluse duty
{
data_effect=0;//sign bit
counter=0;
// Serial.println("Heart rate measure error,test will restart!" );
arrayInit();
}
    if (counter==20&&data_effect)
    {
counter=0;
sum();
    }
    else if(counter!=20&&data_effect)
    counter++;
    else
    {
counter=0;
data_effect=1;
    }
   
}
/*Function: Initialization for the array(temp)*/
void arrayInit()
{
for(unsigned char i=0;i < 20;i ++)
{
temp[i]=0;
}
temp[20]=millis();
}


Code: [Select]
unsigned char pin = 13;
unsigned char counter=0;
unsigned int heart_rate=0;
unsigned long temp[21];
unsigned long sub=0;
volatile unsigned char state = LOW;
bool data_effect=true;
const int max_heartpluse_duty=2000;//you can change it follow your system's request.2000 meams 2 seconds, heart rate is 60/2. System return error if the duty overtrip 2 second.
void setup()
{
  pinMode(pin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Please press the sensor with your finger.");
  delay(5000);//wait finger press ready
  array_init();
  Serial.println("Heart rate test begin.");
  attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2
}
void loop()
{
  digitalWrite(pin, state);
  //digitalWrite(12,HIGH);
  //delay(2000);
  //digitalWrite(12,LOW);
  //delay(2000); 
}
void sum()//calculate the heart rate
{
 if(data_effect)
    {
      heart_rate=1200000/(temp[20]-temp[0]);//60*20*1000/20_total_time
      Serial.print("Heart_rate_is:\t");
      Serial.println(heart_rate);
    }
   data_effect=1;//sign bit
}
void interrupt()
{
    temp[counter]=millis(); //get sys time
    state = !state;    //change LED status
    // Serial.println(counter,DEC);
    // Serial.println(temp[counter]);
    switch(counter)
      {
       case(0):
       sub=temp[counter]-temp[20];
       // Serial.println(sub);
       break;
       default:
       sub=temp[counter]-temp[counter-1];
       // Serial.println(sub);
       break;
      }
    if(sub>max_heartpluse_duty)//set 2 seconds as max heart pluse duty
      {
        data_effect=0;//sign bit
        counter=0;
        // Serial.println("Heart rate measure error,test will restart!" );
        array_init();
       }
    if (counter==20&&data_effect)
    {
      counter=0;
      sum();
    }
    else if(counter!=20&&data_effect)
    counter++;
    else
    {
      counter=0;
      data_effect=1;
    }
}
void array_init()
{
  for(unsigned char i=0;i!=20;++i)
  {
    temp[i]=0;
  }
  temp[20]=millis();
}

summerCoder22

Code: [Select]
// Arduino Meets Yogic Arts - The Relaxino!
/*  Program to measure and display heart beats on two led's (and on serial monitor for debug)
*   Green led flashes at approx freq of your heart rate when you are at or below your target,
*   if you go above this (eg 65 bpm) the red.
*   led flashes at the approx freq of your heart rate
*   You can check by feeling your pulse
*   in your neck and looking at LED - both should be in sync
*   C. Turner 16/01/2013.
 
 *  Seeed product wiki http://www.seeedstudio.com/wiki/Grove_-_Heart_rate_ear_clip_kit
*  Avaialible in UK here:  https://digitalmeans.co.uk/shop/sensors-category/sensors-medical-category/grove-ear_clip_heart_rate_sensor
*  More detailed project write-up here: http://gampageek.blogspot.co.uk/2013/01/arduino-meets-yogic-arts-seeduino-ear.html

// Sketch is provided "As is" with no guarantees, or support from the Author.
// Help with Arduino and shields can be found by joining the forum on the Arduino website: http://arduino.cc/en/

*/
unsigned char HIpin = 13;//red led = over target & use 560 Ohm resitor in series
unsigned char LOpin = 12;// green = @target heart rate or below & use 560 Ohm resitor in series
// times
unsigned long t1 = 0;
unsigned long t2 = 0;

unsigned long counter = 0; // count interrupts = beats
unsigned long secsElapsed = 0; // time for 60 beats
unsigned long myCount = 0; // heart beat count so far

float heartRate = 0; // instantaneous rate
float averageHeartRate = 0;// ave over 30 beats

volatile boolean beatDetect = false;

void setup()
{
  pinMode(HIpin, OUTPUT);
  pinMode(LOpin, OUTPUT);


  Serial.begin(9600);
  Serial.println("Please ready your ear clip.");
  digitalWrite(HIpin, HIGH);// red led off

  delay(2000);//time to place clip, note that some people's earlobes are too thick (mine are)
 // I had to place it on the main ear. May need to play until you get sensible results.
 // change to 5000 or more if need more time.
 
  digitalWrite(HIpin, LOW);// leds off
  digitalWrite(LOpin, LOW);
 
  Serial.println("Heart rate test begin.");// debug

  t1 = millis(); // set start time.

  attachInterrupt(0, interrupt, RISING);//set interrupt 0, digital pin 2 -
  //Seed / grove heart monitor out pin is attched here.
 
}
void loop()
{

  if (beatDetect == true)// if interrupted on pin 2 ie beat was detected
  {
    //*****************************************************************************     

    Serial.println("BEAT");// debug: print BEAT on each interrupt

    if (counter > 20 )// use heart rate when 20 beats averaged
    {
      Serial.println("Heart Rate is: ");// debug
      averageHeartRate = heartRate;
      Serial.print(averageHeartRate);// debug
      Serial.println();// debug
    }
    //************************************************************************************   


    counter = counter + 1 ;

    t2 = millis(); // check time

    myCount = counter;// heart beats so far
   
    secsElapsed = (t2 - t1 ) / 1000 ; // seconds elapsed
   
    heartRate =  (float(myCount) / float(secsElapsed) ) * 60;// beats per minute
   
    beatDetect = false;// reset for next interrupt (beat)

    if (counter == 61)
    {
      counter = 0; // reset counter after 30 beats
      t1 = millis(); // reset t1 to millis()
    }


    //display the info **************************
    if (averageHeartRate != 0)
    {
// SET TARGET HEART BEAT HERE ++++++++++++++++++++++++++++++++++++++++++++++++
      if (averageHeartRate > 63)// my average resting heart rate = 65 bpm - choose your own
      {
        //HIGH target RED led
        digitalWrite(HIpin, HIGH);// red led on
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(HIpin, LOW);// red led off
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(LOpin, LOW);// green led off
      }


      if (averageHeartRate <= 63) // my average resting heart rate = 65bpm choose your own
      {   
        //LOW target green led   
        digitalWrite(LOpin, HIGH);// green led on
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(LOpin, LOW);// gree led off
        delay10thsOfSeconds (1);// flash at heart beat rate
        digitalWrite(HIpin, LOW);// red led off
      }
    }

    else if (averageHeartRate == 0)// when starting up flash both leds

    {
      digitalWrite(HIpin, HIGH);// red led on
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(HIpin, LOW);// red led off
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(LOpin, LOW);// green led off

      digitalWrite(LOpin, HIGH);// green led on
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(LOpin, LOW);// gree led off
      delay10thsOfSeconds (1);// flash at heart beat rate
      digitalWrite(HIpin, LOW);// red led off


    }

  }// end of beat detected


}


void interrupt()
{
  beatDetect = true;

}


void delay10thsOfSeconds (int multi){// delay multi x 0.1 sec

  for (int i = 1; i < (multi * 10); i++) // wait 10 = 0.1 sec
  {
    delayMicroseconds(10000);   // multi x 100 x 10000 us
  }

}

Go Up