TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: aripod en 16 de Agosto de 2012, 14:04:51

Título: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 16 de Agosto de 2012, 14:04:51
Estoy tratando de utilizar las interrupciones del timer0 y timer1 simultaneamente. Una cada 10ms y la otra cada 3ms respectivamente. Luego de configurar todo, el primer problema surge en que solo se interrumpe una sola vez y nunca mas. El codigo es:

Citar
#include    "p18f4550.h"
#include   "timers.h"

#pragma config FOSC = HS
#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config PLLDIV = 1   //Divide by 1 (4 MHz oscillator input) (OSC tiene que ser multiplo de 4Mhz)

#define led1   PORTAbits.RA0   
#define led2   PORTAbits.RA1   

void interrupcion(void);

#pragma code prioridad_alta = 0X0008
void interrupcion_alta (void)
   {
   _asm goto interrupcion _endasm
   }
#pragma code

void interrupcion(void)
   {
   if(INTCONbits.TMR0IF == 1)             // check for TMR0 overflow
      {                     
       INTCONbits.TMR0IF = 0;          // clear interrupt flag
       TMR0H = 0xD8;                   // set the timer to expire in 10 ms. (at 4MHz)
       TMR0L = 0xA0;
      led1=!led1;
      }

   if(PIR1bits.TMR1IF == 1)             // check for TMR3 overflow
      {                     
        PIR1bits.TMR1IF = 0;            // clear interrupt flag
        TMR1H = 0xE5;                   // set the timer to expire in 3.3 ms. (at 4MHz)
        TMR1L = 0xF5;
      led2=!led2;
      }
   }

void main(void)
   {
   OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_1);
   TMR0H = 0xD8;
   TMR0L = 0xA0;

   OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T1_OSC1EN_OFF &  T1_SYNC_EXT_OFF );
   TMR1H = 0xE5;
   TMR1L = 0xF5;

   INTCONbits.PEIE = 1;
   INTCONbits.GIEH = 1;

   TRISA = 0x00;

   led1=0;   
   led2=0;

   while(1)
      {

      }
   }

Muchas gracias por la ayuda!!
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: irukza en 16 de Agosto de 2012, 15:38:37
Hola aripod

El problema es que C18 pone en cero el bit INTCONbits.GIEH automaticamente cada vez que entra en una rutina de atencion de interrupciones. Entonces, justo antes de salir de la rutina debes poner este bit en uno.
Agrega la linea que pongo en rojo y con eso tiene que funcionar.
saludos

void interrupcion(void)
   {
   if(INTCONbits.TMR0IF == 1)             // check for TMR0 overflow
      {                     
       INTCONbits.TMR0IF = 0;          // clear interrupt flag
       TMR0H = 0xD8;                   // set the timer to expire in 10 ms. (at 4MHz)
       TMR0L = 0xA0;
      led1=!led1;
      }

   if(PIR1bits.TMR1IF == 1)             // check for TMR3 overflow
      {                     
        PIR1bits.TMR1IF = 0;            // clear interrupt flag
        TMR1H = 0xE5;                   // set the timer to expire in 3.3 ms. (at 4MHz)
        TMR1L = 0xF5;
      led2=!led2;
      }
INTCONbits.GIEH = 1;
   }
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 16 de Agosto de 2012, 16:08:17
Agragada esa linea interrumpe....pero...los tiempos no son los que esperaba ver.....es mas, son aleatorios...no esta produciendo el desborde inclusive en la proporcion que deberia (tres interrupciones del timer1 por cada interrupcion del timer0)
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: irukza en 16 de Agosto de 2012, 17:24:23
Eso es porque esta mal el valor que le das al TMR1. Cargalo con el valor 0xf448. No te olvides de modificar este valor en la rutina de atencion a interrupciones.
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: irukza en 16 de Agosto de 2012, 17:49:52
Perdon, me doy cuenta ahora que hice el calculo para 3ms. El valor que debes usar es 0xf31c para 3.3ms.
Saludos
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 16 de Agosto de 2012, 20:10:20
Cambie el valor que estaba mal calculado....y el resultado que veo en proteus esta  en la imagen adjuntada.

