Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:e80a245c4d0d, committed 2014-02-09
- Comitter:
- donalm
- Date:
- Sun Feb 09 15:37:19 2014 +0000
- Child:
- 1:57f98c8ff4fd
- Commit message:
- Initial version.
Changed in this revision
| PulseSensor.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 |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PulseSensor.cpp Sun Feb 09 15:37:19 2014 +0000
@@ -0,0 +1,152 @@
+#include "PulseSensor.h"
+
+
+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
+ 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
+ }
+}
+
+
+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 Sun Feb 09 15:37:19 2014 +0000
@@ -0,0 +1,72 @@
+#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.
+ */
+
+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 BPM; // used to hold the pulse rate
+ 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:
+ /** 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