Trabajar con dos interrupciones 18f452

hola gente, soy nuevo en esto de los microcontroladores y he tenido problemas para trabajar con dos interrupciones, especificamente int ext y int timer1, el codigo lo que hace es detectar en que sentido se mueve el motor de una puerta y en base a esto realizar una accion, la puerta tiene unos sensores y al acercarse alguien se abre hacia adentro, en ese caso el programa solo enciende un led, pero si una persona viene desde dentro la puerta no se abre, lo que hice en ese caso fue usar el contador que le puse al encoder y si se decrementa (llegado a ciertos parametros) activa unos reles que estan conectados a un modulo de la puerta que regula en que sentido abre y da la alimentacion para que abra, hasta ahi todo bien, el problema que tengo es que quiero que pasado 10 segundos la puerta vuelva a su funcionamiento normal desctivando la alimentacion y quitando el cambio de polaridad, eso lo quiero hacer con el timer 1 o timer 0, para el caso da lo mismo, la cosa es que no se como configurar el timer para que empieze a contar desde una linea especifica y para que no tenga conflictos con la interrupcion externa, mas abajo esta el codigo de lo que llevo, desde ya agradesco su ayuda :)

Código:
#Include <18F452.h>           
#Fuses XT, NOWDT, NOPROTECT, NOLVP, BROWNOUT
#use Delay( Clock = 4000000 )
#include <LCD.c>


#Byte PortA = 0xF80            
#Byte PortB = 0xF81            
#Byte PortC = 0xF82            
#Byte PortD = 0xF83            

// ------ Variable Global ------
int16 cont = 3000;                
int   temp = 0;                   
int   flag_temp;                  
                                
                                

// --------- Interrupción ---------
#int_TIMER1
void  TIMER1_isr(void) {
 disable_interrupts(INT_TIMER1);
 set_timer1(3036);
 temp++;
 if(temp==20){
 flag_temp=0;
 }
 
      }


#INT_EXT                        // Interrupción Externa por RB0: Decodificación de Encoder.
Void IntRB0() 
{
   

   If (Bit_Test(PortB, 0))      // Si RB0 se ha puesto a 1 (flanco de subida),
   {  
       Ext_Int_Edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de
                                // bajada. 
       If (Bit_Test(PortB, 1))  // Si RB1 está a 1,
       {
         
           cont++;                 // entonces incrementar una unidad el valor de cont.
          
       }
   }
   Else                         // Si RB0 se ha puesto a 0 (flanco de bajada),
   {  
       Ext_Int_Edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de
                                // subida.
       If (Bit_Test(PortB, 1))  // Si RB1 está 1,
       {
         
           cont--;                 // entonces decrementar una unidad el valor de cont.
           
       }
   }
  
}

Void Main(){                  // Inicio y configuración.
   lcd_init();
   Port_B_Pullups(FALSE);       // Configuración para el PIC 18F4550.
   Setup_ADC_Ports(NO_ANALOGS); // Sin comparadores ni ADCs, todo digital, etc...
   Setup_adc(ADC_CLOCK_DIV_2);
   Setup_spi(SPI_SS_DISABLED);
   Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   Setup_timer_2(T2_DISABLED,0,1);
   set_timer1(3036);
   

   Enable_Interrupts(Int_Ext);  // Activar Interrupción Externa a través de RB0. 
   Ext_Int_Edge(L_TO_H);        // Inicialmente detectar interrupción por flanco de subida. 
   Enable_Interrupts(GLOBAL);   // Interrupciones Generales Activadas. 

   Set_Tris_A(0b00000000);      // Puerto A todo entradas, 
   Set_Tris_B(0b11111111);      // Puerto B todo entradas, sólo usamos las entradas RB0 yRB1.
   Set_Tris_C(0b00000000);      
   PortA=0;
   
   // ---------- Programa Principial ----------
        
   While (True){

      lcd_gotoxy(5,1);
      printf(LCD_PUTC, "Posicion");
      lcd_gotoxy(7,2);
      printf(LCD_PUTC, "%Ld",cont);
    
      while((cont>3010)&&(cont<=3150)){              
 
         lcd_gotoxy(5,1);
         printf(LCD_PUTC, "Posicion");
         lcd_gotoxy(7,2);
         printf(LCD_PUTC, "%Ld",cont);
 
         bit_set(PORTA,2);
         //delay_ms(200);
   
      }
      bit_clear(PORTA,2);
      flag_temp = 1;
      enable_interrupts(INT_TIMER1);//inicia temporizador 10seg por interrupcion (definir un   
                                                //flag_temp que de cero cuando se cumplan 10 segundos)
 
      while((cont<2995)&&(cont>=2870)&&(flag_temp==1)){
         
            lcd_gotoxy(5,1);
            printf(LCD_PUTC, "Posicion");
            lcd_gotoxy(7,2);
            printf(LCD_PUTC, "%Ld",cont);
            bit_set(PORTA,0);
            delay_ms(100);
            bit_set(PORTA,1);
         
         
      }
      while((cont<2995)&&(cont>=2870)&&(flag_temp==0)){
         
         lcd_gotoxy(5,1);
         printf(LCD_PUTC, "Posicion");
         lcd_gotoxy(7,2);
         printf(LCD_PUTC, "%Ld",cont); //ver posicion de encoder por LCD 
         bit_clear(PORTA,1);//saco alimentacion
         delay_ms(100);
         bit_clear(PORTA,0);//reestablesco el sentido de giro
         
      }   
         
   }
}
 
Hola.
Con decir...
como configurar el timer para que empieze a contar desde una linea especifica
Te refieres a las líneas del código??... bueno, eso solo se puede hacer manualmente; tienes...

--->
enable_interrupts() // Para habilitar la interrupción del Timer
disable_interrupts() // Para desactivar la interrupción del Timer
clear_interrupt()
set_timer...() // Para establecer un valor en el contador del timer o reiniciar conteo...
--->

Sobre los conflictos a simple vista no veo que pueda tener... en los 16F se intenta salvar el contexto para que no se pierdan datos por suceder una interrupción, pasa lo mismo con los 18F, además el CCS se supone que hace esto automáticamente pero te puedes asegurar....

En los 18F también tienes la posibilidad de dar prioridad a las interrupciones:
Baja prioridad, se ejecuta igual que en un 16F
Alta prioridad, igual que en un 16F pero también se ejecuta si hay una de baja prioridad activa...

Código:
#device HIGH_INTS = TRUE // habilita prioridades
.. 
#priority INT_TIMER0 // ver Help del CCS
.. 
#INT_TIMER1 HIGH 
void timer1_interrupt() 
{ 
...
}
 
claro, me refiero a que el timer empiece a contar desde un punto especifico del codigo, en este caso lo quiero hacer para que salga del ciclo while que esta en rojo, cosa que ejecute lo que esta en ese ciclo, se active la interrupcion y luego pase al while que esta en azul

Código:
#Include <18F452.h>           
#Fuses XT, NOWDT, NOPROTECT, NOLVP, BROWNOUT
#use Delay( Clock = 4000000 )
#include <LCD.c>


#Byte PortA = 0xF80            
#Byte PortB = 0xF81            
#Byte PortC = 0xF82            
#Byte PortD = 0xF83            

// ------ Variable Global ------
int16 cont = 3000;                
int   temp = 0;                   
int   flag_temp;                  
                                
                                

// --------- Interrupción ---------
#int_TIMER1
void  TIMER1_isr(void) {
 disable_interrupts(INT_TIMER1);
 set_timer1(3036);
 temp++;
 if(temp==20){
 flag_temp=0;
 }
 
      }


#INT_EXT                        // Interrupción Externa por RB0: Decodificación de Encoder.
Void IntRB0() 
{
   

   If (Bit_Test(PortB, 0))      // Si RB0 se ha puesto a 1 (flanco de subida),
   {  
       Ext_Int_Edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de
                                // bajada. 
       If (Bit_Test(PortB, 1))  // Si RB1 está a 1,
       {
         
           cont++;                 // entonces incrementar una unidad el valor de cont.
          
       }
   }
   Else                         // Si RB0 se ha puesto a 0 (flanco de bajada),
   {  
       Ext_Int_Edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de
                                // subida.
       If (Bit_Test(PortB, 1))  // Si RB1 está 1,
       {
         
           cont--;                 // entonces decrementar una unidad el valor de cont.
           
       }
   }
  
}

Void Main(){                  // Inicio y configuración.
   lcd_init();
   Port_B_Pullups(FALSE);       // Configuración para el PIC 18F4550.
   Setup_ADC_Ports(NO_ANALOGS); // Sin comparadores ni ADCs, todo digital, etc...
   Setup_adc(ADC_CLOCK_DIV_2);
   Setup_spi(SPI_SS_DISABLED);
   Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   Setup_timer_2(T2_DISABLED,0,1);
   set_timer1(3036);
   

   Enable_Interrupts(Int_Ext);  // Activar Interrupción Externa a través de RB0. 
   Ext_Int_Edge(L_TO_H);        // Inicialmente detectar interrupción por flanco de subida. 
   Enable_Interrupts(GLOBAL);   // Interrupciones Generales Activadas. 

   Set_Tris_A(0b00000000);      // Puerto A todo entradas, 
   Set_Tris_B(0b11111111);      // Puerto B todo entradas, sólo usamos las entradas RB0 yRB1.
   Set_Tris_C(0b00000000);      
   PortA=0;
   
   // ---------- Programa Principial ----------
        
   While (True){

      lcd_gotoxy(5,1);
      printf(LCD_PUTC, "Posicion");
      lcd_gotoxy(7,2);
      printf(LCD_PUTC, "%Ld",cont);
    
      while((cont>3010)&&(cont<=3150)){              
 
         lcd_gotoxy(5,1);
         printf(LCD_PUTC, "Posicion");
         lcd_gotoxy(7,2);
         printf(LCD_PUTC, "%Ld",cont);
 
         bit_set(PORTA,2);
         //delay_ms(200);
   
      }
      bit_clear(PORTA,2);
      flag_temp = 1;
      enable_interrupts(INT_TIMER1);//inicia temporizador 10seg por interrupcion (definir un   
                                                //flag_temp que de cero cuando se cumplan 10 segundos)
 
      [COLOR="Red"]while((cont<2995)&&(cont>=2870)&&(flag_temp==1)){
         
            lcd_gotoxy(5,1);
            printf(LCD_PUTC, "Posicion");
            lcd_gotoxy(7,2);
            printf(LCD_PUTC, "%Ld",cont);
            bit_set(PORTA,0);
            delay_ms(100);
            bit_set(PORTA,1);
         
         
      }[/COLOR]
      [COLOR="Blue"]while((cont<2995)&&(cont>=2870)&&(flag_temp==0)){
         
         lcd_gotoxy(5,1);
         printf(LCD_PUTC, "Posicion");
         lcd_gotoxy(7,2);
         printf(LCD_PUTC, "%Ld",cont); //ver posicion de encoder por LCD 
         bit_clear(PORTA,1);//saco alimentacion
         delay_ms(100);
         bit_clear(PORTA,0);//reestablesco el sentido de giro
         
      }   [/COLOR]
         
   }
}
 
Si la int. del Timer se ejecuta bien, podrias forzar con break...

temp = 0;
flag_temp = 1;
set_timer1(3036); // Iniciar los contadores antes de iniciar el Timer1
enable_interrupts(INT_TIMER1);

while(cont > 2870 && cont < 2995)
{
lcd_gotoxy(5,1);
printf(LCD_PUTC, "Posicion");
lcd_gotoxy(7,2);
printf(LCD_PUTC, "%Ld",cont);
bit_set(PORTA,0);
delay_ms(100);
bit_set(PORTA,1);

if(!flag_temp)
break;
}

disable_interrupts(INT_TIMER1); // Detiene int.

----------------
Usar disable_interrupts(...); dentro de la misma interrupción no hace ningún efecto a menos que se quiera desactivar otra int. de alta prioridad... no la misma.
 
ese flag (flag_temp) lo estoy usando para que no caiga denuevo en el ciclo while que activa los reles, por eso en la interrupcion lo pongo a 0, asi no entra denuevo y se salta al otro while que los desactiva, ya que el encoder sigue contando cuando el motor se empieza a devolver, o si no estaria todo el rato entrando al while que activa los reles porque cumpliria con los parametros, lo primero que ya me quedo claro es que no es necesario desactivar la interrupcion dentro de la interrupcion :LOL:, aun asi, lo he simulado y todo y no salta a la rutina de interrupcion, ese es mi problema D:
 
-Perdon por la interrupcion-

En mi caso son INT EXT e INT RB (mismo micro 18f452)
Que e de poner para que INT EXT tenga prioridad

Y pregunta:
Si INT EXT es prioritaria aunque se produzca int rb no la atendera. Si el programa esta sumergido dentro de int rb saldra de esta de inmediato para atender a INT EXT
¿Estos conceptos son asi?. Es lo que quiero



Si INT EXT es prioritaria aunque se produzca int rb no la atendera
Mas esplicito. Quise decir no atendera a INT RB solo en el caso de que no este sumergido en INT EXT Claro.
 
Última edición:
Atrás
Arriba