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

Dependencies:   mbed

Committer:
roberthill04
Date:
Wed Feb 24 17:43:56 2016 +0000
Revision:
0:92d3ea9d3e67
Heart Rate Monitor

Who changed what in which revision?

UserRevisionLine numberNew contents of line
roberthill04 0:92d3ea9d3e67 1 #include "PulseSensor.h"
roberthill04 0:92d3ea9d3e67 2 #include "mbed.h"
roberthill04 0:92d3ea9d3e67 3 //#include "AnalogIn.h"
roberthill04 0:92d3ea9d3e67 4
roberthill04 0:92d3ea9d3e67 5 DigitalOut led_red(LED_RED);
roberthill04 0:92d3ea9d3e67 6 DigitalOut led_green(LED_GREEN);
roberthill04 0:92d3ea9d3e67 7 DigitalOut led_blue(LED_BLUE);
roberthill04 0:92d3ea9d3e67 8 DigitalIn sw2(SW2);
roberthill04 0:92d3ea9d3e67 9 DigitalIn sw3(SW3);
roberthill04 0:92d3ea9d3e67 10 Serial pc(USBTX, USBRX);
roberthill04 0:92d3ea9d3e67 11
roberthill04 0:92d3ea9d3e67 12 AnalogIn Pulse_Signal(A0); //Initialize analog input for pulse signal
roberthill04 0:92d3ea9d3e67 13
roberthill04 0:92d3ea9d3e67 14 bool Button_Pressed = true; //Initialize flag for output on terminal
roberthill04 0:92d3ea9d3e67 15
roberthill04 0:92d3ea9d3e67 16 PulseSensor::PulseSensor(PinName analogPin, void (*printDataCallback)(char,int), int callbackRateMs)
roberthill04 0:92d3ea9d3e67 17 {
roberthill04 0:92d3ea9d3e67 18 _started = false;
roberthill04 0:92d3ea9d3e67 19
roberthill04 0:92d3ea9d3e67 20 _pAin = new AnalogIn(analogPin);
roberthill04 0:92d3ea9d3e67 21
roberthill04 0:92d3ea9d3e67 22 _callbackRateMs = callbackRateMs;
roberthill04 0:92d3ea9d3e67 23
roberthill04 0:92d3ea9d3e67 24 _printDataCallback = printDataCallback;
roberthill04 0:92d3ea9d3e67 25 }
roberthill04 0:92d3ea9d3e67 26
roberthill04 0:92d3ea9d3e67 27
roberthill04 0:92d3ea9d3e67 28 PulseSensor::~PulseSensor()
roberthill04 0:92d3ea9d3e67 29 {
roberthill04 0:92d3ea9d3e67 30 delete _pAin;
roberthill04 0:92d3ea9d3e67 31 }
roberthill04 0:92d3ea9d3e67 32
roberthill04 0:92d3ea9d3e67 33
roberthill04 0:92d3ea9d3e67 34 void PulseSensor::process_data_ticker_callback(void)
roberthill04 0:92d3ea9d3e67 35 {
roberthill04 0:92d3ea9d3e67 36 _printDataCallback('S', Signal); // send Processing the raw Pulse Sensor data
roberthill04 0:92d3ea9d3e67 37 if (QS == true) { // Quantified Self flag is true when a heartbeat is found
roberthill04 0:92d3ea9d3e67 38 //fadeRate = 255; // Set 'fadeRate' Variable to 255 to fade LED with pulse
roberthill04 0:92d3ea9d3e67 39 _printDataCallback('B',BPM); // send heart rate with a 'B' prefix
roberthill04 0:92d3ea9d3e67 40 _printDataCallback('Q',IBI); // send time between beats with a 'Q' prefix
roberthill04 0:92d3ea9d3e67 41 QS = false; // reset the Quantified Self flag for next time
roberthill04 0:92d3ea9d3e67 42 }
roberthill04 0:92d3ea9d3e67 43 }
roberthill04 0:92d3ea9d3e67 44
roberthill04 0:92d3ea9d3e67 45
roberthill04 0:92d3ea9d3e67 46 void PulseSensor::sensor_ticker_callback(void)
roberthill04 0:92d3ea9d3e67 47 {
roberthill04 0:92d3ea9d3e67 48 Signal = 1023 * _pAin->read(); // read the Pulse Sensor
roberthill04 0:92d3ea9d3e67 49
roberthill04 0:92d3ea9d3e67 50
roberthill04 0:92d3ea9d3e67 51 sampleCounter += 2; // keep track of the time in mS with this variable
roberthill04 0:92d3ea9d3e67 52 int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
roberthill04 0:92d3ea9d3e67 53
roberthill04 0:92d3ea9d3e67 54 // find the peak and trough of the pulse wave
roberthill04 0:92d3ea9d3e67 55 if(Signal < thresh && N > (IBI/5)*3) { // avoid dichrotic noise by waiting 3/5 of last IBI
roberthill04 0:92d3ea9d3e67 56 if (Signal < T) { // T is the trough
roberthill04 0:92d3ea9d3e67 57 T = Signal; // keep track of lowest point in pulse wave
roberthill04 0:92d3ea9d3e67 58 }
roberthill04 0:92d3ea9d3e67 59 }
roberthill04 0:92d3ea9d3e67 60
roberthill04 0:92d3ea9d3e67 61 if(Signal > thresh && Signal > P) { // thresh condition helps avoid noise
roberthill04 0:92d3ea9d3e67 62 P = Signal; // P is the peak
roberthill04 0:92d3ea9d3e67 63 } // keep track of highest point in pulse wave
roberthill04 0:92d3ea9d3e67 64
roberthill04 0:92d3ea9d3e67 65 // NOW IT'S TIME TO LOOK FOR THE HEART BEAT
roberthill04 0:92d3ea9d3e67 66 // signal surges up in value every time there is a pulse
roberthill04 0:92d3ea9d3e67 67 if (N > 250) { // avoid high frequency noise by waiting
roberthill04 0:92d3ea9d3e67 68 //this also sets limit to HR sensor to max =240 BPMs
roberthill04 0:92d3ea9d3e67 69 if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ) {
roberthill04 0:92d3ea9d3e67 70 Pulse = true; // set the Pulse flag when we think there is a pulse
roberthill04 0:92d3ea9d3e67 71 //digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
roberthill04 0:92d3ea9d3e67 72 IBI = sampleCounter - lastBeatTime; // measure time between beats in mS
roberthill04 0:92d3ea9d3e67 73 lastBeatTime = sampleCounter; // keep track of time for next pulse
roberthill04 0:92d3ea9d3e67 74
roberthill04 0:92d3ea9d3e67 75 if(firstBeat) { // if it's the first time we found a beat, if firstBeat == TRUE
roberthill04 0:92d3ea9d3e67 76 firstBeat = false; // clear firstBeat flag
roberthill04 0:92d3ea9d3e67 77 return; // IBI value is unreliable so discard it
roberthill04 0:92d3ea9d3e67 78 }
roberthill04 0:92d3ea9d3e67 79 if(secondBeat) { // if this is the second beat, if secondBeat == TRUE
roberthill04 0:92d3ea9d3e67 80 secondBeat = false; // clear secondBeat flag
roberthill04 0:92d3ea9d3e67 81 for(int i=0; i<=9; i++) { // seed the running total to get a realisitic BPM at startup
roberthill04 0:92d3ea9d3e67 82 rate[i] = IBI;
roberthill04 0:92d3ea9d3e67 83 }
roberthill04 0:92d3ea9d3e67 84 }
roberthill04 0:92d3ea9d3e67 85
roberthill04 0:92d3ea9d3e67 86 // keep a running total of the last 10 IBI values
roberthill04 0:92d3ea9d3e67 87 long runningTotal = 0; // clear the runningTotal variable
roberthill04 0:92d3ea9d3e67 88
roberthill04 0:92d3ea9d3e67 89 for(int i=0; i<=8; i++) { // shift data in the rate array
roberthill04 0:92d3ea9d3e67 90 rate[i] = rate[i+1]; // and drop the oldest IBI value
roberthill04 0:92d3ea9d3e67 91 runningTotal += rate[i]; // add up the 9 oldest IBI values
roberthill04 0:92d3ea9d3e67 92 }
roberthill04 0:92d3ea9d3e67 93
roberthill04 0:92d3ea9d3e67 94 rate[9] = IBI; // add the latest IBI to the rate array
roberthill04 0:92d3ea9d3e67 95 runningTotal += rate[9]; // add the latest IBI to runningTotal
roberthill04 0:92d3ea9d3e67 96 runningTotal /= 10; // average the last 10 IBI values
roberthill04 0:92d3ea9d3e67 97 BPM = 60000/runningTotal; // how many beats can fit into a minute? that's BPM!
roberthill04 0:92d3ea9d3e67 98 QS = true; // set Quantified Self flag
roberthill04 0:92d3ea9d3e67 99 // QS FLAG IS NOT CLEARED INSIDE THIS ISR
roberthill04 0:92d3ea9d3e67 100 }
roberthill04 0:92d3ea9d3e67 101 }
roberthill04 0:92d3ea9d3e67 102
roberthill04 0:92d3ea9d3e67 103 if (Signal < thresh && Pulse == true) { // when the values are going down, the beat is over
roberthill04 0:92d3ea9d3e67 104 Pulse = false; // reset the Pulse flag so we can do it again
roberthill04 0:92d3ea9d3e67 105 amp = P - T; // get amplitude of the pulse wave
roberthill04 0:92d3ea9d3e67 106 thresh = amp/2 + T; // set thresh at 50% of the amplitude
roberthill04 0:92d3ea9d3e67 107 P = thresh; // reset these for next time
roberthill04 0:92d3ea9d3e67 108 T = thresh;
roberthill04 0:92d3ea9d3e67 109 }
roberthill04 0:92d3ea9d3e67 110
roberthill04 0:92d3ea9d3e67 111 if (N > 2500) { // if 2.5 seconds go by without a beat
roberthill04 0:92d3ea9d3e67 112 thresh = 512; // set thresh default
roberthill04 0:92d3ea9d3e67 113 P = 512; // set P default
roberthill04 0:92d3ea9d3e67 114 T = 512; // set T default
roberthill04 0:92d3ea9d3e67 115 lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
roberthill04 0:92d3ea9d3e67 116 firstBeat = true; // set these to avoid noise
roberthill04 0:92d3ea9d3e67 117 secondBeat = true; // when we get the heartbeat back
roberthill04 0:92d3ea9d3e67 118 }
roberthill04 0:92d3ea9d3e67 119 }
roberthill04 0:92d3ea9d3e67 120
roberthill04 0:92d3ea9d3e67 121 void sendDataToProcessing(char symbol, int data)
roberthill04 0:92d3ea9d3e67 122 {
roberthill04 0:92d3ea9d3e67 123 pc.printf("%c%d\r\n", symbol, data);
roberthill04 0:92d3ea9d3e67 124 }
roberthill04 0:92d3ea9d3e67 125
roberthill04 0:92d3ea9d3e67 126 int main()
roberthill04 0:92d3ea9d3e67 127 {
roberthill04 0:92d3ea9d3e67 128 pc.baud(9600);
roberthill04 0:92d3ea9d3e67 129 pc.printf("Hello World from FRDM-K64F board. This is the Heart Rate Demo Program. ");
roberthill04 0:92d3ea9d3e67 130 pc.printf("Press SW2 (Button Near FRDM Logo) to see current Heart Rate.\n ");
roberthill04 0:92d3ea9d3e67 131
roberthill04 0:92d3ea9d3e67 132 led_blue = 1; //LED is off
roberthill04 0:92d3ea9d3e67 133 led_green = 1;
roberthill04 0:92d3ea9d3e67 134 led_red = 1;
roberthill04 0:92d3ea9d3e67 135
roberthill04 0:92d3ea9d3e67 136 PulseSensor Pulse_Signal(A0, sendDataToProcessing);
roberthill04 0:92d3ea9d3e67 137 Pulse_Signal.start();
roberthill04 0:92d3ea9d3e67 138 while(1)
roberthill04 0:92d3ea9d3e67 139 {
roberthill04 0:92d3ea9d3e67 140
roberthill04 0:92d3ea9d3e67 141 if (sw2 == 0 && Button_Pressed == true)
roberthill04 0:92d3ea9d3e67 142 {
roberthill04 0:92d3ea9d3e67 143 Pulse_Signal.stop(); //stops the continuous signal
roberthill04 0:92d3ea9d3e67 144 pc.printf("Current Heart Rate is: %d BPM \t", Pulse_Signal.BPM);
roberthill04 0:92d3ea9d3e67 145 Button_Pressed= false;
roberthill04 0:92d3ea9d3e67 146
roberthill04 0:92d3ea9d3e67 147
roberthill04 0:92d3ea9d3e67 148 wait(1);
roberthill04 0:92d3ea9d3e67 149 }
roberthill04 0:92d3ea9d3e67 150 else if (sw3 == 0 && Button_Pressed == true)
roberthill04 0:92d3ea9d3e67 151 {
roberthill04 0:92d3ea9d3e67 152 Pulse_Signal.start(); //restarts the pulse signal
roberthill04 0:92d3ea9d3e67 153 // Button_Pressed= false;
roberthill04 0:92d3ea9d3e67 154 }
roberthill04 0:92d3ea9d3e67 155 Button_Pressed = true;
roberthill04 0:92d3ea9d3e67 156 }
roberthill04 0:92d3ea9d3e67 157 }
roberthill04 0:92d3ea9d3e67 158
roberthill04 0:92d3ea9d3e67 159 bool PulseSensor::start()
roberthill04 0:92d3ea9d3e67 160 {
roberthill04 0:92d3ea9d3e67 161 if (_started == false)
roberthill04 0:92d3ea9d3e67 162 {
roberthill04 0:92d3ea9d3e67 163 sampleCounter = 0;
roberthill04 0:92d3ea9d3e67 164 lastBeatTime = 0;
roberthill04 0:92d3ea9d3e67 165 P =512;
roberthill04 0:92d3ea9d3e67 166 T = 512;
roberthill04 0:92d3ea9d3e67 167 thresh = 512;
roberthill04 0:92d3ea9d3e67 168 amp = 100;
roberthill04 0:92d3ea9d3e67 169 firstBeat = true;
roberthill04 0:92d3ea9d3e67 170 secondBeat = true;
roberthill04 0:92d3ea9d3e67 171
roberthill04 0:92d3ea9d3e67 172 BPM=0;
roberthill04 0:92d3ea9d3e67 173 Signal=0;
roberthill04 0:92d3ea9d3e67 174 IBI = 600;
roberthill04 0:92d3ea9d3e67 175 Pulse = false;
roberthill04 0:92d3ea9d3e67 176 QS = false;
roberthill04 0:92d3ea9d3e67 177
roberthill04 0:92d3ea9d3e67 178 _pulseSensorTicker.attach(this, &PulseSensor::sensor_ticker_callback, ((float)_sensorTickRateMs/1000));
roberthill04 0:92d3ea9d3e67 179 _processDataTicker.attach(this, &PulseSensor::process_data_ticker_callback, ((float)_callbackRateMs/1000));
roberthill04 0:92d3ea9d3e67 180 _started = true;
roberthill04 0:92d3ea9d3e67 181 return true;
roberthill04 0:92d3ea9d3e67 182 }
roberthill04 0:92d3ea9d3e67 183 else
roberthill04 0:92d3ea9d3e67 184 {
roberthill04 0:92d3ea9d3e67 185 return false;
roberthill04 0:92d3ea9d3e67 186 }
roberthill04 0:92d3ea9d3e67 187 }
roberthill04 0:92d3ea9d3e67 188
roberthill04 0:92d3ea9d3e67 189 bool PulseSensor::stop()
roberthill04 0:92d3ea9d3e67 190 {
roberthill04 0:92d3ea9d3e67 191 if(_started == true)
roberthill04 0:92d3ea9d3e67 192 {
roberthill04 0:92d3ea9d3e67 193 _pulseSensorTicker.detach();
roberthill04 0:92d3ea9d3e67 194 _processDataTicker.detach();
roberthill04 0:92d3ea9d3e67 195 _started = false;
roberthill04 0:92d3ea9d3e67 196 return true;
roberthill04 0:92d3ea9d3e67 197 }
roberthill04 0:92d3ea9d3e67 198 else
roberthill04 0:92d3ea9d3e67 199 {
roberthill04 0:92d3ea9d3e67 200 return false;
roberthill04 0:92d3ea9d3e67 201 }
roberthill04 0:92d3ea9d3e67 202 }