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.
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.
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
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