element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Arduino
  • Products
  • More
Arduino
Arduino Forum Heart Pulse Monitor
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Arduino to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 8 replies
  • Subscribers 393 subscribers
  • Views 693 views
  • Users 0 members are here
Related

Heart Pulse Monitor

Former Member
Former Member over 11 years ago

Hi,

I am wondering can anyone help me please. I have been trying to put tone / melody to a heart monitor for some time now but I am not getting anywhere.

The data is coming in from the heart sensor but it seems to be jumping all over the place. For ex; when the user is not even moving the pulse is jumping from 50 to 800. If that was real the person would be dead.

So I am trying to put sound onto that its coming up with nothing just crackling noise.

Can anyone help, I am getting really frustrated, and driving myself crazy.

Here is the code: Maybe I am doing something wrong, is there an easier way to attach sound onto the heart pulse monitor.

I have an LED and that is taking in the heart pulse but the sound isnt.

below is the code I have been working on.

 

 

/*

>> Pulse Sensor Digital Filter <<

This code is the library prototype for Pulse Sensor by Yury Gitman and Joel Murphy

    www.pulsesensor.com

    >>> Pulse Sensor purple wire goes to Analog Pin 0 <<<

Pulse Sensor sample aquisition and processing happens in the background via Timer 1 interrupt. 1mS sample rate.

The following variables are automatically updated:

Pulse :     boolean that is true when a heartbeat is sensed then false in time with pin13 LED going out.

Signal :    int that holds the analog signal data straight from the sensor. updated every 1mS.

HRV  :      int that holds the time between the last two beats. 1mS resolution.

B  :        boolean that is made true whenever HRV is updated. User must reset.

BPM  :      int that holds the heart rate value. derived from averaging HRV every 10 pulses.

QS  :       boolean that is made true whenever BPM is updated. User must reset.

Scale  :    int that works abit like gain. use to change the amplitude of the digital filter output. useful range 12<>20 : high<>low default = 12

FSignal  :  int that holds the output of the digital filter/amplifier. updated every 1mS.

 

 

*/

 

 

 

 

 

 

 

 

 

 

long Hxv[4]; // these arrays are used in the digital filter

long Hyv[4]; // H for highpass, L for lowpass

long Lxv[4];

long Lyv[4];

 

 

unsigned long readings; // used to help normalize the signal

unsigned long peakTime; // used to time the start of the heart pulse

unsigned long lastPeakTime = 0;// used to find the time between beats

volatile int Peak;     // used to locate the highest point in positive phase of heart beat waveform

int rate;              // used to help determine pulse rate        //MELODY REVELANT

volatile int BPM;      // used to hold the pulse rate              //MELODY REVELANT

int offset = 0;        // used to normalize the raw data

int sampleCounter;     // used to determine pulse timing

int beatCounter = 1;   // used to keep track of pulses

volatile int Signal;   // holds the incoming raw data

int NSignal;           // holds the normalized signal

volatile int FSignal;  // holds result of the bandpass filter

volatile int HRV;      // holds the time between beats

volatile int Scale = 13;  // used to scale the result of the digital filter. range 12<>20 : high<>low amplification

volatile int Fade = 0;

 

 

boolean first = true; // reminds us to seed the filter on the first go

volatile boolean Pulse = false;  // becomes true when there is a heart pulse    //MELODY REVELANT

volatile boolean B = false;     // becomes true when there is a heart pulse

volatile boolean QS = false;      // becomes true when pulse rate is determined. every 20 pulses

 

 

int pulsePin = 0;  // pulse sensor purple wire connected to analog pin 0

 

 

int speakerOut = 10;

 

 

 

 

void setup()

{

 

  pinMode(speakerOut, OUTPUT);

 

 

 

pinMode(10,OUTPUT);    // pin 13 will blink to your heartbeat!  //MELODY REVELANT

Serial.begin(115200); // we agree to talk fast!

// this next bit will wind up in the library. it initializes Timer1 to throw an interrupt every 1mS.

TCCR1A = 0x00; // DISABLE OUTPUTS AND BREAK PWM ON DIGITAL PINS 9 & 10

TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER

TCCR1C = 0x00; // DON'T FORCE COMPARE

TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)

ICR1 = 8000;   // TRIGGER TIMER INTERRUPT EVERY 1mS 

sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED

 

 

}

 

 

  //========

 

  #define  c     3830    // 261 Hz

#define  d     3400    // 294 Hz

#define  e     3038    // 329 Hz

#define  f     2864    // 349 Hz

#define  g     2550    // 392 Hz

#define  a     2272    // 440 Hz

#define  b     2028    // 493 Hz

#define  C     1912    // 523 Hz

#define  R     0

 

 

  int melody[] = {  C,  b,  g,  C,  b,   e,  R,  C,  c,  g, a, C };

int beats[]  = { 16, 16, 16,  8,  8,  16, 32, 16, 16, 16, 8, 8 };

int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping.

 

 

// Set overall tempo

long tempo = 10000;

// Set length of pause between notes

int pause = 1000;

// Loop variable to increase Rest length

int rest_count = 100; //<-BLETCHEROUS HACK; See NOTES

 

 

// Initialize core variables

int tone_ = 0;

int beat = 0;

long duration  = 0;

 

 

// PLAY TONE  ==============================================

// Pulse the speaker to play a tone for a particular duration

void playTone() {

  long elapsed_time = 0;

  if (tone_ > 0) { // if this isn't a Rest beat, while the tone has

    //  played less long than 'duration', pulse speaker HIGH and LOW

    while (elapsed_time < duration) {

 

 

      digitalWrite(speakerOut,HIGH);

      delayMicroseconds(tone_ / 2);

 

 

      // DOWN

      digitalWrite(speakerOut, LOW);

      delayMicroseconds(tone_ / 2);

 

 

      // Keep track of how long we pulsed

      elapsed_time += (tone_);

    }

  }

  else { // Rest beat; loop times delay

    for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count

      delayMicroseconds(duration); 

    }                               

  }                               

}

  //========

 

 

 

 

void loop()

