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
main.cpp
- Committer:
- maryannionascu
- Date:
- 2015-10-28
- Revision:
- 10:ad2548407023
- Parent:
- 9:b2a894f94cb7
File content as of revision 10:ad2548407023:
#include "mbed.h" #include "uLCD_4DGL.h" //Calculates the BPM using a photoresistor as input and outputs the BPM to an LCD screen. uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin; AnalogIn photoresistor(p15); Timer t; //running timer Ticker interrupt; //recurring 2 ms interrupt volatile float beat; //raw analog signal data from photoresistor volatile int BPM = 60; //beats per minute volatile int beatCount = 0; //number of beats found volatile float currIBI = 0; // current InterBeat Interval: the time since the last beat volatile float lastIBI = 1; //last InterBeat Interval: the time between beats volatile float pastIBI[10]; //past ten IBI values volatile float sumIBI = 0; ///sum of past ten IBI values volatile unsigned long lastBeatTime = 0; //time of last beat volatile float peak = 25; //peak of heartbeat wave; initilized to 20 to avoid noise at startup volatile float trough = 15; //trough of heartbeat wave volatile float lowerThresh = 10; // used to reduce noice; change these values based on amount of light in room volatile float upperThresh = 30; // used to reduce noice; change these values based on amount of light in room volatile float amp = 5; // amplitude of heartbeat wave volatile bool firstBeat = true; //keeps track of first beat found volatile bool beatFound = false; //true when a beat is found, false in between beats volatile bool BPMfound = false; //true when BPM is found, false otherwise. void findBPM(){ __disable_irq(); // disable interrupts beat = photoresistor * 100; // read the analog data from the photoresistor and multiply by 100 (amplifies small values) currIBI = t.read() - lastBeatTime; // avoid noise by waiting 3/5 of last IBI if((beat < lowerThresh) && (currIBI > (lastIBI*3)/5)){ if (beat < trough){ trough = beat; } } if((beat > upperThresh) && (beat > peak)){ peak = beat; } // photoresistor signal surges when there is a heartbeat if ((currIBI > 0.25) && (beat > upperThresh) && (beatFound == false)){ beatFound = true; beatCount++; lowerThresh = beat - 0.7; //adjust threshold to account for any change in lighting and avoid noise lastIBI = t.read() - lastBeatTime; lastBeatTime = t.read(); //if this is the first beat found, fill pastIBI values with this value until more beats are found if(firstBeat){ firstBeat = false; for(int i=0; i< 10; i++){ pastIBI[i] = lastIBI; } } sumIBI = lastIBI; //shift data over one value in pastIBI array to make room for next IBI value and discard oldest value for(int i=0; i< 9; i++){ pastIBI[i] = pastIBI[i+1]; sumIBI += pastIBI[i]; } pastIBI[9] = lastIBI; //add most recent IBI value to array sumIBI = sumIBI/10; //average the last 10 IBI values BPM = 60/sumIBI; //BPM = 1 minute / average IBI if(beatCount == 5){ //Only report BPM after at least 5 beats are found BPMfound = true; beatCount = 0; } } //when the signal is less than the threshold, the beat is over if (((beat < lowerThresh) && beatFound) || (currIBI > 2)){ beatFound = false; // reset the beatFound flag to find the next beat amp = peak - trough; // calculate amplitude of heartbeat wave upperThresh = amp/2 + trough; // set upper threshold to 50% of the amplitude peak = upperThresh; trough = lowerThresh; } __enable_irq(); //enable interrupts } int main() { uLCD.color(RED); uLCD.printf("\nHeart Beat Monitor\n"); wait(1); uLCD.cls(); t.start(); interrupt.attach(&findBPM, 0.002); //throws interrupt every 2ms to read sensor data and calculate BPM while(1){ if(t.read() > 10){ //wait 10 seconds to get an accurate average if(BPMfound){ BPMfound = false; //start calculating next BPM uLCD.locate(1,2); uLCD.printf("\nYour BPM is:\n"); uLCD.printf("%2D", BPM); wait(3); uLCD.cls(); lastBeatTime = 0; beatCount = 0; t.start(); //restart timer } //No heartbeat detected wtihin 10 seconds else{ uLCD.printf("\nNo heartbeat detected!"); wait(3); uLCD.cls(); lastBeatTime = 0; beatCount = 0; t.start(); //restart timer } } else{ uLCD.locate(1,2); uLCD.printf("\nCalculating...\n"); wait(.1); uLCD.cls(); } } }