This is the Heart Rate demo program, testing and verifying the functionality of the HR sensor.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
roberthill04
Date:
Wed Feb 24 17:43:56 2016 +0000
Commit message:
Heart Rate Monitor

Changed in this revision

HeartRate.cpp Show annotated file Show diff for this revision Revisions of this file
PulseSensor.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HeartRate.cpp	Wed Feb 24 17:43:56 2016 +0000
@@ -0,0 +1,202 @@
+#include "PulseSensor.h"
+#include "mbed.h"
+//#include "AnalogIn.h"
+
+DigitalOut led_red(LED_RED);
+DigitalOut led_green(LED_GREEN);
+DigitalOut led_blue(LED_BLUE);
+DigitalIn sw2(SW2);
+DigitalIn sw3(SW3);
+Serial pc(USBTX, USBRX);
+
+AnalogIn Pulse_Signal(A0);              //Initialize analog input for pulse signal
+
+bool Button_Pressed = true;     //Initialize flag for output on terminal
+ 
+PulseSensor::PulseSensor(PinName analogPin, void (*printDataCallback)(char,int), int callbackRateMs)
+{
+    _started = false;
+    
+    _pAin = new AnalogIn(analogPin);
+    
+    _callbackRateMs = callbackRateMs;
+    
+    _printDataCallback = printDataCallback;
+}
+ 
+ 
+PulseSensor::~PulseSensor()
+{
+    delete _pAin;
+}
+ 
+ 
+void PulseSensor::process_data_ticker_callback(void)
+{
+    _printDataCallback('S', Signal);        // send Processing the raw Pulse Sensor data
+    if (QS == true) {                       // Quantified Self flag is true when a heartbeat is found
+        //fadeRate = 255;                  // Set 'fadeRate' Variable to 255 to fade LED with pulse
+        _printDataCallback('B',BPM);        // send heart rate with a 'B' prefix
+        _printDataCallback('Q',IBI);        // send time between beats with a 'Q' prefix
+        QS = false;                         // reset the Quantified Self flag for next time
+    }
+}
+ 
+ 
+void PulseSensor::sensor_ticker_callback(void)
+{
+    Signal = 1023 * _pAin->read();              // read the Pulse Sensor
+    
+    
+    sampleCounter += 2;                         // keep track of the time in mS with this variable
+    int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise
+ 
+    //  find the peak and trough of the pulse wave
+    if(Signal < thresh && N > (IBI/5)*3) {      // avoid dichrotic noise by waiting 3/5 of last IBI
+        if (Signal < T) {                       // T is the trough
+            T = Signal;                         // keep track of lowest point in pulse wave
+        }
+    }
+ 
+    if(Signal > thresh && Signal > P) {         // thresh condition helps avoid noise
+        P = Signal;                             // P is the peak
+    }                                        // keep track of highest point in pulse wave
+ 
+    //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
+    // signal surges up in value every time there is a pulse
+    if (N > 250) {                                  // avoid high frequency noise by waiting 
+                                                    //this also sets limit to HR sensor to max =240 BPMs
+        if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ) {
+            Pulse = true;                               // set the Pulse flag when we think there is a pulse
+            //digitalWrite(blinkPin,HIGH);                // turn on pin 13 LED
+            IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
+            lastBeatTime = sampleCounter;               // keep track of time for next pulse
+ 
+            if(firstBeat) {                        // if it's the first time we found a beat, if firstBeat == TRUE
+                firstBeat = false;                 // clear firstBeat flag
+                return;                            // IBI value is unreliable so discard it
+            }
+            if(secondBeat) {                       // if this is the second beat, if secondBeat == TRUE
+                secondBeat = false;                 // clear secondBeat flag
+                for(int i=0; i<=9; i++) {        // seed the running total to get a realisitic BPM at startup
+                    rate[i] = IBI;
+                }
+            }
+ 
+            // keep a running total of the last 10 IBI values
+            long runningTotal = 0;                   // clear the runningTotal variable
+ 
+            for(int i=0; i<=8; i++) {               // shift data in the rate array
+                rate[i] = rate[i+1];                // and drop the oldest IBI value
+                runningTotal += rate[i];            // add up the 9 oldest IBI values
+            }
+ 
+            rate[9] = IBI;                          // add the latest IBI to the rate array
+            runningTotal += rate[9];                // add the latest IBI to runningTotal
+            runningTotal /= 10;                     // average the last 10 IBI values
+            BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
+            QS = true;                              // set Quantified Self flag
+            // QS FLAG IS NOT CLEARED INSIDE THIS ISR
+        }
+    }
+ 
+    if (Signal < thresh && Pulse == true) {    // when the values are going down, the beat is over
+        Pulse = false;                         // reset the Pulse flag so we can do it again
+        amp = P - T;                           // get amplitude of the pulse wave
+        thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
+        P = thresh;                            // reset these for next time
+        T = thresh;
+    }
+ 
+    if (N > 2500) {                            // if 2.5 seconds go by without a beat
+        thresh = 512;                          // set thresh default
+        P = 512;                               // set P default
+        T = 512;                               // set T default
+        lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date
+        firstBeat = true;                      // set these to avoid noise
+        secondBeat = true;                     // when we get the heartbeat back
+    }
+}
+
+void sendDataToProcessing(char symbol, int data)
+{
+    pc.printf("%c%d\r\n", symbol, data);
+}
+
+int main()
+{
+    pc.baud(9600);
+    pc.printf("Hello World from FRDM-K64F board. This is the Heart Rate Demo Program. ");
+    pc.printf("Press SW2 (Button Near FRDM Logo) to see current Heart Rate.\n ");
+    
+    led_blue =  1;                                       //LED is off
+    led_green = 1;
+    led_red =   1;
+    
+    PulseSensor Pulse_Signal(A0, sendDataToProcessing);
+    Pulse_Signal.start();
+    while(1)
+    {
+        
+        if (sw2 == 0 && Button_Pressed == true)
+        {
+          Pulse_Signal.stop();                 //stops the continuous signal
+          pc.printf("Current Heart Rate is: %d BPM \t", Pulse_Signal.BPM); 
+           Button_Pressed= false; 
+          
+         
+           wait(1);
+        }
+        else if (sw3 == 0 && Button_Pressed == true)
+        {
+            Pulse_Signal.start();               //restarts the pulse signal
+           // Button_Pressed= false; 
+        }
+        Button_Pressed = true;
+    }                                   
+}
+ 
+bool PulseSensor::start()
+{
+    if (_started == false)
+    {
+        sampleCounter = 0;
+        lastBeatTime = 0;
+        P =512;
+        T = 512;
+        thresh = 512;
+        amp = 100;
+        firstBeat = true;
+        secondBeat = true;
+        
+        BPM=0;
+        Signal=0;
+        IBI = 600;
+        Pulse = false;
+        QS = false;
+        
+        _pulseSensorTicker.attach(this, &PulseSensor::sensor_ticker_callback, ((float)_sensorTickRateMs/1000));
+        _processDataTicker.attach(this, &PulseSensor::process_data_ticker_callback,  ((float)_callbackRateMs/1000));
+        _started = true;
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+ 
+bool PulseSensor::stop()
+{
+    if(_started == true)
+    {
+        _pulseSensorTicker.detach();
+        _processDataTicker.detach();
+        _started = false;
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PulseSensor.h	Wed Feb 24 17:43:56 2016 +0000
@@ -0,0 +1,75 @@
+#ifndef PULSE_SENSOR_H
+#define PULSE_SENSOR_H
+ 
+#include "mbed.h"
+ 
+ 
+/**
+ * Class for interfacing with a http://pulsesensor.myshopify.com/ 'Pulse Sensor Amped'.
+ * The contents of this class are based on the "Pulse Sensor Amped 1.1" Arduino Sketch.
+ *
+ * When using this class for the first time, it is recommended that you use the Processing 
+ * GUI app available http://pulsesensor.myshopify.com/pages/code-and-guide. Using this, you
+ * will easily be able to verify the operating of your sensor, and the integration of this
+ * class into your mbed project. 
+ * WEBSITE is incorrect^^^
+ **/
+ 
+class PulseSensor
+{
+    private:
+        volatile int rate[10];                          // used to hold last ten IBI values
+        volatile unsigned long sampleCounter;          // used to determine pulse timing
+        volatile unsigned long lastBeatTime;           // used to find the inter beat interval
+        volatile int P;                                // used to find peak in pulse wave
+        volatile int T;                     // used to find trough in pulse wave
+        volatile int thresh;                // used to find instant moment of heart beat
+        volatile int amp;                   // used to hold amplitude of pulse waveform
+        volatile bool firstBeat;        // used to seed rate array so we startup with reasonable BPM
+        volatile bool secondBeat;       // used to seed rate array so we startup with reasonable BPM
+        
+        // these variables are volatile because they are used during the interrupt service routine!
+        
+        volatile int Signal;                // holds the incoming raw data
+        volatile int IBI;             // holds the time between beats, the Inter-Beat Interval
+        volatile bool Pulse;        // true when pulse wave is high, false when it's low
+        volatile bool QS;           // becomes true when a beat is found
+    
+    
+        void (*_printDataCallback)(char,int);
+        static const int _sensorTickRateMs = 2;
+        int       _callbackRateMs;
+        bool      _started;
+        
+        AnalogIn *_pAin;
+        Ticker    _pulseSensorTicker;
+        Ticker    _processDataTicker;
+        
+        void sensor_ticker_callback(void);
+        void process_data_ticker_callback(void);
+    
+    public:
+    
+         volatile int BPM;                   // used to hold the pulse rate
+        /** PulseSensor Constructor - Note this does not start the reading of the sensor.
+         * @param   analogPin Name of the analog pin that the sensor is connected to.
+         * @param   printDataCallback Pointer to function which will be called to print the latest data. Output format available here: http://pulsesensor.myshopify.com/pages/code-and-guide
+         * @param   callbackRateMs Rate at which the printDataCallback is to be called, recommended is 20ms for graphing of pulse signal.
+         */
+        PulseSensor(PinName analogPin, void (*printDataCallback)(char,int), int callbackRateMs=20);
+        
+        /** Destructor */
+        ~PulseSensor();
+        
+        /** Start reading the Pulse Sensor, and sending current readings to the print data callback.
+         * @returns true if reading of the sensor is started, false if reading was aleady in progress.
+         */
+        bool start();
+        
+        /** Stops the current reading of the Pulse Senson.
+         * @return true if reading is stopped, false if reading was already stopped.
+         */
+        bool stop();
+};
+ 
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Feb 24 17:43:56 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/252557024ec3
\ No newline at end of file