Sbit LCD_RS at RD0_bit;
Sbit LCD_EN at RD6_bit;
Sbit LCD_D4 at RD5_bit;
Sbit LCD_D5 at RD4_bit;
Sbit LCD_D6 at RD3_bit;
Sbit LCD_D7 at RD2_bit;
Sbit LCD_RS_Direction at TRISD0_bit;
Sbit LCD_EN_Direction at TRISD6_bit;
Sbit LCD_D4_Direction at TRISD5_bit;
Sbit LCD_D5_Direction at TRISD4_bit;
Sbit LCD_D6_Direction at TRISD3_bit;
Sbit LCD_D7_Direction at TRISD2_bit;
Enum {FALSE = 0, TRUE = 1};
Char intro_msg[] = “ELECTRONIC HEART RATE MONITOR”;
Char temp_str[8], disp_result;
Int rate[10]; // array to hold last ten IBI values
Unsigned long sampleCounter = 0; // used to determine pulse timing
Unsigned long lastBeatTime = 0; // used to find IBI
Int Peak =512; // used to find peak in pulse wave, seeded
Int Trough = 512; // used to find trough in pulse wave, seeded
Int thresh = 512; // used to find instant moment of heart beat, seeded
Int amp = 100; // used to hold amplitude of pulse waveform, seeded
Bit firstBeat; // used to seed rate array so we startup with reasonable BPM
Bit secondBeat; // used to seed rate array so we startup with reasonable BPM
Int pulsePin = 0; // Pulse Sensor purple wire connected to analog pin 0
Int blinkPin = 13; // pin to blink led at each beat
Int runningTotal = 0; // clear the runningTotal variable
// these variables are volatile because they are used during the interrupt service routine!
Unsigned int BPM; // used to hold the pulse rate
Unsigned int Signal; // holds the incoming raw data
Unsigned int IBI = 600; // holds the time between beats, must be seeded!
Bit Pulse ; // true when pulse wave is high, false when it’s low
Bit QS;
Int N_cnt, P_cnt;
Int I = 0;
Void InitTimer0(){ //timer0 is set to Interrupt every 2ms. PIC18F452 is running at 32MHz
T0CON = 0xC5;
TMR0L = 0x06;
GIE_bit = 1;
TMR0IE_bit = 1;
Void Interrupt(){
GIE_bit = 0;
If (TMR0IF_bit){ //every 2ms
//READ HEART RATE FROM LCD
Signal = ADC_Get_Sample(0);
sampleCounter += 2;
N_cnt = sampleCounter – lastBeatTime;
If(Signal < thresh && N_cnt > (IBI/5)*3){
If (Signal < Trough){
Trough = Signal;
If(Signal > thresh && Signal > P_cnt){
P_cnt = Signal;
// NOW IT’S TIME TO LOOK FOR THE HEART BEAT
// signal surges up in value every time there is a pulse
If (N_cnt > 250){ // avoid high frequency noise
If ( (Signal > thresh) && (Pulse == FALSE) && (N_cnt > (IBI/5)*3) ){
Pulse = TRUE; // set the Pulse flag when we think there is a pulse
IBI = sampleCounter – lastBeatTime; // measure time between beats in mS
lastBeatTime = sampleCounter; // keep track of time for next pulse
if(secondBeat){ // if this is the second beat, if secondBeat == TRUE
secondBeat = FALSE; // clear secondBeat flag
for(i=0; i<=9; i++){ // seed the running total to get a realisitic BPM at startup
rate[i] = IBI;
}
If(firstBeat){ // if it’s the first time we found a beat, if firstBeat == TRUE
firstBeat = FALSE; // clear firstBeat flag
secondBeat = TRUE; // set the second beat flag
return; // IBI value is unreliable so discard it
// keep a running total of the last 10 IBI values
runningTotal = 0; // clear the runningTotal variable
for(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_cnt – Trough; // get amplitude of the pulse wave
Thresh = amp/2 + Trough; // set thresh at 50% of the amplitude
P_cnt = thresh; // reset these for next time
Trough = thresh;
If (N_cnt > 2500){ // if 2.5 seconds go by without a beat
Thresh = 512; // set thresh default
P_cnt = 512; // set P default
Trough = 512; // set T default
lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
firstBeat = TRUE; // set these to avoid noise
secondBeat = FALSE; // when we get the heartbeat back
TMR0IF_bit = 0;
TMR0L = 0x06;
GIE_bit =1;
}// end isr
GIE_bit =1; // enable interrupts when youre done!
Void main() {
Int g;
OSCCON.IRCF0=0;
OSCCON.IRCF1=1;
OSCCON.IRCF2=1;
ANSELA=0x01;
ANSELB=0x00;
ANSELC=0x00;
ANSELD=0x00;
ANSELE=0x00;
Pulse = FALSE;
QS = FALSE;
firstBeat = TRUE;
secondBeat = FALSE;
Lcd_Init(); //initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear display
Delay_ms(200);
Lcd_Cmd(_LCD_CURSOR_OFF);
Delay_ms(200);
Lcd_Out(1,1, intro_msg);
Delay_ms(1500); // First row
For(g=0; g<sizeof(intro_msg)-16; g++) { // Move text to the right 4 times
Lcd_Cmd(_LCD_SHIFT_LEFT);
Delay_ms(250);
Lcd_Cmd(_LCD_CLEAR); // Clear display
Delay_ms(200);
ADC_Init();
InitTimer0();
While(1){
If (QS == TRUE){ //New Pulse detected
Lcd_Out(1,1,”HEART RATE (BPM)”);
Lcd_Out(2,1,” “);
IntToStr(BPM, temp_str);
Lcd_Out(2,8,temp_str);
Delay_ms(2000);