La señal en amarillo es la del timer0 y la de azul es del timer1. El osc esta en 5mS/Div, por lo cual se puede ver que ni la de timer0 es de 10mS y ni la de azul es de 3mS. Es mas, cambia el tiempo de la interrupcion......y se puede ver que una es la inversa de la otra.
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 18 de Agosto de 2012, 12:46:45
Las interrupciones andan bien cuando las voy viendo con el MPLABSim, por tres interrupciones del timer1 hace una del timer0....pero,,,dentro de la interrupcion cuando hago LATDbits.LATD0=!LATDbits.LATD0, nunca pone en uno en el puerto.....pero si lo hago dentro del main, usando una variable de bandera en la interrupcion en vez de cambiar el valor del puerto, anda perfecto.
No se pueden cambiar los valores de los puertos, ya sea dentro de la interrupcion o en una llamada proveniente de la interrupcion?? Solo puedo cambiar valores de puertos cuando no hay interrupciones??
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: MerLiNz en 18 de Agosto de 2012, 13:31:43
has probado a poner LATDbits.LATD0=!PORTDbits.RD0; ?
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 18 de Agosto de 2012, 13:33:37
Con LATDbits.LATD0=!PORTDbits.RD0; anduvo perfecto!!
Gracias por la ayuda!!

Edit: Me apure en responder.....con el MPLABSim anda bien,,,pero cuando lo veo en proteus deja de andar....
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: Suky en 18 de Agosto de 2012, 14:48:28
Los registros LAT se usan para escribir en el puerto y los registros PORT para leerlos, ten en cuenta eso  ;-)


Saludos!
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 18 de Agosto de 2012, 15:03:11
Los registros LAT se usan para escribir en el puerto y los registros PORT para leerlos, ten en cuenta eso  ;-)


Saludos!

Teniendo en cuenta eso, ahora con el while infinito vacio y sin banderas, tengo en las interrupciones:
Citar
void interrupcion(void)
   {
   if(INTCONbits.TMR0IF == 1)             // check for TMR0 overflow
      {                    
       INTCONbits.TMR0IF = 0;          // clear interrupt flag
       TMR0H = 0xD8;                   // set the timer to expire in 10 ms. (at 4MHz)
       TMR0L = 0xA0;
      LATDbits.LATD0=!PORTDbits.RD0;
      //bandera1=!bandera1;
      }

   if(PIR1bits.TMR1IF == 1)             // check for TMR1 overflow
      {                    
        PIR1bits.TMR1IF = 0;            // clear interrupt flag
        TMR1H = 0xF4;                   // set the timer to expire in 3.3 ms. (at 4MHz)
        TMR1L = 0x48;
      LATDbits.LATD1=!PORTDbits.RD1;
      //bandera2=!bandera2;
      }
   
   INTCONbits.GIEH = 1;
   }
Viendolo en el watch anda bien,,,,pero cuando lo veo en proteus deja de andar.....es confiable esto en proteus o deberia bajarlo al pic y ver con un osciloscopio?
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: poseidon20 en 18 de Agosto de 2012, 19:53:10
No hay nada mejor que probarlo en la vida real, ya me paso que en el proteus no simulaba bien, pero en el ckto si o a veces ocurria al reves.
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: Suky en 18 de Agosto de 2012, 20:05:26
El tema de colocar INTCONbits.GIEH=1 al terminar la interrupción yo no lo uso  :roll: Me parece que el problema viene en la simulación con MPLAB SIM y no de C18.


Saludos!
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 18 de Agosto de 2012, 20:08:21
Voy a probar de no usarllo al final de la interrupcion....y lo voy a bajar al pic entonces......
Otra vez, gracias a los que me ayudaron!
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: jukinch en 19 de Agosto de 2012, 12:30:52
aripod:
           con las modificaciones que hiciste ¿funcionó bien la simulación en proteus?.
                Saludos.
                           Jukinch
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 19 de Agosto de 2012, 12:35:26
Ya no se que toque...pero el codigo esta asi:
Citar
#include    <p18f4550.h>
#include   "timers.h"

#pragma config FOSC = HS
#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config PLLDIV = 1   //Divide by 1 (4 MHz oscillator input) (OSC tiene que ser multiplo de 4Mhz)

#define led1   LATDbits.LATD0   
#define led2   LATDbits.LATD1   

char bandera1=0, bandera2=0;

void interrupcion(void);

#pragma code prioridad_alta = 0X0008
void interrupcion_alta (void)
   {
   _asm goto interrupcion _endasm
   }
#pragma code

void interrupcion(void)
   {
   if(INTCONbits.TMR0IF == 1)             // check for TMR0 overflow
      {                     
       INTCONbits.TMR0IF = 0;          // clear interrupt flag
       TMR0H = 0xD8;                   // set the timer to expire in 10 ms. (at 4MHz)
       TMR0L = 0xA0;
      LATDbits.LATD0=!PORTDbits.RD0;
      //bandera1=!bandera1;
      }

   if(PIR1bits.TMR1IF == 1)             // check for TMR1 overflow
      {                     
        PIR1bits.TMR1IF = 0;            // clear interrupt flag
        TMR1H = 0xF4;                   // set the timer to expire in 3.3 ms. (at 4MHz)
        TMR1L = 0x48;
      LATDbits.LATD1=!PORTDbits.RD1;
      //bandera2=!bandera2;
      }
   
   INTCONbits.GIEH = 1;   //Ver si hace falta o no.
   }

void main(void)
   {
   OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_1);
   TMR0H = 0xD8;
   TMR0L = 0xA0;

   OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T1_OSC1EN_OFF &  T1_SYNC_EXT_OFF );
   TMR1H = 0xF4;      //   periodo del desborde =  4  x  Prescaler  x  (65535 - valor cargado en timer0)
   TMR1L = 0x48;      //                     ----------------------------------------------------
                  //                                  cristal oscilador
   
   INTCONbits.TMR0IE = 1;   //enables timer0 overflow interrupt
   INTCONbits.PEIE = 1;   //enables all unmasked peripheral interrupt 
   INTCONbits.GIEH = 1;   //enables all interrupts   

   TRISD = 0x00;
   LATD = 0x00;

   while(1)
      {
//      if(bandera1==1)
//         {
//         LATDbits.LATD2=!PORTDbits.RD2;
//         bandera1=0;
//         }
//      if(bandera2==1)
//         {
//         LATDbits.LATD3=!PORTDbits.RD3;
//         bandera2=0;
//         }

      }
   }

Y esta andando bien en proteus.....en unos dias voy a probar en el pic....seguramente tambien andara bien
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: jukinch en 19 de Agosto de 2012, 12:52:38
aripod:
          Es que proteus me ha estado dando varios dolores de cabeza.  :5]. Aunque reconozco que fue por mi propia culpa. Y quería saber como había sido el resultado final.  ;-)
          Me pasó que quería ver el cambio de estado de los registros portA, portB, etc. por el watch windows. Y si no consultaba su estado mediante un IF en el programa principal proteus no mostraba ningún cambio en el watchwindows.
          Para hacer las pruebas cambiaba de estado de un pin en RB4 en plena simulación con un botón conectado tanto a gnd como a vcc con su respectiva resistencia y si bien se reflejaba el cambio de estado del pin con el cambio de color en el dibujo del pin del pic, en el watch windows no cambiaba de estado, siempre quedaba en 0.-
          Aclaro que para hacer esa prueba utilicé un programa que constaba únicamente de un while(1);
Código: [Seleccionar]
void main(void)
{
   ADCON1=0x0F;//Todos entrada/salida digitales.
   TRISB = 0b11111111; // PORTB como entradas
   TRISD = 0b00000000; // PORTD como salidas
   LATD = 0b00000000; // TODOS LOS PINES A 0
   while (1);
}

luego agregué el if que transcribo más abajo y si me mostró correctamente los cambios de estado del pin de entrada RB4.
Código: [Seleccionar]