{

 

 

  //=====================================

  /*

    // Set up a counter to pull from melody[] and beats[]

  for (int i=0; i<MAX_COUNT; i++) {

    tone_ = melody[i];

    beat = beats[i];

 

 

    duration = beat * tempo; // Set up timing

 

 

    playTone();

    // A pause between notes...

    delayMicroseconds(pause);

  }*/

  //=====================================

 

// Serial.print("S");          // S tells processing that the following string is sensor data

  //Serial.println(Signal);     // Signal holds the latest raw Pulse Sensor signal

  if (B == true)

  {

  //==============================

  /*

               //  B is true when arduino finds the heart beat

    for (int i=0; i<MAX_COUNT; i++) {

    tone_ = melody[i];

    beat = beats[i];

 

 

    duration = beat * tempo; // Set up timing

 

 

    playTone();

    // A pause between notes...

    delayMicroseconds(pause);

  }

  */

  //============================

   

    //Serial.print("B");        // 'B' tells Processing the following string is HRV data (time between beats in mS)

    //Serial.println(HRV);      //  HRV holds the time between this pulse and the last pulse in mS

    B = false;                // reseting the QS for next time

  }

  if (QS == true)

  {        

 

  //==============================

  /*

               //  B is true when arduino finds the heart beat

    for (int i=0; i<MAX_COUNT; i++) {

    tone_ = melody[i];

    beat = beats[i];

 

 

    duration = beat * tempo; // Set up timing

 

 

    playTone();

    // A pause between notes...

    delayMicroseconds(pause);

  }

  */

  //============================

   

 

    //  QS is true when arduino derives the heart rate by averaging HRV over 20 beats

    Serial.print("Q");        //  'QS' tells Processing that the following string is heart rate data

    Serial.println(BPM);      //  BPM holds the heart rate in beats per minute

    QS = false;               //  reset the B for next time

  }

 

  Fade -= 15;

  Fade = constrain(Fade,0,255);

  analogWrite(11,Fade);

 

 

delay(20);                    //  take a break

//BPM IS VARIABLE

 

 

  //Serial.println(analogValue);      // print it 

 

  // get a sensor reading:

 

 

   // map the results from the sensor reading's range

   // to the desired pitch range:

    if(BPM > 100 && BPM < 200)

   

    {

  //====  for (int i=0; i<BPM; i++) {

    tone_ = melody[BPM/17];

    beat = beats[BPM/17];

   

    //12 in the arrays---<?>

 

 

    duration = BPM; // Set up timing

 

 

    playTone();

   

  //===}

      digitalWrite(10, HIGH);

      Serial.print("1st playtone working in BPM if");

     //tone(8, frequency, 100);

    }

      else

      {

    tone_ = melody[BPM/17];

    beat = beats[BPM/17];

     //Serial.print("1st playtone working in BPM else");

   

    //12 in the arrays---<?>

 

 

    duration = BPM; // Set up timing

 

 

    playTone();

        digitalWrite(10,HIGH);

        Serial.print("second playtone working in BPM else");

      }

     

  

   // change the pitch, play for 10 ms:

   //tone(8, frequency, 100);

 

 

 

 

 

 

}

 

 

// THIS IS THE TIMER 1 INTERRUPT SERVICE ROUTINE. IT WILL BE PUT INTO THE LIBRARY

ISR(TIMER1_OVF_vect){ // triggered every time Timer 1 overflows

// Timer 1 makes sure that we take a reading every milisecond

Signal = analogRead(pulsePin);

 

 

// First normailize the waveform around 0

readings += Signal; // take a running total

sampleCounter++;     // we do this every milisecond. this timer is used as a clock

if ((sampleCounter %300) == 0)

{   // adjust as needed

  offset = readings / 300;        // average the running total

  readings = 0;                   // reset running total

}

NSignal = Signal - offset;        // normalizing here

 

 

// IF IT'S THE FIRST TIME THROUGH THE SKETCH, SEED THE FILTER WITH CURRENT DATA

if (first = true)

{

  for (int i=0; i<4; i++)

  {

    Lxv[i] = Lyv[i] = NSignal <<10;  // seed the lowpass filter

    Hxv[i] = Hyv[i] = NSignal <<10;  // seed the highpass filter

  }

first = false;      // only seed once please

}

// THIS IS THE BANDPAS FILTER. GENERATED AT www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html

//  BUTTERWORTH LOWPASS ORDER = 3; SAMPLERATE = 1mS; CORNER = 5Hz

    Lxv[0] = Lxv[1]; Lxv[1] = Lxv[2]; Lxv[2] = Lxv[3];

    Lxv[3] = NSignal<<10;    // insert the normalized data into the lowpass filter

    Lyv[0] = Lyv[1]; Lyv[1] = Lyv[2]; Lyv[2] = Lyv[3];

    Lyv[3] = (Lxv[0] + Lxv[3]) + 3 * (Lxv[1] + Lxv[2])

          + (3846 * Lyv[0]) + (-11781 * Lyv[1]) + (12031 * Lyv[2]);

//  Butterworth; Highpass; Order = 3; Sample Rate = 1mS; Corner = .8Hz

    Hxv[0] = Hxv[1]; Hxv[1] = Hxv[2]; Hxv[2] = Hxv[3];

    Hxv[3] = Lyv[3] / 4116; // insert lowpass result into highpass filter

    Hyv[0] = Hyv[1]; Hyv[1] = Hyv[2]; Hyv[2] = Hyv[3];

    Hyv[3] = (Hxv[3]-Hxv[0]) + 3 * (Hxv[1] - Hxv[2])

          + (8110 * Hyv[0]) + (-12206 * Hyv[1]) + (12031 * Hyv[2]);

FSignal = Hyv[3] >> Scale;  // result of highpass shift-scaled

 

 

//PLAY AROUND WITH THE SHIFT VALUE TO SCALE THE OUTPUT ~12 <> ~20 = High <> Low Amplification.

 

 

if (FSignal >= Peak && Pulse == false){  // heart beat causes ADC readings to surge down in value. 

  Peak = FSignal;                        // finding the moment when the downward pulse starts

  peakTime = sampleCounter;              // recodrd the time to derive HRV.

}

//  NOW IT'S TIME TO LOOK FOR THE HEART BEAT

if ((sampleCounter %20) == 0){// only look for the beat every 20mS. This clears out alot of high frequency noise.

  if (FSignal < 0 && Pulse == false){  // signal surges down in value every time there is a pulse

     Pulse = true;                     // Pulse will stay true as long as pulse signal < 0

     //digitalWrite(10,HIGH);

 

 

       // Serial.print("tone is coming from sample counter if");     // pin 13 will stay high as long as pulse signal < 0 

     Fade = 255;                       // set the fade value to highest for fading LED on pin 11 (optional)  

     HRV = peakTime - lastPeakTime;    // measure time between beats

     lastPeakTime = peakTime;          // keep track of time for next pulse

     B = true;                         // set the Quantified Self flag when HRV gets updated. NOT cleared inside this ISR    

     rate += HRV;                      // add to the running total of HRV used to determine heart rate

     beatCounter++;                     // beatCounter times when to calculate bpm by averaging the beat time values

     if (beatCounter == 10){            // derive heart rate every 10 beats. adjust as needed

       rate /= beatCounter;             // averaging time between beats

       BPM = 60000/rate;                // how many beats can fit into a minute?

       beatCounter = 0;                 // reset counter

       rate = 0;                        // reset running total

       QS = true;                       // set Beat flag when BPM gets updated. NOT cleared inside this ISR

     }

  }

  if (FSignal > 0 && Pulse == true)

  {    // when the values are going up, it's the time between beats

// Serial.print("tone is coming from FSignal if");

  //  digitalWrite(10,LOW);               // so turn off the pin 13 LED

    Pulse = false;                      // reset these variables so we can do it again!

    Peak = 0;                           //

  }

}

 

 

}// end isr

  • Sign in to reply
  • Cancel
