Interrupción externa no vuelve al programa

Hola. Aquí les dejo mi inquietud en un vídeo.
Anexo el programa:​
PHP:
//***********************HEADER**************************************************
// Lavadora digital

//MICROCONTROLADOR PIC16F883
// mikroc  Pro for PIC v6.0.0
//simulación con proteus  windows 8 (x64) v6.02 build 9200 /

//recuerda que se deben ajustar los tiempo de llenado bajo, medio, alto
// en cada ciclo , y que los tiempos de vaceado deberian ser los mismos
//ojo con los tiempos de seguridad para que el motor principal no se frene

//*****************************************************************************

//Pines de salida para el LCD
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D4 at RB7_bit;

//Bits de configuración TRIS b para el lcd
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D7_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB7_bit;

// funciones (subrutinas)   que seran llamadas a cumplir una funcion especifica
void lavado();
void pantalla();
void centrifuga();
void llenado();
void llenado_bajo();
void sensor_presion();
void exprimir();
void interrupt(void);     // si se activa RB0, para el sistema

 // strings para lcd en cada subrutina
char txt1 [] = "mantenimiento";
char txt2 [] = "3137458698";
char txt3 [] = "presione inicio";
char txt4 [] = "3 segundos";
char txt5 [] = "nivel";
char txt6 [] = "lavando";
char txt7 [] = "nv bajo";
char txt9 [] = "nv alto";
char txt10 [] = "llenando agua";
char txt11 [] = "Bajo Medio Alto";
char txt12 [] = "nv medio";
char txt13 [] = "presion";
char txt14 [] = "exprimiendo";
char txt15  [] = "fin-apagar";

int nivel; //bandera pDE nivel de agua escogido para el lavado y exprimido.
#define Int_pin TRISB.F0 //define RB0 como el pin de interrupción

//**********************funcion principal***********************************
void main() {
ANSEL  = 0;                   // eliminar entradas analogas
ANSELH = 0;                  // eliminar entradas analogas
C1ON_bit = 0;               //eliminar comparadores
C2ON_bit = 0;              //eliminar comparadores
Int_pin=1;                 // habilita RB0 como entrada para interrupcion
PORTC = 0b00000000;       //puerto C estado inicial 0
TRISC=  0b11110000;      //rc7- start , rc6 sensor nivel sw,rc5 level low
TRISB.F6=0;             // habilita rb6 como salida por si se necesita
PORTA=0;               // rc4,medium level , rc3-hi level , rc2 electrovalvula
TRISA=0b11100000;     //rc1, valvula llenado , rco motor principal, RA0-vaciado
INTCON = 0x90;       // banderas de interrupción, habilita interrupcion global
                    // y habilita interrupcion externa
WPUB = 0x01;                         // Pull-Up en pin RB0
Lcd_Init();                         // llama a la rutina de inicio del LCD.
Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off

//************************ loop principal*************************************

while( 1 )                       //Bucle infinito
{
Lcd_Out( 1, 1, txt1);        //mantenimiento
Lcd_Out( 2, 1, txt2);       //numero celular
Delay_ms(1000);             // retardo texto pantalla
Lcd_Cmd(_LCD_CLEAR);               // Clear display
Lcd_Out( 1, 1, txt3 );            // presione iniciar
Lcd_Out( 2, 1, txt4 );           //por 4 segundos
Delay_ms(1000);                 // retardo texto pantalla
Lcd_Cmd(_LCD_CLEAR);          // borrar pantalla
if( PORTC.F7==1 ){           //Evalúa si presionó el boton iniciar
delay_ms(20);               // retardo   antirebote
llenado();                 //llama a la rutina llenado de agua
 }
else{                     // si no presiona iniciar
PORTC=0;                 //  asegura que las salidas en cero
PORTA.F0=0;
}
}
}
//**************************si RB0 SE ACTIVA-- interrumpe apaga todo*********

void interrupt(void){          // rutina de interrupción externa por RB0
  if(INTCON.INTF == 1 ){    // si la bandera de interrupcion se activo haga
  while (1){
    if (PORTB.F0==1){     //haga mientras RB0 = 1
    delay_ms(20);        //  retardo antirebote
    PORTC.F0=0;         //pare motor principal
    PORTC.F1=0;         //pare valvula de llenado
    PORTA.F0=0;         //pare valvula de vaceado
    //PORTC.F2=0;         // pare electrovalvula
    PORTA.F4=1;            // que parpadee RA4
    delay_ms(500);
    PORTA.F4=0;            // que parpadee RA4
    delay_ms(500);
    }
    else{
    PORTA.F4=1;
    INTCON.INTF = 0;   // borra la bandera de interrupción para salir de rutina
          // PERO NO SE A DONDE SE VA PORQUE NO REGRESA DONDE IBA
    }
  }

  }
}
 
Última edición por un moderador:
No uses un If (PORTB.F0 == 1) Eso se determina por la configuración de selección de flanco.
La selección del flanco de activación se realiza en el registro OPTION_REG bit 6 (INTEDG)
Tampoco está bien que el flag INTF esté condicionado.
Los flags de interrupción deben limpiarse antes o después de la ejecución de código, dependiendo de la situación.
 
hola,gracias a todos por la respuesta la idea con el while es que no salga hasta que el RB0 este en cero

D@rkbytes , creo entender que dentro de la rutina de interrupción no lea el puerto sino una bandera pero como lo hago?
 
D@rkbytes, creo entender que dentro de la rutina de interrupción no lea el puerto sino una bandera. ¿Pero, cómo lo hago?
Pues ya lo estás haciendo al comprobar el estado de INTF.
Si está en 1, significa que ocurrió una interrupción por RB0 y dependiendo del estado del bit INTEDG es como se decide si la interrupción ocurrirá por flanco ascendente o por flanco descendente.
Si se establece en 1 el bit 6 del registro OPTION_REG, la interrupción ocurrirá por flanco ascendente, y estando en 0, ocurrirá por flanco descendente.
(Como ya te podrás ir imaginando, al seleccionar flanco ascendente, la interrupción ocurrirá cuando el estado del pin RB0 sea llevado del estado bajo al estado alto. "Rising Edge")
A continuación, puedes deshabilitar las interrupciones para evitar reingresos, limpiar el flag INTF o hacerlo hasta salir de la rutina.
La idea con el while, es que no salga hasta que el RB0 esté en cero
Entonces debes hacerlo así:
while (PORTB.F0 == 1) o así, que es lo mismo: while (PORTB.F0)

Vendría siendo como esto:
PHP:
void interrupt (void)
{
   if(INTCON.INTF)      // Si ocurrió interrupción por RB0...
   {
      while (PORTB.F0)  // Mientras RB0 = 1...
      {
         // Código mientras RB0 esté en 1.
      }
      // Código cuando RB0 esté en 0.
      INTCON.INTF = 0;  // Limpiar flag INTF
   }
}

Aquí se ejecuta código mientras RB0 esté en 1, se sale del bucle cuando RB0 sea 0, se ejecuta código y se limpia el flag INTF.
De esta manera la limpieza del flag INTF no queda condicionada por la sentencia "if (PORTB.F0 == 1)", sino por la misma ejecución de la interrupción por RB0, o sea, cuando se determina que el bit INTF está en 1.

Nota que en este código se siguen permitiendo reingresos, y esto se evita deshabilitando las interrupciones globales al ingresar al servicio de interrupción, posteriormente se vuelven a habilitar y el programa continúa su ejecución hasta una nueva interrupción.
 
Última edición:
Atrás
Arriba