2 Ekim 2017 Pazartesi

Measure period using CCP2 and TIMER1

In this example, we will measure period of a pulse signal. In theory it is simple, measure the time difference between two rising/falling edges. I saw two approaches; first to do this within main.c, like in http://www.electronicwings.com/pic/pic18f4550-timer-capture. But it did not work for me specially in high frequencies=low periods. If you measure high frequency a lot of CCP interrupt occurs and it seems blocking the PIC.


while(1) { while(!(PIR1bits.CCP1IF)); /* Wait for interrupt flag which is generated when edge is detected*/ data1=CCPR1; /* Copy count of 1st edge detected*/ PIR1bits.CCP1IF=0; while(!(PIR1bits.CCP1IF)); /* Wait for interrupt flag which is generated when edge is detected*/ data2=CCPR1; /* Copy count of 2nd edge detected*/ PIR1bits.CCP1IF=0;


Thus, I wanted to capture only two rising edge, not more, at every 1 second. I
handled it within interrupt routine.

Proteus: Connect a pulse generator to the RC1/CCP2A. I opened the debugger to see
how many CCP event occurs.


MCC:  Add TIMER and CCP peripherals. Select rising edge. CCP2 interrupt automatically selected. 1MHZ internal osc was used. Use 1:1 prescaler at timer. no timer interrupt.





XC8:   added the code inside ISR. I used c=0, c=1 tokens to take only two samples, then disable the CCPCON=0x00;  interrupt. I enable within main.c again. Period is measured inside main.c. Be careful, you have to define t1 variable as extern inside ISR and take them to top at main.c  

It is working good between 500us-262ms (timer1 range without overflow). but again below 500us, more than two CCP interrupts occurs and measurement may give wrong results. I could not solve it yet. Any comments are welcome. obviously using higher freq oscillator will decrease this value.

------ccp2.c---------
#include <xc.h>
#include "ccp2.h"

extern double t1;
int c;
...

void CCP2_CaptureISR(void)
{
    CCP_PERIOD_REG_T module;

    // Clear the CCP2 interrupt flag
    PIR2bits.CCP2IF = 0;
    
    // Copy captured value.
    module.ccpr2l = CCPR2L;
    module.ccpr2h = CCPR2H;
    
    // Return 16bit captured value
    CCP2_CallBack(module.ccpr2_16Bit);
}

void CCP2_CallBack(uint16_t capturedValue)
{
    // Add your code here
    

    if ( c==1) {        
        t2=capturedValue;    //second  rising edge
        CCP2CON=0x00;    //disable after second rising edge
        c=0;        
    } else  {    
        t1=capturedValue;    //first rising edge
        c=1;
    }


    }


-----main.c-------

#include "mcc_generated_files/mcc.h"
#include "delays.h"
#include "myxlcd.h"
#include <stdio.h>

double  pr,t1,t2;
int c;
/*
                         Main application
 */
void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();

    // Enable the Global Interrupts
    INTERRUPT_GlobalInterruptEnable();


    // Enable the Peripheral Interrupts
    INTERRUPT_PeripheralInterruptEnable();

   unsigned char s1[10], s2[10];

   
    OpenXLCD(FOUR_BIT & LINES_5X7);
    WriteCmdXLCD(DON&CURSOR_OFF&BLINK_OFF); 
    
    
    while (1)
    {
        // Add your application code


         CCP2CON=0x05;  //enable CCP interrupt, which will be disabled inside ccp2.c        
        while (CCP2CON ==0x05); // wait for the end of interrupt
        pr=t2-t1;   //time difference
        if (pr<0) pr=pr+65536;  //in case of timer1 overflow
        pr=pr*4.0/1000.0;
     
        sprintf(s1,"%3.3fms", pr);   
  

        while(BusyXLCD());
        SetDDRamAddr(0x01); // clear LCD        
        putrsXLCD("P=");putrsXLCD(s1);
        SetDDRamAddr(0x40); // goto second line
        while(BusyXLCD());
        putrsXLCD("D=");putrsXLCD(s2);
        __delay_ms(1000);
        
    }
}

I checked with measurement inside main.c using (8MHz clock, thus 0.5 multiplier) this works fine upto 10ms but gives double or wrong values below. I noticed that  while (PIR2bits.CCP2IF==0);  may not work well because interrupts flowing continuously at debugger which causes high CPU load.

   while (1)
    {
        // Add your application code


        while (PIR2bits.CCP2IF==0); //wait until interrupt
        t1=CCPR2H*256+CCPR2L;

        while (PIR2bits.CCP2IF==0);
        t2=CCPR2H * 256 + CCPR2L;
     
        pr=t2-t1;
        if (pr<0) pr=pr+65536;
        pr=pr*0.5/1000.0;

I also checked the algorithm at https://web.sonoma.edu/users/f/farahman/sonoma/courses/es310/lectures/chapter_11_timers.pdf but it did not work for me also. I read some comments that resetting timer for period measurement will not give accurate results, instead measure time difference between two CCP rising edge interrupt advised as a better approach


Hiç yorum yok:

Yorum Gönder