Parents
  • shabaz
    shabaz over 11 years ago

    Hi Deirdre,

     

    This is not enough information I'm afraid. How do you know the issue is in the code? I'm guessing the code is copied from somewhere, otherwise it would be easier for you to test it bit-by-bit.

    Crackling sound could mean you have an electrical issue (and it is more likely). Also, where did you determine the rate was 800, was that some unprocessed value in debug that you enabled? The code implements a filter.

    Finally, unless someone has tried this exact project, it's unlikely we'll be able to work through this code without considerable effort, to know if it can actually work. Although the project was on the Internet, how can you be sure it was a working project?

    But definitely first off, confirm your circuit, and write a simpler program (tones only) to check the circuit. Then at least you have a chance of trying to debug this, but it will need you to experiment and try things, this is not something that is easily checked by visual inspection.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 11 years ago in reply to shabaz

    Hi,

    Thanks for your quick reply, much appreciated. I am new to arduino and this is a college project that I have been working on for a while now and its due very soon. It was an idea of my own to hook up a sound speaker for the device when the user is out walking or running the sound increases or decreases in velocity to let the user know what is happening, so to speak. Are you saying this is not possible? Am I wasting my time?

     

    The rate determined(800)  was viewed on the serial monitor I am managing to get heart sensor ratings coming in on the monitor that displays the data. (When its attached to your finger the data coming in is ranging from almost 100 to 900.)

    Using this data I am trying to syn it with sound.

     

    Ya I tried that before as well, and then I wasnt getting sound either

    iwas using

    tone(pin, frequency, duration)

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 11 years ago in reply to Former Member

    Any other ideas or guidance on this area?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • shabaz
    shabaz over 11 years ago in reply to Former Member

    Deirdre Griffin wrote:

    Ya I tried that before as well, and then I wasnt getting sound either

    iwas using

    tone(pin, frequency, duration)

    If you're not getting a sound with a smaller program, that needs to be resolved. It's likely to be the circuit. How are you connecting your speaker?

    Deirdre Griffin wrote:

     

    The rate determined(800)  was viewed on the serial monitor I am managing to get heart sensor ratings coming in on the monitor that displays the data. (When its attached to your finger the data coming in is ranging from almost 100 to 900.)

    I've not looked in any detail but the code appears to implement some filtering, so the output should not be 100-900bpm, although the input may appear to fluctuate all over.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • mcb1
    mcb1 over 11 years ago in reply to shabaz

    Deidre

     

    You might want to check out this link

    https://www.sparkfun.com/products/11574

    http://pulsesensor.myshopify.com/blogs/news/6877119-announcing-code-version-1-1-its-out-of-beta

     

    It includes code for flashing, and talks about speaker, but that could be from the Processing (computer) software.

     

    Mark

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 11 years ago in reply to mcb1

    thanks for that, yes it includes processing my project is a wearable and at the moment the sound is terrible.

    It is supposed to be when the heart races the sound also increases or plays some kind of melody. But at the moment I have an awful tone

    I am not much of a coder but the heart sensor seems complex and not sure is that interefering with the sound or what is it.

    can anyone help attached below is the code

     

    long Hxv[4]; // these arrays are used in the digital filter

      long Hyv[4]; // H for highpass, L for lowpass

      long Lxv[4];

      long Lyv[4];

      unsigned long readings; // used to help normalize the signal

      unsigned long peakTime; // used to time the start of the heart pulse

      unsigned long lastPeakTime = 0;// used to find the time between beats

      volatile int Peak;     // used to locate the highest point in positive phase of heart beat waveform

      int rate;              // used to help determine pulse rate

      volatile int BPM;      // used to hold the pulse rate

      int offset = 0;        // used to normalize the raw data

      int sampleCounter;     // used to determine pulse timing

      int beatCounter = 1;   // used to keep track of pulses

      volatile int Signal;   // holds the incoming raw data

      int NSignal;           // holds the normalized signal

      volatile int FSignal;  // holds result of the bandpass filter

      volatile int HRV;      // holds the time between beats

      volatile int Scale = 13;  // used to scale the result of the digital filter. range 12<>20 : high<>low amplification

      volatile int Fade = 0;

      // i changed them all to const does that make a difference? i think its ok hard to tell when things dont work

      const int BUTTON = 2; // the input pin where the button is

      int buttonVal =0; //this will be used to store data

      int speakerPin = 10;

      int pause = 100;

      int note1 = 500; // music note A4

      int note2 = 900;

      int note3 = 1200;

      int note4 = 1500;

      boolean first = true; // reminds us to seed the filter on the first go

      volatile boolean Pulse = false;  // becomes true when there is a heart pulse

      volatile boolean B = false;     // becomes true when there is a heart pulse

      volatile boolean QS = false;      // becomes true when pulse rate is determined. every 20 pulses

      int pulsePin = 0;  // pulse sensor purple wire connected to analog pin 0

     

      int potPin = A1;    // select the input pin for the potentiometer

      int potval = 0;

      int play = 0;

     

      const int xpin = A2;                  // x-axis of the accelerometer

      const int ypin = A3;                  // y-axis

      const int zpin = A4;                  // z-axis (only on 3-axis models)

     

      void setup() {

     

      Serial.begin(115200); // we agree to talk fast!

     

      pinMode(potPin, INPUT);

      pinMode(10, OUTPUT); //Speaker pin set as output

      pinMode(BUTTON, INPUT); // and set BUTTON as an input

      pinMode(13,OUTPUT);    // pin 13 will blink to your heartbeat!

      // this next bit will wind up in the library. it initializes Timer1 to throw an interrupt every 1mS.

      TCCR1A = 0x00; // DISABLE OUTPUTS AND BREAK PWM ON DIGITAL PINS 9 & 10

      TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER

      TCCR1C = 0x00; // DON'T FORCE COMPARE

      TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)

      ICR1 = 8000;   // TRIGGER TIMER INTERRUPT EVERY 1mS 

      sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED

      }

     

      void loop()

      {

        // print the sensor values:

      Serial.print(analogRead(xpin));

      // print a tab between values:

      Serial.print("\t");

      Serial.print(analogRead(ypin));

      // print a tab between values:

      Serial.print("\t");

      Serial.print(analogRead(zpin));

      Serial.println();

      // delay before next reading:

      delay(100);

       

       

       

        Serial.print("S");          // S tells processing that the following string is sensor data

        Serial.println(Signal);     // Signal holds the latest raw Pulse Sensor signal

        if (B == true)

        {                            //  B is true when arduino finds the heart beat

          Serial.print("B");        // 'B' tells Processing the following string is HRV data (time between beats in mS)

       /*   buttonVal = digitalRead(BUTTON); // reads input the value from the button and store it

        if (buttonVal =- HIGH) {

         //play the sound when you hold it.

          for (int i=0; i<3; i++){

            tone(speakerPin, note, 900);

            delay(20);

            noTone(speakerPin);

            }

        }else {

          //don't play the sound.

        }*/

          Serial.println(HRV);       //  HRV holds the time between this pulse and the last pulse in mS

          B = false;                // reseting the QS for next time

         

        }

        if (QS == true)

        {                            //  QS is true when arduino derives the heart rate by averaging HRV over 20 beats

          Serial.print("Q");        //  'QS' tells Processing that the following string is heart rate data

        

        buttonVal = digitalRead(BUTTON); // reads input the value from the button and store it

        potval = analogRead(potPin);    // read the value from the sensor

        if (buttonVal == HIGH)

        {

          play = 1;

        }

       

        if (play == 1){

          //do nothing, basically you can't access the sound code, so it won't play the sound

          if(BPM <= 25){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval, 300);

          delay(20);

          noTone(speakerPin);

        }

      

        }

        else if(BPM > 25){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval+10, 300);

          delay(20);

          noTone(speakerPin);

        }

        }else if(BPM > 50){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval+30, 300);

          delay(20);

          noTone(speakerPin);

        }

        }else if(BPM > 75){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval+50, 300);

          delay(20);

          noTone(speakerPin);

        }

        }

        }else

        {

          //play the tone

         }

          Serial.println(BPM);      //  BPM holds the heart rate in beats per minute

          QS = false;               //  reset the B for next time

        }

        Fade -= 15;

        Fade = constrain(Fade,0,255);

        analogWrite(11,Fade);

       

      delay(20);                    //  take a break

     

      }

     

      // THIS IS THE TIMER 1 INTERRUPT SERVICE ROUTINE. IT WILL BE PUT INTO THE LIBRARY

      ISR(TIMER1_OVF_vect){ // triggered every time Timer 1 overflows

      // Timer 1 makes sure that we take a reading every milisecond

      Signal = analogRead(pulsePin);

     

      // First normailize the waveform around 0

      readings += Signal; // take a running total

      sampleCounter++;     // we do this every milisecond. this timer is used as a clock

      if ((sampleCounter %300) == 0){   // adjust as needed

        offset = readings / 300;        // average the running total

        readings = 0;                   // reset running total

      }

      NSignal = Signal - offset;        // normalizing here

     

      // IF IT'S THE FIRST TIME THROUGH THE SKETCH, SEED THE FILTER WITH CURRENT DATA

      if (first = true){

        for (int i=0; i<4; i++){

          Lxv[i] = Lyv[i] = NSignal <<10;  // seed the lowpass filter

          Hxv[i] = Hyv[i] = NSignal <<10;  // seed the highpass filter

        }

      first = false;      // only seed once please

      }

      // THIS IS THE BANDPAS FILTER. GENERATED AT www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html

      //  BUTTERWORTH LOWPASS ORDER = 3; SAMPLERATE = 1mS; CORNER = 5Hz

          Lxv[0] = Lxv[1]; Lxv[1] = Lxv[2]; Lxv[2] = Lxv[3];

          Lxv[3] = NSignal<<10;    // insert the normalized data into the lowpass filter

          Lyv[0] = Lyv[1]; Lyv[1] = Lyv[2]; Lyv[2] = Lyv[3];

          Lyv[3] = (Lxv[0] + Lxv[3]) + 3 * (Lxv[1] + Lxv[2])

                + (3846 * Lyv[0]) + (-11781 * Lyv[1]) + (12031 * Lyv[2]);

      //  Butterworth; Highpass; Order = 3; Sample Rate = 1mS; Corner = .8Hz

          Hxv[0] = Hxv[1]; Hxv[1] = Hxv[2]; Hxv[2] = Hxv[3];

          Hxv[3] = Lyv[3] / 4116; // insert lowpass result into highpass filter

          Hyv[0] = Hyv[1]; Hyv[1] = Hyv[2]; Hyv[2] = Hyv[3];

          Hyv[3] = (Hxv[3]-Hxv[0]) + 3 * (Hxv[1] - Hxv[2])

                + (8110 * Hyv[0]) + (-12206 * Hyv[1]) + (12031 * Hyv[2]);

      FSignal = Hyv[3] >> Scale;  // result of highpass shift-scaled

     

      //PLAY AROUND WITH THE SHIFT VALUE TO SCALE THE OUTPUT ~12 <> ~20 = High <> Low Amplification.

     

      if (FSignal >= Peak && Pulse == false)

      {  // heart beat causes ADC readings to surge down in value. 

        Peak = FSignal;                        // finding the moment when the downward pulse starts

        peakTime = sampleCounter;              // recodrd the time to derive HRV.

      }

      //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT

      if ((sampleCounter %20) == 0)

      {// only look for the beat every 20mS. This clears out alot of high frequency noise.

        if (FSignal < 0 && Pulse == false)

        {  // signal surges down in value every time there is a pulse

           Pulse = true;                     // Pulse will stay true as long as pulse signal < 0

           digitalWrite(13,HIGH);           // pin 13 will stay high as long as pulse signal < 0 

          

         

           

           Fade = 255;                       // set the fade value to highest for fading LED on pin 11 (optional)  

           HRV = peakTime - lastPeakTime;    // measure time between beats

           lastPeakTime = peakTime;          // keep track of time for next pulse

           B = true;                         // set the Quantified Self flag when HRV gets updated. NOT cleared inside this ISR    

           rate += HRV;                      // add to the running total of HRV used to determine heart rate

           beatCounter++;                     // beatCounter times when to calculate bpm by averaging the beat time values

           if (beatCounter == 10)

           {            // derive heart rate every 10 beats. adjust as needed

             rate /= beatCounter;             // averaging time between beats

             BPM = 60000/rate;                // how many beats can fit into a minute?

             beatCounter = 0;                 // reset counter

             rate = 0;                        // reset running total

             QS = true;                       // set Beat flag when BPM gets updated. NOT cleared inside this ISR

           }

        }

        if (FSignal > 0 && Pulse == true)

        {    // when the values are going up, it's the time between beats

          digitalWrite(13,LOW);               // so turn off the pin 13 LED

         

        

         

          Pulse = false;                      // reset these variables so we can do it again!

          Peak = 0;                           //

        }

      }play = 0;

     

      }// end isr

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • Former Member
    Former Member over 11 years ago in reply to mcb1

    thanks for that, yes it includes processing my project is a wearable and at the moment the sound is terrible.

    It is supposed to be when the heart races the sound also increases or plays some kind of melody. But at the moment I have an awful tone

    I am not much of a coder but the heart sensor seems complex and not sure is that interefering with the sound or what is it.

    can anyone help attached below is the code

     

    long Hxv[4]; // these arrays are used in the digital filter

      long Hyv[4]; // H for highpass, L for lowpass

      long Lxv[4];

      long Lyv[4];

      unsigned long readings; // used to help normalize the signal

      unsigned long peakTime; // used to time the start of the heart pulse

      unsigned long lastPeakTime = 0;// used to find the time between beats

      volatile int Peak;     // used to locate the highest point in positive phase of heart beat waveform

      int rate;              // used to help determine pulse rate

      volatile int BPM;      // used to hold the pulse rate

      int offset = 0;        // used to normalize the raw data

      int sampleCounter;     // used to determine pulse timing

      int beatCounter = 1;   // used to keep track of pulses

      volatile int Signal;   // holds the incoming raw data

      int NSignal;           // holds the normalized signal

      volatile int FSignal;  // holds result of the bandpass filter

      volatile int HRV;      // holds the time between beats

      volatile int Scale = 13;  // used to scale the result of the digital filter. range 12<>20 : high<>low amplification

      volatile int Fade = 0;

      // i changed them all to const does that make a difference? i think its ok hard to tell when things dont work

      const int BUTTON = 2; // the input pin where the button is

      int buttonVal =0; //this will be used to store data

      int speakerPin = 10;

      int pause = 100;

      int note1 = 500; // music note A4

      int note2 = 900;

      int note3 = 1200;

      int note4 = 1500;

      boolean first = true; // reminds us to seed the filter on the first go

      volatile boolean Pulse = false;  // becomes true when there is a heart pulse

      volatile boolean B = false;     // becomes true when there is a heart pulse

      volatile boolean QS = false;      // becomes true when pulse rate is determined. every 20 pulses

      int pulsePin = 0;  // pulse sensor purple wire connected to analog pin 0

     

      int potPin = A1;    // select the input pin for the potentiometer

      int potval = 0;

      int play = 0;

     

      const int xpin = A2;                  // x-axis of the accelerometer

      const int ypin = A3;                  // y-axis

      const int zpin = A4;                  // z-axis (only on 3-axis models)

     

      void setup() {

     

      Serial.begin(115200); // we agree to talk fast!

     

      pinMode(potPin, INPUT);

      pinMode(10, OUTPUT); //Speaker pin set as output

      pinMode(BUTTON, INPUT); // and set BUTTON as an input

      pinMode(13,OUTPUT);    // pin 13 will blink to your heartbeat!

      // this next bit will wind up in the library. it initializes Timer1 to throw an interrupt every 1mS.

      TCCR1A = 0x00; // DISABLE OUTPUTS AND BREAK PWM ON DIGITAL PINS 9 & 10

      TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER

      TCCR1C = 0x00; // DON'T FORCE COMPARE

      TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)

      ICR1 = 8000;   // TRIGGER TIMER INTERRUPT EVERY 1mS 

      sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED

      }

     

      void loop()

      {

        // print the sensor values:

      Serial.print(analogRead(xpin));

      // print a tab between values:

      Serial.print("\t");

      Serial.print(analogRead(ypin));

      // print a tab between values:

      Serial.print("\t");

      Serial.print(analogRead(zpin));

      Serial.println();

      // delay before next reading:

      delay(100);

       

       

       

        Serial.print("S");          // S tells processing that the following string is sensor data

        Serial.println(Signal);     // Signal holds the latest raw Pulse Sensor signal

        if (B == true)

        {                            //  B is true when arduino finds the heart beat

          Serial.print("B");        // 'B' tells Processing the following string is HRV data (time between beats in mS)

       /*   buttonVal = digitalRead(BUTTON); // reads input the value from the button and store it

        if (buttonVal =- HIGH) {

         //play the sound when you hold it.

          for (int i=0; i<3; i++){

            tone(speakerPin, note, 900);

            delay(20);

            noTone(speakerPin);

            }

        }else {

          //don't play the sound.

        }*/

          Serial.println(HRV);       //  HRV holds the time between this pulse and the last pulse in mS

          B = false;                // reseting the QS for next time

         

        }

        if (QS == true)

        {                            //  QS is true when arduino derives the heart rate by averaging HRV over 20 beats

          Serial.print("Q");        //  'QS' tells Processing that the following string is heart rate data

        

        buttonVal = digitalRead(BUTTON); // reads input the value from the button and store it

        potval = analogRead(potPin);    // read the value from the sensor

        if (buttonVal == HIGH)

        {

          play = 1;

        }

       

        if (play == 1){

          //do nothing, basically you can't access the sound code, so it won't play the sound

          if(BPM <= 25){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval, 300);

          delay(20);

          noTone(speakerPin);

        }

      

        }

        else if(BPM > 25){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval+10, 300);

          delay(20);

          noTone(speakerPin);

        }

        }else if(BPM > 50){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval+30, 300);

          delay(20);

          noTone(speakerPin);

        }

        }else if(BPM > 75){

         for (int i=0; i<3; i++)

        {

          tone(speakerPin, potval+50, 300);

          delay(20);

          noTone(speakerPin);

        }

        }

        }else

        {

          //play the tone

         }

          Serial.println(BPM);      //  BPM holds the heart rate in beats per minute

          QS = false;               //  reset the B for next time

        }

        Fade -= 15;

        Fade = constrain(Fade,0,255);

        analogWrite(11,Fade);

       

      delay(20);                    //  take a break

     

      }

     

      // THIS IS THE TIMER 1 INTERRUPT SERVICE ROUTINE. IT WILL BE PUT INTO THE LIBRARY

      ISR(TIMER1_OVF_vect){ // triggered every time Timer 1 overflows

      // Timer 1 makes sure that we take a reading every milisecond

      Signal = analogRead(pulsePin);

     

      // First normailize the waveform around 0

      readings += Signal; // take a running total

      sampleCounter++;     // we do this every milisecond. this timer is used as a clock

      if ((sampleCounter %300) == 0){   // adjust as needed

        offset = readings / 300;        // average the running total

        readings = 0;                   // reset running total

      }

      NSignal = Signal - offset;        // normalizing here

     

      // IF IT'S THE FIRST TIME THROUGH THE SKETCH, SEED THE FILTER WITH CURRENT DATA

      if (first = true){

        for (int i=0; i<4; i++){

          Lxv[i] = Lyv[i] = NSignal <<10;  // seed the lowpass filter

          Hxv[i] = Hyv[i] = NSignal <<10;  // seed the highpass filter

        }

      first = false;      // only seed once please

      }

      // THIS IS THE BANDPAS FILTER. GENERATED AT www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html

      //  BUTTERWORTH LOWPASS ORDER = 3; SAMPLERATE = 1mS; CORNER = 5Hz

          Lxv[0] = Lxv[1]; Lxv[1] = Lxv[2]; Lxv[2] = Lxv[3];

          Lxv[3] = NSignal<<10;    // insert the normalized data into the lowpass filter

          Lyv[0] = Lyv[1]; Lyv[1] = Lyv[2]; Lyv[2] = Lyv[3];

          Lyv[3] = (Lxv[0] + Lxv[3]) + 3 * (Lxv[1] + Lxv[2])

                + (3846 * Lyv[0]) + (-11781 * Lyv[1]) + (12031 * Lyv[2]);

      //  Butterworth; Highpass; Order = 3; Sample Rate = 1mS; Corner = .8Hz

          Hxv[0] = Hxv[1]; Hxv[1] = Hxv[2]; Hxv[2] = Hxv[3];

          Hxv[3] = Lyv[3] / 4116; // insert lowpass result into highpass filter

          Hyv[0] = Hyv[1]; Hyv[1] = Hyv[2]; Hyv[2] = Hyv[3];

          Hyv[3] = (Hxv[3]-Hxv[0]) + 3 * (Hxv[1] - Hxv[2])

                + (8110 * Hyv[0]) + (-12206 * Hyv[1]) + (12031 * Hyv[2]);

      FSignal = Hyv[3] >> Scale;  // result of highpass shift-scaled

     

      //PLAY AROUND WITH THE SHIFT VALUE TO SCALE THE OUTPUT ~12 <> ~20 = High <> Low Amplification.

     

      if (FSignal >= Peak && Pulse == false)

      {  // heart beat causes ADC readings to surge down in value. 

        Peak = FSignal;                        // finding the moment when the downward pulse starts

        peakTime = sampleCounter;              // recodrd the time to derive HRV.

      }

      //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT

      if ((sampleCounter %20) == 0)

      {// only look for the beat every 20mS. This clears out alot of high frequency noise.

        if (FSignal < 0 && Pulse == false)

        {  // signal surges down in value every time there is a pulse

           Pulse = true;                     // Pulse will stay true as long as pulse signal < 0

           digitalWrite(13,HIGH);           // pin 13 will stay high as long as pulse signal < 0 

          

         

           

           Fade = 255;                       // set the fade value to highest for fading LED on pin 11 (optional)  

           HRV = peakTime - lastPeakTime;    // measure time between beats

           lastPeakTime = peakTime;          // keep track of time for next pulse

           B = true;                         // set the Quantified Self flag when HRV gets updated. NOT cleared inside this ISR    

           rate += HRV;                      // add to the running total of HRV used to determine heart rate

           beatCounter++;                     // beatCounter times when to calculate bpm by averaging the beat time values

           if (beatCounter == 10)

           {            // derive heart rate every 10 beats. adjust as needed

             rate /= beatCounter;             // averaging time between beats

             BPM = 60000/rate;                // how many beats can fit into a minute?

             beatCounter = 0;                 // reset counter

             rate = 0;                        // reset running total

             QS = true;                       // set Beat flag when BPM gets updated. NOT cleared inside this ISR

           }

        }

        if (FSignal > 0 && Pulse == true)

        {    // when the values are going up, it's the time between beats

          digitalWrite(13,LOW);               // so turn off the pin 13 LED

         

        

         

          Pulse = false;                      // reset these variables so we can do it again!

          Peak = 0;                           //

        }

      }play = 0;

     

      }// end isr

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Children
  • mcb1
    mcb1 over 11 years ago in reply to Former Member

    Deirdre

     

    Can I suggest that you look at doing tones/sounds on their own, and then try integrating it.

     

    You don't mention what type of speaker/buzzer/beeper you are using, and the output quality from these varies CONSIDERABLY.

     

    I recall looking for sound and Arduino some time ago, and there were plenty of links, and some very good audio produced.

    You may well find a very useful piece of code that suits your needs, as it very hard to tell what you think is suitable v what we think.

    ie do you want a heart montor type beep that we are used to seeing on the TV/Movies?

    You mention melody, so would you play it faster.?

    Once you have a piece of sound, you should be able to integrate it.

     

    Line 52 says it will disable the Output and PWM on Pin 9 and 10, which is your choosen speaker pin.

    I'm not sure if it affects the tone function or not, but you may wish to choose a new pin.

     

    From line 107 you have introduced a delay of 20mS, but the ISR (Interupt Service Routine) suggests its going to look every 1mS for a heart beat.

    Rather than delay you might want to use the millis() timer (see the BlinkWithoutDelay example in Arduino IDE).

    Basically you note the time, and if less than 20mS then carry on and do other stuff, if the time has passed then do the sound change.

     

     

    Also when posting code ... select the >> to the right of HTML, then go down to Syntax Highlighting and select C++

    (It will be coloured, and in theory uch shorter ... but not here at my work for some reason)

     

      long Hxv[4]; // these arrays are used in the digital filter
      long Hyv[4]; // H for highpass, L for lowpass
      long Lxv[4];
      long Lyv[4];
      unsigned long readings; // used to help normalize the signal
      unsigned long peakTime; // used to time the start of the heart pulse
      unsigned long lastPeakTime = 0;// used to find the time between beats
      volatile int Peak;     // used to locate the highest point in positive phase of heart beat waveform
      int rate;              // used to help determine pulse rate
      volatile int BPM;      // used to hold the pulse rate
      int offset = 0;        // used to normalize the raw data
      int sampleCounter;     // used to determine pulse timing
      int beatCounter = 1;   // used to keep track of pulses
      volatile int Signal;   // holds the incoming raw data
      int NSignal;           // holds the normalized signal
      volatile int FSignal;  // holds result of the bandpass filter
      volatile int HRV;      // holds the time between beats
      volatile int Scale = 13;  // used to scale the result of the digital filter. range 12<>20 : high<>low amplification
      volatile int Fade = 0;
      // i changed them all to const does that make a difference? i think its ok hard to tell when things dont work
      const int BUTTON = 2; // the input pin where the button is
      int buttonVal =0; //this will be used to store data
      int speakerPin = 10;
      int pause = 100;
      int note1 = 500; // music note A4
      int note2 = 900;
      int note3 = 1200;
      int note4 = 1500;
      boolean first = true; // reminds us to seed the filter on the first go
      volatile boolean Pulse = false;  // becomes true when there is a heart pulse
      volatile boolean B = false;     // becomes true when there is a heart pulse
      volatile boolean QS = false;      // becomes true when pulse rate is determined. every 20 pulses
      int pulsePin = 0;  // pulse sensor purple wire connected to analog pin 0
    
      int potPin = A1;    // select the input pin for the potentiometer
      int potval = 0;
      int play = 0;
    
      const int xpin = A2;                  // x-axis of the accelerometer
      const int ypin = A3;                  // y-axis
      const int zpin = A4;                  // z-axis (only on 3-axis models)
    
      void setup() {
    
      Serial.begin(115200); // we agree to talk fast!
    
      pinMode(potPin, INPUT);
      pinMode(10, OUTPUT); //Speaker pin set as output
      pinMode(BUTTON, INPUT); // and set BUTTON as an input
      pinMode(13,OUTPUT);    // pin 13 will blink to your heartbeat!
      // this next bit will wind up in the library. it initializes Timer1 to throw an interrupt every 1mS.
      TCCR1A = 0x00; // DISABLE OUTPUTS AND BREAK PWM ON DIGITAL PINS 9 & 10
      TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER
      TCCR1C = 0x00; // DON'T FORCE COMPARE
      TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)
      ICR1 = 8000;   // TRIGGER TIMER INTERRUPT EVERY 1mS
      sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED
      }
    
      void loop()
      {
        // print the sensor values:
      Serial.print(analogRead(xpin));
      // print a tab between values:
      Serial.print("\t");
      Serial.print(analogRead(ypin));
      // print a tab between values:
      Serial.print("\t");
      Serial.print(analogRead(zpin));
      Serial.println();
      // delay before next reading:
      delay(100);
    
    
    
        Serial.print("S");          // S tells processing that the following string is sensor data
        Serial.println(Signal);     // Signal holds the latest raw Pulse Sensor signal
        if (B == true)
        {                            //  B is true when arduino finds the heart beat
          Serial.print("B");        // 'B' tells Processing the following string is HRV data (time between beats in mS)
       /*   buttonVal = digitalRead(BUTTON); // reads input the value from the button and store it
        if (buttonVal =- HIGH) {
         //play the sound when you hold it.
          for (int i=0; i<3; i++){
            tone(speakerPin, note, 900);
            delay(20);
            noTone(speakerPin);
            }
        }else {
          //don't play the sound.
        }*/
          Serial.println(HRV);       //  HRV holds the time between this pulse and the last pulse in mS
          B = false;                // reseting the QS for next time
       
        }
        if (QS == true)
        {                            //  QS is true when arduino derives the heart rate by averaging HRV over 20 beats
          Serial.print("Q");        //  'QS' tells Processing that the following string is heart rate data
      
        buttonVal = digitalRead(BUTTON); // reads input the value from the button and store it
        potval = analogRead(potPin);    // read the value from the sensor
        if (buttonVal == HIGH)
        {
          play = 1;
        }
    
        if (play == 1){
          //do nothing, basically you can't access the sound code, so it won't play the sound
          if(BPM <= 25){
         for (int i=0; i<3; i++)
        {
          tone(speakerPin, potval, 300);
          delay(20);
          noTone(speakerPin);
        }
    
        }
        else if(BPM > 25){
         for (int i=0; i<3; i++)
        {
          tone(speakerPin, potval+10, 300);
          delay(20);
          noTone(speakerPin);
        }
        }else if(BPM > 50){
         for (int i=0; i<3; i++)
        {
          tone(speakerPin, potval+30, 300);
          delay(20);
          noTone(speakerPin);
        }
        }else if(BPM > 75){
         for (int i=0; i<3; i++)
        {
          tone(speakerPin, potval+50, 300);
          delay(20);
          noTone(speakerPin);
        }
        }
        }else
        {
          //play the tone
         }
          Serial.println(BPM);      //  BPM holds the heart rate in beats per minute
          QS = false;               //  reset the B for next time
        }
        Fade -= 15;
        Fade = constrain(Fade,0,255);
        analogWrite(11,Fade);
    
      delay(20);                    //  take a break
    
      }
    
      // THIS IS THE TIMER 1 INTERRUPT SERVICE ROUTINE. IT WILL BE PUT INTO THE LIBRARY
      ISR(TIMER1_OVF_vect){ // triggered every time Timer 1 overflows
      // Timer 1 makes sure that we take a reading every milisecond
      Signal = analogRead(pulsePin);
    
      // First normailize the waveform around 0
      readings += Signal; // take a running total
      sampleCounter++;     // we do this every milisecond. this timer is used as a clock
      if ((sampleCounter %300) == 0){   // adjust as needed
        offset = readings / 300;        // average the running total
        readings = 0;                   // reset running total
      }
      NSignal = Signal - offset;        // normalizing here
    
      // IF IT'S THE FIRST TIME THROUGH THE SKETCH, SEED THE FILTER WITH CURRENT DATA
      if (first = true){
        for (int i=0; i<4; i++){
          Lxv[i] = Lyv[i] = NSignal <<10;  // seed the lowpass filter
          Hxv[i] = Hyv[i] = NSignal <<10;  // seed the highpass filter
        }
      first = false;      // only seed once please
      }
      // THIS IS THE BANDPAS FILTER. GENERATED AT www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
      //  BUTTERWORTH LOWPASS ORDER = 3; SAMPLERATE = 1mS; CORNER = 5Hz
          Lxv[0] = Lxv[1]; Lxv[1] = Lxv[2]; Lxv[2] = Lxv[3];
          Lxv[3] = NSignal<<10;    // insert the normalized data into the lowpass filter
          Lyv[0] = Lyv[1]; Lyv[1] = Lyv[2]; Lyv[2] = Lyv[3];
          Lyv[3] = (Lxv[0] + Lxv[3]) + 3 * (Lxv[1] + Lxv[2])
                + (3846 * Lyv[0]) + (-11781 * Lyv[1]) + (12031 * Lyv[2]);
      //  Butterworth; Highpass; Order = 3; Sample Rate = 1mS; Corner = .8Hz
          Hxv[0] = Hxv[1]; Hxv[1] = Hxv[2]; Hxv[2] = Hxv[3];
          Hxv[3] = Lyv[3] / 4116; // insert lowpass result into highpass filter
          Hyv[0] = Hyv[1]; Hyv[1] = Hyv[2]; Hyv[2] = Hyv[3];
          Hyv[3] = (Hxv[3]-Hxv[0]) + 3 * (Hxv[1] - Hxv[2])
                + (8110 * Hyv[0]) + (-12206 * Hyv[1]) + (12031 * Hyv[2]);
      FSignal = Hyv[3] >> Scale;  // result of highpass shift-scaled
    
      //PLAY AROUND WITH THE SHIFT VALUE TO SCALE THE OUTPUT ~12 <> ~20 = High <> Low Amplification.
    
      if (FSignal >= Peak && Pulse == false)
      {  // heart beat causes ADC readings to surge down in value.
        Peak = FSignal;                        // finding the moment when the downward pulse starts
        peakTime = sampleCounter;              // recodrd the time to derive HRV.
      }
      //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
      if ((sampleCounter %20) == 0)
      {// only look for the beat every 20mS. This clears out alot of high frequency noise.
        if (FSignal < 0 && Pulse == false)
        {  // signal surges down in value every time there is a pulse
           Pulse = true;                     // Pulse will stay true as long as pulse signal < 0
           digitalWrite(13,HIGH);           // pin 13 will stay high as long as pulse signal < 0
        
       
         
           Fade = 255;                       // set the fade value to highest for fading LED on pin 11 (optional)
           HRV = peakTime - lastPeakTime;    // measure time between beats
           lastPeakTime = peakTime;          // keep track of time for next pulse
           B = true;                         // set the Quantified Self flag when HRV gets updated. NOT cleared inside this ISR  
           rate += HRV;                      // add to the running total of HRV used to determine heart rate
           beatCounter++;                     // beatCounter times when to calculate bpm by averaging the beat time values
           if (beatCounter == 10)
           {            // derive heart rate every 10 beats. adjust as needed
             rate /= beatCounter;             // averaging time between beats
             BPM = 60000/rate;                // how many beats can fit into a minute?
             beatCounter = 0;                 // reset counter
             rate = 0;                        // reset running total
             QS = true;                       // set Beat flag when BPM gets updated. NOT cleared inside this ISR
           }
        }
        if (FSignal > 0 && Pulse == true)
        {    // when the values are going up, it's the time between beats
          digitalWrite(13,LOW);               // so turn off the pin 13 LED
          Pulse = false;                      // reset these variables so we can do it again!
          Peak = 0;                           //
        }
      }
      play = 0;
    
      }// end isr

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • colin_meikle@mentor.com
    colin_meikle@mentor.com over 11 years ago in reply to mcb1

    Hi Deirdre,

     

    I've used this pulse sensor (with MBED not Ardiuno but it makes no difference). I had some trouble getting good results when i first tried it, I had to experiment with mounting it on your finger. In my case it need to be in close contact but not too tight.

    Before developing your own code I'd use the example code supplied to get a reliable BPM . There is also  processing App that will draw the raw signal, you should use this to get a nice clean signal before continuing,

     

    As others have said you need to break the problem down and tackle it one piece at a time.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube