Autor Tema: Problema con INT del TMR0 en C18  (Leído 1524 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado ant

  • PIC10
  • *
  • Mensajes: 10
    • picfernalia
Problema con INT del TMR0 en C18
« en: 28 de Junio de 2012, 10:51:01 »
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)
Código: [Seleccionar]
#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:
Código: [Seleccionar]
#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);
}