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
Reply
  • 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
Children
No Data
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