Heart Rate Monitor example for the BLE API using nRF51822 native mode drivers

Dependencies:   BLE_API mbed nRF51822

Fork of BLE_HeartRate by Bluetooth Low Energy

Committer:
ankuraga
Date:
Wed Sep 02 06:14:39 2015 +0000
Revision:
73:82447ab9efd8
Parent:
71:ecf479422c04
Simulating heart rate and temperature.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ankuraga 71:ecf479422c04 1 #include "PulseSensor.h"
ankuraga 71:ecf479422c04 2
ankuraga 71:ecf479422c04 3
ankuraga 71:ecf479422c04 4 PulseSensor::PulseSensor(PinName analogPin, void (*printDataCallback)(int), int callbackRateMs)
ankuraga 71:ecf479422c04 5 {
ankuraga 71:ecf479422c04 6 _started = false;
ankuraga 71:ecf479422c04 7
ankuraga 71:ecf479422c04 8 _pAin = new AnalogIn(analogPin);
ankuraga 71:ecf479422c04 9
ankuraga 71:ecf479422c04 10 _callbackRateMs = callbackRateMs;
ankuraga 71:ecf479422c04 11
ankuraga 71:ecf479422c04 12 _printDataCallback = printDataCallback;
ankuraga 71:ecf479422c04 13 }
ankuraga 71:ecf479422c04 14
ankuraga 71:ecf479422c04 15
ankuraga 71:ecf479422c04 16 PulseSensor::~PulseSensor()
ankuraga 71:ecf479422c04 17 {
ankuraga 71:ecf479422c04 18 delete _pAin;
ankuraga 71:ecf479422c04 19 }
ankuraga 71:ecf479422c04 20
ankuraga 71:ecf479422c04 21
ankuraga 71:ecf479422c04 22 void PulseSensor::process_data_ticker_callback(void)
ankuraga 71:ecf479422c04 23 {
ankuraga 71:ecf479422c04 24 // _printDataCallback(Signal); // send Processing the raw Pulse Sensor data
ankuraga 71:ecf479422c04 25 if (QS == true) { // Quantified Self flag is true when a heartbeat is found
ankuraga 71:ecf479422c04 26 //fadeRate = 255; // Set 'fadeRate' Variable to 255 to fade LED with pulse
ankuraga 71:ecf479422c04 27 _printDataCallback(BPM); // send heart rate with a 'B' prefix
ankuraga 71:ecf479422c04 28 //_printDataCallback(IBI); // send time between beats with a 'Q' prefix
ankuraga 71:ecf479422c04 29 QS = false; // reset the Quantified Self flag for next time
ankuraga 71:ecf479422c04 30 }
ankuraga 71:ecf479422c04 31 }
ankuraga 71:ecf479422c04 32
ankuraga 71:ecf479422c04 33
ankuraga 71:ecf479422c04 34 void PulseSensor::sensor_ticker_callback(void)
ankuraga 71:ecf479422c04 35 {
ankuraga 71:ecf479422c04 36 Signal = 1023 * _pAin->read(); // read the Pulse Sensor
ankuraga 71:ecf479422c04 37
ankuraga 71:ecf479422c04 38
ankuraga 71:ecf479422c04 39 sampleCounter += 2; // keep track of the time in mS with this variable
ankuraga 71:ecf479422c04 40 int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
ankuraga 71:ecf479422c04 41
ankuraga 71:ecf479422c04 42 // find the peak and trough of the pulse wave
ankuraga 71:ecf479422c04 43 if(Signal < thresh && N > (IBI/5)*3) { // avoid dichrotic noise by waiting 3/5 of last IBI
ankuraga 71:ecf479422c04 44 if (Signal < T) { // T is the trough
ankuraga 71:ecf479422c04 45 T = Signal; // keep track of lowest point in pulse wave
ankuraga 71:ecf479422c04 46 }
ankuraga 71:ecf479422c04 47 }
ankuraga 71:ecf479422c04 48
ankuraga 71:ecf479422c04 49 if(Signal > thresh && Signal > P) { // thresh condition helps avoid noise
ankuraga 71:ecf479422c04 50 P = Signal; // P is the peak
ankuraga 71:ecf479422c04 51 } // keep track of highest point in pulse wave
ankuraga 71:ecf479422c04 52
ankuraga 71:ecf479422c04 53 // NOW IT'S TIME TO LOOK FOR THE HEART BEAT
ankuraga 71:ecf479422c04 54 // signal surges up in value every time there is a pulse
ankuraga 71:ecf479422c04 55 if (N > 250) { // avoid high frequency noise
ankuraga 71:ecf479422c04 56 if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ) {
ankuraga 71:ecf479422c04 57 Pulse = true; // set the Pulse flag when we think there is a pulse
ankuraga 71:ecf479422c04 58 //digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
ankuraga 71:ecf479422c04 59 IBI = sampleCounter - lastBeatTime; // measure time between beats in mS
ankuraga 71:ecf479422c04 60 lastBeatTime = sampleCounter; // keep track of time for next pulse
ankuraga 71:ecf479422c04 61
ankuraga 71:ecf479422c04 62 if(firstBeat) { // if it's the first time we found a beat, if firstBeat == TRUE
ankuraga 71:ecf479422c04 63 firstBeat = false; // clear firstBeat flag
ankuraga 71:ecf479422c04 64 return; // IBI value is unreliable so discard it
ankuraga 71:ecf479422c04 65 }
ankuraga 71:ecf479422c04 66 if(secondBeat) { // if this is the second beat, if secondBeat == TRUE
ankuraga 71:ecf479422c04 67 secondBeat = false; // clear secondBeat flag
ankuraga 71:ecf479422c04 68 for(int i=0; i<=9; i++) { // seed the running total to get a realisitic BPM at startup
ankuraga 71:ecf479422c04 69 rate[i] = IBI;
ankuraga 71:ecf479422c04 70 }
ankuraga 71:ecf479422c04 71 }
ankuraga 71:ecf479422c04 72
ankuraga 71:ecf479422c04 73 // keep a running total of the last 10 IBI values
ankuraga 71:ecf479422c04 74 long runningTotal = 0; // clear the runningTotal variable
ankuraga 71:ecf479422c04 75
ankuraga 71:ecf479422c04 76 for(int i=0; i<=8; i++) { // shift data in the rate array
ankuraga 71:ecf479422c04 77 rate[i] = rate[i+1]; // and drop the oldest IBI value
ankuraga 71:ecf479422c04 78 runningTotal += rate[i]; // add up the 9 oldest IBI values
ankuraga 71:ecf479422c04 79 }
ankuraga 71:ecf479422c04 80
ankuraga 71:ecf479422c04 81 rate[9] = IBI; // add the latest IBI to the rate array
ankuraga 71:ecf479422c04 82 runningTotal += rate[9]; // add the latest IBI to runningTotal
ankuraga 71:ecf479422c04 83 runningTotal /= 10; // average the last 10 IBI values
ankuraga 71:ecf479422c04 84 BPM = 60000/runningTotal; // how many beats can fit into a minute? that's BPM!
ankuraga 71:ecf479422c04 85 QS = true; // set Quantified Self flag
ankuraga 71:ecf479422c04 86 // QS FLAG IS NOT CLEARED INSIDE THIS ISR
ankuraga 71:ecf479422c04 87 }
ankuraga 71:ecf479422c04 88 }
ankuraga 71:ecf479422c04 89
ankuraga 71:ecf479422c04 90 if (Signal < thresh && Pulse == true) { // when the values are going down, the beat is over
ankuraga 71:ecf479422c04 91 Pulse = false; // reset the Pulse flag so we can do it again
ankuraga 71:ecf479422c04 92 amp = P - T; // get amplitude of the pulse wave
ankuraga 71:ecf479422c04 93 thresh = amp/2 + T; // set thresh at 50% of the amplitude
ankuraga 71:ecf479422c04 94 P = thresh; // reset these for next time
ankuraga 71:ecf479422c04 95 T = thresh;
ankuraga 71:ecf479422c04 96 }
ankuraga 71:ecf479422c04 97
ankuraga 71:ecf479422c04 98 if (N > 2500) { // if 2.5 seconds go by without a beat
ankuraga 71:ecf479422c04 99 thresh = 512; // set thresh default
ankuraga 71:ecf479422c04 100 P = 512; // set P default
ankuraga 71:ecf479422c04 101 T = 512; // set T default
ankuraga 71:ecf479422c04 102 lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
ankuraga 71:ecf479422c04 103 firstBeat = true; // set these to avoid noise
ankuraga 71:ecf479422c04 104 secondBeat = true; // when we get the heartbeat back
ankuraga 71:ecf479422c04 105 }
ankuraga 71:ecf479422c04 106 }
ankuraga 71:ecf479422c04 107
ankuraga 71:ecf479422c04 108
ankuraga 71:ecf479422c04 109 bool PulseSensor::start()
ankuraga 71:ecf479422c04 110 {
ankuraga 71:ecf479422c04 111 if (_started == false)
ankuraga 71:ecf479422c04 112 {
ankuraga 71:ecf479422c04 113 sampleCounter = 0;
ankuraga 71:ecf479422c04 114 lastBeatTime = 0;
ankuraga 71:ecf479422c04 115 P =512;
ankuraga 71:ecf479422c04 116 T = 512;
ankuraga 71:ecf479422c04 117 thresh = 512;
ankuraga 71:ecf479422c04 118 amp = 100;
ankuraga 71:ecf479422c04 119 firstBeat = true;
ankuraga 71:ecf479422c04 120 secondBeat = true;
ankuraga 71:ecf479422c04 121
ankuraga 71:ecf479422c04 122 BPM=0;
ankuraga 71:ecf479422c04 123 Signal=0;
ankuraga 71:ecf479422c04 124 IBI = 600;
ankuraga 71:ecf479422c04 125 Pulse = false;
ankuraga 71:ecf479422c04 126 QS = false;
ankuraga 71:ecf479422c04 127
ankuraga 71:ecf479422c04 128 _pulseSensorTicker.attach(this, &PulseSensor::sensor_ticker_callback, ((float)_sensorTickRateMs/1000));
ankuraga 71:ecf479422c04 129 _processDataTicker.attach(this, &PulseSensor::process_data_ticker_callback, ((float)_callbackRateMs/1000));
ankuraga 71:ecf479422c04 130 _started = true;
ankuraga 71:ecf479422c04 131 return true;
ankuraga 71:ecf479422c04 132 }
ankuraga 71:ecf479422c04 133 else
ankuraga 71:ecf479422c04 134 {
ankuraga 71:ecf479422c04 135 return false;
ankuraga 71:ecf479422c04 136 }
ankuraga 71:ecf479422c04 137 }
ankuraga 71:ecf479422c04 138
ankuraga 71:ecf479422c04 139 bool PulseSensor::stop()
ankuraga 71:ecf479422c04 140 {
ankuraga 71:ecf479422c04 141 if(_started == true)
ankuraga 71:ecf479422c04 142 {
ankuraga 71:ecf479422c04 143 _pulseSensorTicker.detach();
ankuraga 71:ecf479422c04 144 _processDataTicker.detach();
ankuraga 71:ecf479422c04 145 _started = false;
ankuraga 71:ecf479422c04 146 return true;
ankuraga 71:ecf479422c04 147 }
ankuraga 71:ecf479422c04 148 else
ankuraga 71:ecf479422c04 149 {
ankuraga 71:ecf479422c04 150 return false;
ankuraga 71:ecf479422c04 151 }
ankuraga 71:ecf479422c04 152 }
ankuraga 71:ecf479422c04 153
ankuraga 71:ecf479422c04 154