Robert Hill
/
FRDM_HR_
This is the Heart Rate demo program, testing and verifying the functionality of the HR sensor.
Revision 0:92d3ea9d3e67, committed 2016-02-24
- Comitter:
- roberthill04
- Date:
- Wed Feb 24 17:43:56 2016 +0000
- Commit message:
- Heart Rate Monitor
Changed in this revision
--- /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