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:
Wed Oct 28 17:55:39 2015 +0000
Revision:
10:ad2548407023
Parent:
9:b2a894f94cb7
Updated comments

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 10:ad2548407023 20 volatile float lowerThresh = 10; // used to reduce noice; change these values based on amount of light in room
maryannionascu 10:ad2548407023 21 volatile float upperThresh = 30; // used to reduce noice; change these values based on amount of light in room
maryannionascu 9:b2a894f94cb7 22 volatile float amp = 5; // amplitude of heartbeat wave
maryannionascu 9:b2a894f94cb7 23 volatile bool firstBeat = true; //keeps track of first beat found
maryannionascu 9:b2a894f94cb7 24 volatile bool beatFound = false; //true when a beat is found, false in between beats
maryannionascu 9:b2a894f94cb7 25 volatile bool BPMfound = false; //true when BPM is found, false otherwise.
maryannionascu 9:b2a894f94cb7 26
maryannionascu 9:b2a894f94cb7 27 void findBPM(){
maryannionascu 9:b2a894f94cb7 28 __disable_irq(); // disable interrupts
maryannionascu 9:b2a894f94cb7 29 beat = photoresistor * 100; // read the analog data from the photoresistor and multiply by 100 (amplifies small values)
maryannionascu 9:b2a894f94cb7 30 currIBI = t.read() - lastBeatTime;
maryannionascu 9:b2a894f94cb7 31 // avoid noise by waiting 3/5 of last IBI
maryannionascu 10:ad2548407023 32 if((beat < lowerThresh) && (currIBI > (lastIBI*3)/5)){
maryannionascu 9:b2a894f94cb7 33 if (beat < trough){
maryannionascu 9:b2a894f94cb7 34 trough = beat;
maryannionascu 9:b2a894f94cb7 35 }
maryannionascu 9:b2a894f94cb7 36 }
maryannionascu 10:ad2548407023 37 if((beat > upperThresh) && (beat > peak)){
maryannionascu 9:b2a894f94cb7 38 peak = beat;
maryannionascu 9:b2a894f94cb7 39 }
maryannionascu 9:b2a894f94cb7 40 // photoresistor signal surges when there is a heartbeat
maryannionascu 10:ad2548407023 41 if ((currIBI > 0.25) && (beat > upperThresh) && (beatFound == false)){
maryannionascu 9:b2a894f94cb7 42 beatFound = true;
maryannionascu 9:b2a894f94cb7 43 beatCount++;
maryannionascu 10:ad2548407023 44 lowerThresh = beat - 0.7; //adjust threshold to account for any change in lighting and avoid noise
maryannionascu 9:b2a894f94cb7 45 lastIBI = t.read() - lastBeatTime;
maryannionascu 9:b2a894f94cb7 46 lastBeatTime = t.read();
maryannionascu 9:b2a894f94cb7 47 //if this is the first beat found, fill pastIBI values with this value until more beats are found
maryannionascu 9:b2a894f94cb7 48 if(firstBeat){
maryannionascu 9:b2a894f94cb7 49 firstBeat = false;
maryannionascu 9:b2a894f94cb7 50 for(int i=0; i< 10; i++){
maryannionascu 9:b2a894f94cb7 51 pastIBI[i] = lastIBI;
maryannionascu 9:b2a894f94cb7 52 }
maryannionascu 9:b2a894f94cb7 53 }
maryannionascu 9:b2a894f94cb7 54 sumIBI = lastIBI;
maryannionascu 9:b2a894f94cb7 55 //shift data over one value in pastIBI array to make room for next IBI value and discard oldest value
maryannionascu 9:b2a894f94cb7 56 for(int i=0; i< 9; i++){
maryannionascu 9:b2a894f94cb7 57 pastIBI[i] = pastIBI[i+1];
maryannionascu 9:b2a894f94cb7 58 sumIBI += pastIBI[i];
maryannionascu 9:b2a894f94cb7 59 }
maryannionascu 9:b2a894f94cb7 60 pastIBI[9] = lastIBI; //add most recent IBI value to array
maryannionascu 9:b2a894f94cb7 61 sumIBI = sumIBI/10; //average the last 10 IBI values
maryannionascu 9:b2a894f94cb7 62 BPM = 60/sumIBI; //BPM = 1 minute / average IBI
maryannionascu 9:b2a894f94cb7 63 if(beatCount == 5){ //Only report BPM after at least 5 beats are found
maryannionascu 9:b2a894f94cb7 64 BPMfound = true;
maryannionascu 9:b2a894f94cb7 65 beatCount = 0;
maryannionascu 9:b2a894f94cb7 66 }
maryannionascu 9:b2a894f94cb7 67 }
maryannionascu 9:b2a894f94cb7 68 //when the signal is less than the threshold, the beat is over
maryannionascu 10:ad2548407023 69 if (((beat < lowerThresh) && beatFound) || (currIBI > 2)){
maryannionascu 9:b2a894f94cb7 70 beatFound = false; // reset the beatFound flag to find the next beat
maryannionascu 9:b2a894f94cb7 71 amp = peak - trough; // calculate amplitude of heartbeat wave
maryannionascu 10:ad2548407023 72 upperThresh = amp/2 + trough; // set upper threshold to 50% of the amplitude
maryannionascu 10:ad2548407023 73 peak = upperThresh;
maryannionascu 10:ad2548407023 74 trough = lowerThresh;
maryannionascu 9:b2a894f94cb7 75 }
maryannionascu 9:b2a894f94cb7 76 __enable_irq(); //enable interrupts
maryannionascu 9:b2a894f94cb7 77 }
4180_1 0:cfcf73272647 78
4180_1 2:75727e89a717 79 int main()
4180_1 2:75727e89a717 80 {
4180_1 3:454d1f4c8fd7 81 uLCD.color(RED);
maryannionascu 9:b2a894f94cb7 82 uLCD.printf("\nHeart Beat Monitor\n");
maryannionascu 9:b2a894f94cb7 83 wait(1);
4180_1 4:25a266a74a4c 84 uLCD.cls();
maryannionascu 9:b2a894f94cb7 85 t.start();
maryannionascu 9:b2a894f94cb7 86 interrupt.attach(&findBPM, 0.002); //throws interrupt every 2ms to read sensor data and calculate BPM
maryannionascu 9:b2a894f94cb7 87 while(1){
maryannionascu 9:b2a894f94cb7 88 if(t.read() > 10){ //wait 10 seconds to get an accurate average
maryannionascu 9:b2a894f94cb7 89 if(BPMfound){
maryannionascu 9:b2a894f94cb7 90 BPMfound = false; //start calculating next BPM
maryannionascu 9:b2a894f94cb7 91 uLCD.locate(1,2);
maryannionascu 9:b2a894f94cb7 92 uLCD.printf("\nYour BPM is:\n");
maryannionascu 9:b2a894f94cb7 93 uLCD.printf("%2D", BPM);
maryannionascu 9:b2a894f94cb7 94 wait(3);
maryannionascu 9:b2a894f94cb7 95 uLCD.cls();
maryannionascu 9:b2a894f94cb7 96 lastBeatTime = 0;
maryannionascu 9:b2a894f94cb7 97 beatCount = 0;
maryannionascu 9:b2a894f94cb7 98 t.start(); //restart timer
4180_1 3:454d1f4c8fd7 99 }
maryannionascu 9:b2a894f94cb7 100 //No heartbeat detected wtihin 10 seconds
maryannionascu 9:b2a894f94cb7 101 else{
maryannionascu 9:b2a894f94cb7 102 uLCD.printf("\nNo heartbeat detected!");
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 5:a1ef40ff0f78 108 }
4180_1 5:a1ef40ff0f78 109 }
maryannionascu 9:b2a894f94cb7 110 else{
maryannionascu 9:b2a894f94cb7 111 uLCD.locate(1,2);
maryannionascu 9:b2a894f94cb7 112 uLCD.printf("\nCalculating...\n");
maryannionascu 9:b2a894f94cb7 113 wait(.1);
maryannionascu 9:b2a894f94cb7 114 uLCD.cls();
maryannionascu 9:b2a894f94cb7 115 }
4180_1 5:a1ef40ff0f78 116 }
4180_1 6:f752accd632c 117 }
4180_1 7:7bd7397ab89f 118
4180_1 7:7bd7397ab89f 119
4180_1 8:31e63caf37e2 120