Información breve: estoy usando un PIC18F4580 para medir el período de tiempo de dos pulsos positivos usando el CCP 1 en la MCU. Y luego escribir el resultado en una pantalla LCD. Cuando realizo la prueba, a veces obtengo un resultado que equivale a un recuento de desbordamiento (32,768 ms incorrecto = > 65536 timer1 marca wong = > 1 recuento de desbordamiento).
Detalles: La precisión debe ser mínimo de 1us. Estoy codificando en C y usando el compilador xc8. Se utiliza un cristal de 8MHz para ejecutar el PIC, por lo que Fosc / 4 = 2MHz. El temporizador 1 funciona sin precalificador para obtener una precisión del temporizador de 0.5us. Timer2 se utiliza para sondear el estado del botón pulsador, cada 10 ms. El código está bien documentado y espero que sea fácil de seguir.
La forma en que estamos probando es con un generador de onda cuadrada con frecuencias entre 10Hz y 400Hz.
Primero tuve los salvados a t1 y t2 en el bucle principal, pero eso no funcionó bien en frecuencias más altas.
He intentado verificar el indicador de desbordamiento del temporizador1 en la rutina de interrupción de CCP1 para no perder un desbordamiento al guardar la "marca de tiempo".
¿Alguna idea sobre qué está creando este error?
Código abajo, bits de comfig e incluidos omitidos
/********************* 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;
}
EDITAR: pregunta añadida.