Short info: I'm using a PIC18F4580 to measure the period time of two positive pulses using the CCP 1 on the MCU. And then writing the result to an LCD. When testing I sometimes get a result thats one overflow count wrong.(32,768ms wrong => 65536 timer1 ticks wong => 1 overflow count).
Details: Accuracy needs to be minimum 1us. I'm coding in C and using xc8 compiler. A 8MHz crystal is used to run the PIC so Fosc/4 = 2MHz. Timer1 runs with no prescaler to get a timer accuracy of 0.5us. Timer2 is used to poll the state of the push button, every 10ms. The code is well documented and i hope its easy to follow.
The way we are testing is with a squarewave generator with frequencies between 10Hz to 400Hz.
First i had the saves to t1 and t2 in the main loop but that didn't work good at higher frequencies.
I have tried to check to timer1 overflow flag in the CCP1 interrupt routine so that I dont miss a overflow when saving the "timestamp".
Any ideas on what is creating this error?
Code below, comfig bits and includes omitted
/********************* Variables *********************/
unsigned long t1 = 0;
unsigned long t1Count = 0;
unsigned long t2 = 0;
unsigned long t2Count = 0;
volatile unsigned long timeBuff = 0;
float elapsedTime = 0;
volatile unsigned long overflowCountTMR1 = 0;
volatile unsigned long overflowCountBuff = 0;
volatile int pulseCount = 0;
volatile int btnCount = 0;
char ms[20];
/********************* Function declarations *********************/
void interrupts();
void noInterrupts();
void resetValues();
/********************* Main function *********************/
void main() {
TRISBbits.RB5 = 1; // Input push button
// Set up CCP module, capture rising
TRISCbits.RC2 = 1; // Set RC2/CPP1 pin as input
PORTC = 0x00; // Set all pins to low
CCP1CON = 0x05; // Capture rising edge
PIR1bits.CCP1IF = 0; // Reset interrupt flag
// Set-up timer1 for counting periodtime
T1CON = 0x00; // Disable Timer1 under set-up
T3CON = 0x00; // Set Timer1 as capture source for CCP1
PIR1bits.TMR1IF = 0; // Reset interrupt flag
T1CON = 0x81; // Start Timer1 with 16-bits read/write
// Set-up timer2 for polling push button state
T2CON = 0x00; // Disable Timer1 under set-up
PIR1bits.TMR2IF = 0; // Reset interrupt flag
PR2 = 125;
T2CON = 0x4F; // Prescaler: 16 Postscaler: 10 => Interrupt every 10ms (WHEN PR2 = 125)
// Set up LCD
CMCONbits.CM = 0x07; // Disable comperators at RB2 & RB3
TRISD = 0x00; // Set up D ports as output
Lcd_Init();
Lcd_Clear();
Lcd_Set_Cursor(1,1);
interrupts(); // Enable interrupts
while(1)
{
if(btnCount == 10){
noInterrupts();
resetValues();
Lcd_Clear();
interrupts();
}
// Calculate period from timestamps
if (pulseCount == 2){ // We got 2 pulses, calculate elapsed time
noInterrupts();
// T2-T1 don't forget the overflow count variable
elapsedTime = ( (t2 - t1) + ((t2Count-t1Count)*65536) )/2.0; // In us (microseconds)
pulseCount++; // Increment so we wont calculate again
// Write results to LCD in ms
sprintf(ms,"%4.3f",(elapsedTime/1000.0));
Lcd_Set_Cursor(1,1);
Lcd_Write_String(ms);
interrupts();
}
}
}
/********************* Interrupt functions *********************/
// Handles interrupts. Timer interrupt to keep track of nr of overflows.
// Check if we got a pulse, save value if we did
void interrupt ISR_handeler(){
if(PIR1bits.CCP1IF == 1){
timeBuff = CCPR1;
int saveFlag = PIR1bits.TMR1IF;
if(saveFlag == TRUE){
timeBuff = CCPR1;
overflowCountTMR1++;
PIR1bits.TMR1IF == 0;
}
pulseCount++;
if(pulseCount == 1){
t1 = timeBuff;
t1Count = overflowCountTMR1;
} else if (pulseCount == 2){
t2 = timeBuff;
t2Count = overflowCountTMR1;
PIE1bits.TMR1IE = 0; // We only want to calculate between two pulses
}
PIR1bits.CCP1IF = 0;
}
if(PIR1bits.TMR1IF == 1){ //Count number of Timer1 overflows
overflowCountTMR1++;
PIR1bits.TMR1IF = 0;
}
if(PIR1bits.TMR2IF == 1){
if(PORTBbits.RB5 == 0){
btnCount++;
}
PIR1bits.TMR2IF = 0;
}
}
/********************* Functions *********************/
void noInterrupts(){
// Disable global and peripheral interrupts
INTCONbits.GIE = 0;
INTCONbits.PEIE = 0;
PIE1bits.CCP1IE = 0; // Disable CPP1 interrupt
PIE1bits.TMR1IE = 0; // Disable Timer1 Overflow interrupt
PIE1bits.TMR2IE = 0; // Disable Timer2 Overflow interrupt
}
void interrupts(){
// Enable global and peripheral interrupts
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
PIE1bits.CCP1IE = 1; // Enable CPP1 interrupt
PIE1bits.TMR1IE = 1; // Enable Timer1 Overflow interrupt
PIE1bits.TMR2IE = 1; // Enable Timer2 Overflow interrupt
}
void resetValues() {
pulseCount = 0;
overflowCountTMR1 = 0;
btnCount = 0;
}
EDIT: Added question.