The Design of a Heart RateMonitor Software Problem (CCS)

Discussion in 'Embedded Systems and Microcontrollers' started by Jordan Mauro, Apr 24, 2015.

  1. Jordan Mauro

    Thread Starter New Member

    Apr 24, 2015
    2
    0
    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??

    #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
    } [​IMG][​IMG]
     
  2. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,790
    I'm sorry, but my crystal ball is in the shop. Can you tell me what you think is wrong with it? What is it doing or not doing at the moment?
     
    Jordan Mauro likes this.
  3. Jordan Mauro

    Thread Starter New Member

    Apr 24, 2015
    2
    0
    Hi at the moment the circuit does not react to anything regarding the program, i even put LEDs to show some sign of operation.

    Although i dont know if i may have set interrupt routines wrong or if my syntax is not good enough.

    I thought it was very strange that anything is working.

    Maybe some one experienced with CCS, yourself maybe could analyse the program and maybe see something wrong regarding pins/ports/ standard operationg that i may have missed or not included completely.

    I have been working on this for 3 months now, last month was driven crazy by software as i cant get anything to react.
     
  4. MrChips

    Moderator

    Oct 2, 2009
    12,442
    3,361
    Anyone can put together a circuit and a complex program.
    Getting it to work correctly is where the real challenge occurs.

    Don't attemp to get the whole thing working all at once. Imagine you have 20 problems or errors and each one alone would prevent the system from even making a nudge. How would you go about finding and fixing one problem at a time.

    Begin with your main( ) code.
    Can you insert code to make an LED turn on?
     
  5. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,790
    Well, I don't see anything in the program related to the clock oscillator. I guess a schematic might be in order to see if there is an oscillator and a reset circuit. Some modern PICs will work without those things, but you have to set some configuration fuses for things to work.
     
Loading...