Optical heart rate monitor using photoresistor and LED to calculate BPM, which is outputted to LCD screen.

Dependencies:   4DGL-uLCD-SE mbed

Fork of uLCD144G2_demo by jim hamblen

Committer:
maryannionascu
Date:
Thu Oct 22 20:24:19 2015 +0000
Revision:
9:b2a894f94cb7
Parent:
8:31e63caf37e2
Child:
10:ad2548407023
final;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
4180_1 0:cfcf73272647 1 #include "mbed.h"
4180_1 2:75727e89a717 2 #include "uLCD_4DGL.h"
4180_1 0:cfcf73272647 3
maryannionascu 9:b2a894f94cb7 4 //Calculates the BPM using a photoresistor as input and outputs the BPM to an LCD screen.
maryannionascu 9:b2a894f94cb7 5 uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin;
maryannionascu 9:b2a894f94cb7 6 AnalogIn photoresistor(p15);
maryannionascu 9:b2a894f94cb7 7 Timer t; //running timer
maryannionascu 9:b2a894f94cb7 8 Ticker interrupt; //recurring 2 ms interrupt
maryannionascu 9:b2a894f94cb7 9
maryannionascu 9:b2a894f94cb7 10 volatile float beat; //raw analog signal data from photoresistor
maryannionascu 9:b2a894f94cb7 11 volatile int BPM = 60; //beats per minute
maryannionascu 9:b2a894f94cb7 12 volatile int beatCount = 0; //number of beats found
maryannionascu 9:b2a894f94cb7 13 volatile float currIBI = 0; // current InterBeat Interval: the time since the last beat
maryannionascu 9:b2a894f94cb7 14 volatile float lastIBI = 1; //last InterBeat Interval: the time between beats
maryannionascu 9:b2a894f94cb7 15 volatile float pastIBI[10]; //past ten IBI values
maryannionascu 9:b2a894f94cb7 16 volatile float sumIBI = 0; ///sum of past ten IBI values
maryannionascu 9:b2a894f94cb7 17 volatile unsigned long lastBeatTime = 0; //time of last beat
maryannionascu 9:b2a894f94cb7 18 volatile float peak = 25; //peak of heartbeat wave; initilized to 20 to avoid noise at startup
maryannionascu 9:b2a894f94cb7 19 volatile float trough = 15; //trough of heartbeat wave
maryannionascu 9:b2a894f94cb7 20 volatile float thresh = 10; // used to reduce noice
maryannionascu 9:b2a894f94cb7 21 volatile float amp = 5; // amplitude of heartbeat wave
maryannionascu 9:b2a894f94cb7 22 volatile bool firstBeat = true; //keeps track of first beat found
maryannionascu 9:b2a894f94cb7 23 volatile bool beatFound = false; //true when a beat is found, false in between beats
maryannionascu 9:b2a894f94cb7 24 volatile bool BPMfound = false; //true when BPM is found, false otherwise.
maryannionascu 9:b2a894f94cb7 25
maryannionascu 9:b2a894f94cb7 26 void findBPM(){
maryannionascu 9:b2a894f94cb7 27 __disable_irq(); // disable interrupts
maryannionascu 9:b2a894f94cb7 28 beat = photoresistor * 100; // read the analog data from the photoresistor and multiply by 100 (amplifies small values)
maryannionascu 9:b2a894f94cb7 29 currIBI = t.read() - lastBeatTime;
maryannionascu 9:b2a894f94cb7 30 // avoid noise by waiting 3/5 of last IBI
maryannionascu 9:b2a894f94cb7 31 if((beat < thresh) && (currIBI > (lastIBI*3)/5)){
maryannionascu 9:b2a894f94cb7 32 if (beat < trough){
maryannionascu 9:b2a894f94cb7 33 trough = beat;
maryannionascu 9:b2a894f94cb7 34 }
maryannionascu 9:b2a894f94cb7 35 }
maryannionascu 9:b2a894f94cb7 36 if((beat > thresh) && (beat > peak)){
maryannionascu 9:b2a894f94cb7 37 peak = beat;
maryannionascu 9:b2a894f94cb7 38 }
maryannionascu 9:b2a894f94cb7 39 // photoresistor signal surges when there is a heartbeat
maryannionascu 9:b2a894f94cb7 40 if ((currIBI > 0.25) && (beat > thresh) && (beat > 30) && (beatFound == false)){
maryannionascu 9:b2a894f94cb7 41 beatFound = true;
maryannionascu 9:b2a894f94cb7 42 beatCount++;
maryannionascu 9:b2a894f94cb7 43 thresh = beat - 0.7; //adjust threshold to account for any change in lighting and avoid noise
maryannionascu 9:b2a894f94cb7 44 lastIBI = t.read() - lastBeatTime;
maryannionascu 9:b2a894f94cb7 45 lastBeatTime = t.read();
maryannionascu 9:b2a894f94cb7 46 //if this is the first beat found, fill pastIBI values with this value until more beats are found
maryannionascu 9:b2a894f94cb7 47 if(firstBeat){
maryannionascu 9:b2a894f94cb7 48 firstBeat = false;
maryannionascu 9:b2a894f94cb7 49 for(int i=0; i< 10; i++){
maryannionascu 9:b2a894f94cb7 50 pastIBI[i] = lastIBI;
maryannionascu 9:b2a894f94cb7 51 }
maryannionascu 9:b2a894f94cb7 52 }
maryannionascu 9:b2a894f94cb7 53 sumIBI = lastIBI;
maryannionascu 9:b2a894f94cb7 54 //shift data over one value in pastIBI array to make room for next IBI value and discard oldest value
maryannionascu 9:b2a894f94cb7 55 for(int i=0; i< 9; i++){
maryannionascu 9:b2a894f94cb7 56 pastIBI[i] = pastIBI[i+1];
maryannionascu 9:b2a894f94cb7 57 sumIBI += pastIBI[i];
maryannionascu 9:b2a894f94cb7 58 }
maryannionascu 9:b2a894f94cb7 59 pastIBI[9] = lastIBI; //add most recent IBI value to array
maryannionascu 9:b2a894f94cb7 60 sumIBI = sumIBI/10; //average the last 10 IBI values
maryannionascu 9:b2a894f94cb7 61 BPM = 60/sumIBI; //BPM = 1 minute / average IBI
maryannionascu 9:b2a894f94cb7 62 if(beatCount == 5){ //Only report BPM after at least 5 beats are found
maryannionascu 9:b2a894f94cb7 63 BPMfound = true;
maryannionascu 9:b2a894f94cb7 64 beatCount = 0;
maryannionascu 9:b2a894f94cb7 65 }
maryannionascu 9:b2a894f94cb7 66 }
maryannionascu 9:b2a894f94cb7 67 //when the signal is less than the threshold, the beat is over
maryannionascu 9:b2a894f94cb7 68 if (((beat < thresh) && beatFound) || (currIBI > 2)){
maryannionascu 9:b2a894f94cb7 69 beatFound = false; // reset the beatFound flag to find the next beat
maryannionascu 9:b2a894f94cb7 70 amp = peak - trough; // calculate amplitude of heartbeat wave
maryannionascu 9:b2a894f94cb7 71 thresh = amp/2 + trough; // set threshold to 50% of the amplitude
maryannionascu 9:b2a894f94cb7 72 peak = thresh;
maryannionascu 9:b2a894f94cb7 73 trough = thresh;
maryannionascu 9:b2a894f94cb7 74 }
maryannionascu 9:b2a894f94cb7 75 /*
maryannionascu 9:b2a894f94cb7 76 //if 3 seconds pass since the last beat, reset all variables to default values
maryannionascu 9:b2a894f94cb7 77 if (currIBI > 3){
maryannionascu 9:b2a894f94cb7 78 thresh = 10;
maryannionascu 9:b2a894f94cb7 79 peak = 10;
maryannionascu 9:b2a894f94cb7 80 trough = 10;
maryannionascu 9:b2a894f94cb7 81 lastBeatTime = t.read();
maryannionascu 9:b2a894f94cb7 82 firstBeat = true;
maryannionascu 9:b2a894f94cb7 83 }
maryannionascu 9:b2a894f94cb7 84 */
maryannionascu 9:b2a894f94cb7 85 __enable_irq(); //enable interrupts
maryannionascu 9:b2a894f94cb7 86 }
4180_1 0:cfcf73272647 87
4180_1 2:75727e89a717 88 int main()
4180_1 2:75727e89a717 89 {
4180_1 3:454d1f4c8fd7 90 uLCD.color(RED);
maryannionascu 9:b2a894f94cb7 91 uLCD.printf("\nHeart Beat Monitor\n");
maryannionascu 9:b2a894f94cb7 92 wait(1);
4180_1 4:25a266a74a4c 93 uLCD.cls();
maryannionascu 9:b2a894f94cb7 94 t.start();
maryannionascu 9:b2a894f94cb7 95 interrupt.attach(&findBPM, 0.002); //throws interrupt every 2ms to read sensor data and calculate BPM
maryannionascu 9:b2a894f94cb7 96 while(1){
maryannionascu 9:b2a894f94cb7 97 if(t.read() > 10){ //wait 10 seconds to get an accurate average
maryannionascu 9:b2a894f94cb7 98 if(BPMfound){
maryannionascu 9:b2a894f94cb7 99 BPMfound = false; //start calculating next BPM
maryannionascu 9:b2a894f94cb7 100 uLCD.locate(1,2);
maryannionascu 9:b2a894f94cb7 101 uLCD.printf("\nYour BPM is:\n");
maryannionascu 9:b2a894f94cb7 102 uLCD.printf("%2D", BPM);
maryannionascu 9:b2a894f94cb7 103 wait(3);
maryannionascu 9:b2a894f94cb7 104 uLCD.cls();
maryannionascu 9:b2a894f94cb7 105 lastBeatTime = 0;
maryannionascu 9:b2a894f94cb7 106 beatCount = 0;
maryannionascu 9:b2a894f94cb7 107 t.start(); //restart timer
4180_1 3:454d1f4c8fd7 108 }
maryannionascu 9:b2a894f94cb7 109 //No heartbeat detected wtihin 10 seconds
maryannionascu 9:b2a894f94cb7 110 else{
maryannionascu 9:b2a894f94cb7 111 uLCD.printf("\nNo heartbeat detected!");
maryannionascu 9:b2a894f94cb7 112 wait(3);
maryannionascu 9:b2a894f94cb7 113 uLCD.cls();
maryannionascu 9:b2a894f94cb7 114 lastBeatTime = 0;
maryannionascu 9:b2a894f94cb7 115 beatCount = 0;
maryannionascu 9:b2a894f94cb7 116 t.start(); //restart timer
4180_1 5:a1ef40ff0f78 117 }
4180_1 5:a1ef40ff0f78 118 }
maryannionascu 9:b2a894f94cb7 119 else{
maryannionascu 9:b2a894f94cb7 120 uLCD.locate(1,2);
maryannionascu 9:b2a894f94cb7 121 uLCD.printf("\nCalculating...\n");
maryannionascu 9:b2a894f94cb7 122 //uLCD.printf("%2F\n", (float) photoresistor*100);
maryannionascu 9:b2a894f94cb7 123 //uLCD.printf("beatCount: %2F\n", (float) beatCount);
maryannionascu 9:b2a894f94cb7 124 //uLCD.printf("currIBI: %2F\n", (float) currIBI);
maryannionascu 9:b2a894f94cb7 125 wait(.1);
maryannionascu 9:b2a894f94cb7 126 uLCD.cls();
maryannionascu 9:b2a894f94cb7 127 /*
maryannionascu 9:b2a894f94cb7 128 uLCD.printf("%2F\n", (float) photoresistor*100);
maryannionascu 9:b2a894f94cb7 129 //uLCD.printf("BPMfound: %2F\n", (float) BPMfound);
maryannionascu 9:b2a894f94cb7 130 uLCD.printf("beatFound: %2F\n", (float) beatFound);
maryannionascu 9:b2a894f94cb7 131 uLCD.printf("beatCount: %2F\n", (float) beatCount);
maryannionascu 9:b2a894f94cb7 132 //uLCD.printf("firstBeat: %2F\n", (float) firstBeat);
maryannionascu 9:b2a894f94cb7 133 uLCD.printf("thresh: %2F\n", (float) thresh);
maryannionascu 9:b2a894f94cb7 134 //uLCD.printf("sumIBI: %2F\n", (float) sumIBI);
maryannionascu 9:b2a894f94cb7 135 //uLCD.printf("time: %2F\n", (float) t.read());
maryannionascu 9:b2a894f94cb7 136 wait(.1);
maryannionascu 9:b2a894f94cb7 137 uLCD.cls();
maryannionascu 9:b2a894f94cb7 138 */
maryannionascu 9:b2a894f94cb7 139 }
4180_1 5:a1ef40ff0f78 140 }
4180_1 6:f752accd632c 141 }
4180_1 7:7bd7397ab89f 142
4180_1 7:7bd7397ab89f 143
4180_1 8:31e63caf37e2 144