Tengo un problema que no se si es debido a algún bug del C18 o (mucho más posible) a
alguna tontería que estoy haciendo y que no consigo darme cuenta:
Lanzo una interrupción del TMR0 para que salte cada 100 usec. Lo unico que hace es
cambiar el estado de RC0. Todo perfecto. Pantallazo del osciloscopio:
RC0 cambia cada 100 usec como era esperable.
Ahora añado un poco de trabajo al código de la interrupción. Un simple delay de 50 usec
para simular una tarea. Uso RC1 para indicar arranque/fin de la tarea. En la imagen siguiente
muestro el resultado:
La tarea monitorizada en RC1 dura los 50 usec estipulados, pero ahora la siguiente interrupción
entra unos 35 usec retrasada. Este retraso no parece depender del "trabajo"
que le pida en la interrupción. Da igual estipular un delay de 10 que de 90 usec:
la interrupción del TMR0 parece retrasarse lo mismo, unos 30-40 usec.
Supongo que es algún problema del proceso de adaptación
al C18 (vengo de MikroC pro), pero le he dado algunas vueltas y no consigo detectar el fallo.
Me fastidia porque me impide estar seguro de que algo sucede justo cuando quiero.
También he probado cambiar el delay por cualquier otra tarea y el resultado es el mismo,
un retraso en la interrupción del TMR0 de unos 35 usec.
Un programa "idéntico" en MikroC Pro funciona correctamente: el delay codificado en la
interrupción modifica el tiempo que RC1 (abajo) esta alto, pero no altera la frecuencia de
disparo de la interrupción (RC0 arriba):
Un saludo, y gracias por adelantado
Antonio
Adjunto código usado en C18 (da el problema que he tratado de explicar)
#include <p18F4520.h>
#include <delays.h>
#include <timers.h>
#pragma config OSC=HS
#pragma config PWRT = OFF, BOREN = OFF
#pragma config WDT = OFF, WDTPS = 128
#pragma config PBADEN = OFF, LVP = OFF
typedef unsigned char uint8;
typedef unsigned int uint16;
#define set_TMR0(x) {TMR0H=(x>>8); TMR0L=(x&0x00FF);}
#define start_TMR0 T0CONbits.TMR0ON=1;
#define stop_TMR0 T0CONbits.TMR0ON=0;
#define enable_global_ints INTCONbits.GIE=1
#define enable_TMR0_int INTCONbits.TMR0IE=1
#define TMR0_flag INTCONbits.TMR0IF
uint16 TMR0_reset;
// High priority interruption
#pragma interrupt TIMER_ISR
void TIMER_ISR (void)
{
if (TMR0_flag)
{
set_TMR0(TMR0_reset); // reset counter
PORTCbits.RC0=~PORTCbits.RC0; // Blink PORTC
PORTCbits.RC1=1;
Delay10TCYx(25); // 50 usec
PORTCbits.RC1=0;
TMR0_flag=0; // clear flag
}
}
// Code @ 0x0008 -> Jump to ISR for high priority ints
#pragma code high_vector = 0x0008
void high_interrupt (void){_asm goto TIMER_ISR _endasm}
#pragma code
void main()
{
TRISC=0; PORTC=0;
TMR0_reset=65056;
T0CON=0b10001000;
enable_TMR0_int; enable_global_ints;
start_TMR0;
while(1);
}
Aqui va el código (equivalente) para MikroC Pro que funciona OK:
#define set_TMR0(x) {TMR0H=(x>>8); TMR0L=(x&0x00FF);}
#define start_TMR0 T0CON.TMR0ON=1;
#define stop_TMR0 T0CON.TMR0ON=0;
#define enable_global_ints INTCON.GIE=1
#define enable_TMR0_int INTCON.TMR0IE=1
#define TMR0_flag INTCON.TMR0IF
typedef unsigned char uint8;
typedef unsigned int uint16;
uint16 TMR0_reset;
void interrupt() //Rutina principal de interrupcion
{
if (TMR0_flag) // ISR de la interrupcion de TMR0
{
set_TMR0(TMR0_reset); // reset counter
PORTC.RC0=~PORTC.RC0; // Blink PORTC
PORTC.RC1=1;
delay_us(50);
PORTC.RC1=0;
TMR0_flag=0;
}
}
void main()
{
TRISC=0; PORTC=0X00; TRISB=0; PORTB=0;
TMR0_reset=65056;
T0CON=0b10001000;
enable_TMR0_int; enable_global_ints;
start_TMR0;
while(1);
}