if(PORTBbits.RB4==1) // testeamos RB4.
          {
               LATDbits.LATD0=1; // Si esta en 1 ENCENDEMOS led en RD0.
          }
        else
  {
               LATDbits.LATD0=0; // Si esta en 0 APAGAMOS Led en RD0.
          }

                    Saludos y gracias por responder.
                       Jukinch
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 19 de Agosto de 2012, 12:57:01
Al principio tenia que hacer lo mismo....pero era porque estaba haciendo LATDbits.LATD.0=!LATDbits.LATD.0 y vez de LATDbits.LATD.0=!PORTDbits.RD0;....creo que esa fue la solucion al problema....
Todo esto es porque necesitaba la int del timer1 para agregarla aun ucos que estoy usando, que basa sus ticks en el timer0......ya cuando pruebe sumandole el timer1, espero que siga andando todo!. Me parecio mas simple probar en un proyecto simple los dos timers simultaneamente para no complicar el sist. embebido mucho.... :-/
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 28 de Agosto de 2012, 19:01:03
Probe las interrupciones con los toggles bien,,,,pero surge un poblema cuando agrego un simple int que vaya incrementando para usarlo en el bucle infinito....

Citar
#include    <p18f4550.h>
#include   "timers.h"

#pragma config FOSC = HS
#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config PLLDIV = 1   //Divide by 1 (4 MHz oscillator input) (OSC tiene que ser multiplo de 4Mhz)

int numero=0;
void interrupcion(void);

#pragma code prioridad_alta = 0X0008
void interrupcion_alta (void)
   {
   _asm goto interrupcion _endasm
   }
#pragma code

void interrupcion(void)
   {
   if(INTCONbits.TMR0IF == 1)             // check for TMR0 overflow
      {                     
       INTCONbits.TMR0IF = 0;          // clear interrupt flag
       TMR0H = 0xD8;                   // set the timer to expire in 10 ms. (at 4MHz)
       TMR0L = 0xA0;
      LATDbits.LATD0=!PORTDbits.RD0;
      numero++;
      }

   if(PIR1bits.TMR1IF == 1)             // check for TMR1 overflow
      {                     
        PIR1bits.TMR1IF = 0;            // clear interrupt flag
        TMR1H = 0xF4;                   // set the timer to expire in 3.3 ms. (at 4MHz)
        TMR1L = 0x48;
      LATDbits.LATD1=!PORTDbits.RD1;
      //bandera2=!bandera2;
      }
   
   INTCONbits.GIEH = 1;   //Ver si hace falta o no.
   }

void main(void)
   {
   OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_1);
   TMR0H = 0xD8;
   TMR0L = 0xA0;

   OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T1_OSC1EN_OFF &  T1_SYNC_EXT_OFF );
   TMR1H = 0xF4;      //   periodo del desborde =  4  x  Prescaler  x  (65535 - valor cargado en timer0)
   TMR1L = 0x48;      //                     ----------------------------------------------------
                  //                                  cristal oscilador
   
   INTCONbits.TMR0IE = 1;   //enables timer0 overflow interrupt
   INTCONbits.PEIE = 1;   //enables all unmasked peripheral interrupt 
   INTCONbits.GIEH = 1;   //enables all interrupts   

   TRISD = 0x00;
   LATD = 0x00;

   TRISDbits.TRISD2=1;

   while(1)
      {
      if(numero==100)
         {
         numero=0;
         }
      }
   }
El incremento de la variable numero lo hace bien, pero el if(numero==100) entra por mas que numero NO sea igual a 100......
Si deshabilito la interrupciones e incremento numero dentro del while(1) entra al if cuando numero es 100....se entiendie???
Cambie de lugar el if....lo puse dentro de la interrupcion y anda perfecto.....
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: jukinch en 28 de Agosto de 2012, 23:08:41
Probá usando el calificador volatile.
Título: Re: Problema Interrupciones Multiples [18F4550]
Publicado por: aripod en 28 de Agosto de 2012, 23:56:50
Le agregue el volatile pero sigue igual......en el while infinito entra con cualquier valor y si hago el if dentro de la interrupcion entra segun la condicion del if...