Jordan M Buhagiar
Newbie level 3

Hi i am designing a heart rate monitor via photoplethysmography, the signal is derived in to port A0 of the PIC as illustrated. I am looking to display results via a 2 thresholds that was set with respect to the voltage reference towards a 10 bit ADC. This is my code, could someone identify any thing wrong with it??
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 #include <16F877.h> #device ADC=10 #use delay(crystal=8000000) /* Main.c file generated by New Project wizard * * Created: Thu Apr 16 2015 * Processor: PIC16F877 * Compiler: CCS for PIC */ #include "LCD.c" #include <float.h> #include <stdlib.h> #include <string.h> #use RS232(baud=9600, xmit=PIN_C7, rcv=PIN_C6) #use delay(clock = 8000000) #fuses HS, NOWDT, NOPROTECT, PUT, NOBROWNOUT, NOLVP, NOWRT, NODEBUG //A/D Control Register #BYTE ADCON0 = 0x1F #define LCD_ENABLE_PIN PIN_B3 #define LCD_RS_PIN PIN_B1 #define LCD_RW_PIN PIN_B2 #define LCD_DATA4 PIN_D4 #define LCD_DATA5 PIN_D5 #define LCD_DATA6 PIN_D6 #define LCD_DATA7 PIN_D7 #define Analog_In PIN_A0 #define bool int #define BUFFER_SIZE 10 // define globals const int TIMER_STOP_TIME = 15000; // pulses stop time in milliseconds const int MOVING_AVG_SIZE = 10; char message[BUFFER_SIZE]; int ring_buffer[BUFFER_SIZE]; int rb_start = 0; int rb_end = 0; const int16 PULSE_UPPER_THRESHOLD = 460; const int16 PULSE_LOWER_THRESHOLD = 376; int pulse_display; int pulse_count = 0; int ready = 0; int heart_pulse = 0; int timer_count = 0; int16 timer_ms = 0; int16 volt = 0; // function prototypes void LCD_DISP(); void read_ADC_Data(); void initialize(); int is_below_upper_threshold(int q); int is_above_lower_threshold(int q); void write_rb(int val); int get_time_duration(); void reset_timer(); // 262 milliseconds timer interval #int_TIMER1 void TIMER1_isr() { timer_count++; } #int_AD void AD_isr() { delay_ms(500); setup_adc(ADC_CLOCK_DIV_32); setup_adc_ports(AN0_AN1_VSS_VREF); set_adc_channel(0); } void main() { initialize(); read_ADC_Data(); } // resets the timer counter for a new time duration void reset_timer() { timer_count = 0; } // returns the time elapsed from last timer reset (reset_timer) int get_time_duration() { return 262 * timer_count; // 262: see TIMER1_isr } void LCD_DISP() { lcd_init(); Delay_ms(50); putc(254); putc(1); delay_ms(10); //Clear Display Delay_ms(100); printf("Heart Rate:"); putc(heart_pulse); } void read_ADC_Data() { // pulse definition: hits first upper threshold from above it then hits // lower threshold and then hits upper threshold again -> that is one full pulse // hit_upperthreshold is only true if the upperthreshold is hit from above it int hit_upperthreshold = false; // hit_lowerthreshold can only be true if the upper threshold has first been // hit (hit_upperthreshold = true) int hit_lowerthreshold = false; int prev_value_above_upper_threshold = false; int i; int1 timer_started = false; int16 adc_value; for (i=0; i<5; i++) { output_high(PIN_B4); // Green LED on while no input delay_ms(250); output_low(PIN_B4); } // start reading adc values as long they are coming while (input(Analog_In)) { AD_isr(); adc_value = read_adc(); // Read ADC values - in built function output_high(PIN_B5); // Yellow LED on 'Buffer' delay_ms(2000); if (is_below_upper_threshold(adc_value) == true) { if(prev_value_above_upper_threshold == true) { // we hit the upper threshold from above the upperthreshold // so we have (start of) a new pulse hit_upperthreshold = true; if (pulse_count == 0) { reset_timer(); // saves the current time so the duration can be calculated timer_started = true; } // only those adc values which are between lower_threshold and // upper_threshold will be added to the ring buffer: if(is_above_lower_threshold(adc_value) == true) write_rb(adc_value); // Ring buffer receives adc value } prev_value_above_upper_threshold = false; } else // we are above the upper threshold { prev_value_above_upper_threshold = true; } if((hit_upperthreshold == true) && (is_above_lower_threshold(adc_value) == false)) { // hit upper threshold and now lower threshold hit_lowerthreshold = true; } else if((hit_lowerthreshold == true) && (is_below_upper_threshold(adc_value) == false)) { // hit upper threshold then lower threshold and now uppert hreshold again // so one pulse is now finished pulse_count++; // zero threshold-hit flags hit_upperthreshold = false; hit_lowerthreshold = false; } // Condition if timer reaches 15 seconds if (timer_started && (get_time_duration() >= TIMER_STOP_TIME)) { // Stop timer and perform heart pulse calculations heart_pulse = pulse_count * 4; // Such calculations provides BPM LCD_DISP(); delay_ms(1000); output_low(PIN_B4); // Green LED off output_low(PIN_B5); // Yellow LED off while no input // initialize the while-loop for the next heart rate calculations: pulse_count = 0; timer_started = false; // wait for the next pulse to start using timer again prev_value_above_upper_threshold = false; // zero the threshold-hit flags hit_upperthreshold = false; hit_lowerthreshold = false; } } } /* initialize: Function to initialize the globals and the in built functions accrodingly */ void initialize() { // the circular buffer int q; for (q = 0; q < BUFFER_SIZE; q++) { ring_buffer[q] = 0; } //I/O PORTS output_D(255); //PortD as OUTPUT // Interrupts enable_interrupts(int_timer1); enable_interrupts(INT_AD); enable_interrupts(GLOBAL); //Timer1 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //262 ms overflow // init display start lcd_init(); } /* is_above_lower_threshold: Function for threshold setup. Checks if a value is above the lower threshold. */ int is_above_lower_threshold(int q) { return ((q > PULSE_LOWER_THRESHOLD) ? true : false); } /* is_below_upper_threshold: Function for threshold setup. Checks if a value is below the upper threshold. */ int is_below_upper_threshold(int q) { return ((q < PULSE_UPPER_THRESHOLD) ? true : false); } /* write_rb: Writes val to ring buffer ring_buffer[]. */ void write_rb(int val) { ring_buffer[rb_end++] = val; // Ring buffer designed to shift, therefore end value increments(shifts) if (rb_end == BUFFER_SIZE) // If rb_end on the last location rb_end = 0; // loop round if (rb_end == rb_start) // if they overlap, increment the start value as well rb_start++; if (rb_start == BUFFER_SIZE) // If rb_start on the last location rb_start = 0; // loop round } Capture.PNG Capture.PNG
Last edited by a moderator: