Library for interfacing with a 'Pulse Sensor Amped', from http://pulsesensor.myshopify.com

Dependents:   finalProject PulseSense HealthCare_Graduation 4180project ... more

Simple mbed application for monitoring a pulse sensor

#include "mbed.h"
#include "PulseSensor.h"

Serial pc(USBTX, USBRX);
    

/** Print the data in a format that can be parsed by the 
 *  Processing application available here: http://pulsesensor.myshopify.com/pages/code-and-guide
 */
void sendDataToProcessing(char symbol, int data)
{
    pc.printf("%c%d\r\n", symbol, data);
}



int main() {
    
    PulseSensor sensor(p15, sendDataToProcessing);

    pc.baud(115200);
    
    sensor.start();

    while(1) {
    }
}

/media/uploads/donalm/mbed_pulsesensor_scaled.png

Committer:
donalm
Date:
Sun Feb 09 15:37:19 2014 +0000
Revision:
0:e80a245c4d0d
Initial version.

Who changed what in which revision?

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