Me pasa algo raro con las Interrupciones

Estoy programando un 16F2550 usando CCS me surgio el siguiente problema que no se si es mi error de alguna configuracion o sera otra cosa quisiera su opinion, para hacerlo mas sencillo reduje el codigo para poder ver bien el error, sucede que si miran el codigo cada vez que se dispara la interrupcion 0 de Alto a Bajo enciende o apaga un led e incrementa un contador
ya en la rutina principal Activo las interrupciones y espero que sea la tercera pulsacion para
encender durante 2 segundos otro led

Aqui esta la cosa rara si despues de disable_interrups(GLOBAL) no se presiona el boton todo normal 0 problemas, ahora si despues de eso se presiona el boton durante el tiempo que el delay esta activado no se activa la interrupcion y eso esta bien PERO la rutina de interrupcion se ejecuta automaticamente al pasar por enable_interrups lo cual lo pueden comprobar con el primer led.

1era Interrupcion LED ON
2da Interrupcion LED OFF
3ra Interrupcion LED ON << y asi se tendria que quedar esperando hasta que sea presionado el boton y lo apague

Aqui les envio el codigo para que si quieren lo prueben a ver si les pasa lo mismo o me digan si tengo algun error.
Código:
#use delay(clock=48000000)     // el clock que tendremos a la entrada del CPU
#use fast_io(B)                //compilador usar puerto rapido no reconfigurar cada vez q se setea el puerto
#zero_ram                      //limpia ram

int CuentaClicks;

#int_ext
void ext_handler() {
   output_toggle(PIN_C4);
   CuentaClicks++;    
}

void main(){    
    //---------------------desactivo interrupciones globales--------------------
    disable_interrupts(GLOBAL);
    //-------------------------configuracion de puertos-------------------------
    setup_adc_ports(NO_ANALOGS);  //desactivando puertos analogicos 
    setup_adc(ADC_OFF);           //desactivando conversor analogo digital    
    //-------------------------configuracion de timers---------------------------
    setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256); //tiempo del timeout 4/48000000*65536*128 = 699ms
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED, 255, 1);
    setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
    //-------------------------configuracion de los edges de disparo---------------
    ext_int_edge(0,H_TO_L);
    set_tris_b(0b11111111); //todo el puerto como entrada
    //------------------------activando interrupciones-----------------------------
    enable_interrupts(INT_EXT);
    //------------------------inicializacion del display---------------------------
    output_low(PIN_C4);
    output_low(PIN_C5);
    while(TRUE) { 
       CuentaClicks = 0;
       enable_interrupts(GLOBAL); //solo aqui pueden haber interrupciones
       while(CuentaClicks <= 2){
       } 
       disable_interrupts(GLOBAL); 
       output_high(PIN_C5);
       delay_ms(2000);
       output_low(PIN_C5);
    }//mega while
}//main
 
En algunos uC los flag de interrupción (en el registro que pertenezca) se borran solos una vez que ingresa a la rutina de interrupción.

Tal vez en tu caso lo que está pasando es que al deshabilitar la interrupción los flags de interrupción nunca son borrados (osea, si pulsas el interruptor cambias el estado del flag, por ej. lo dejas en 1) y al activar las interrupciones al ver el estados de esos flags salta a la rutina.

Si ese es tu caso, la solución sería limpiar manualmente ese flag en particular antes de habilitar las interrupciones en forma global.

PD: ¿en vez de inhabilitar todas las interrupciones, no podrías deshabilitar la que solo te interesa?, digo por si en un futuro querés agregar cosas en el código, ya sabes que cada periférico es manejado por su rutina y no afecta a otros.

Editado:

Fijate en la página 101/103 del datasheet, habla de los bit que te mencionaba INT0IF/INT1IF/INT2IF que deben ser limpiados por soft.

Entonces si usas la externa 0:

Código:
...
INTCON&=~(1<<INT0IF); // Funciona como mascara (1<<INT0IF)=0b00000010 => ~(1<<INT0IF)=0b11111101 => INTCON&=~(1<<INT0IF) dará 0bxxxxxx0x 
..

Editado 2:

Fijate en la página 111, incluso en la rutina de interrupción tenés que limpiar ese flag por software, con lo cual esa linea que te dije la tendrías que agregar en la rutina de interrupción y después del delay antes de volver habilitar las interrupciones generales.
 
Última edición:
Gracias cosme efectivamente con el bit INT0IF puesto a 0 antes de activar las interrupciones no se lanza para mi que el compilador o el propio pic deberia de limpiar esa bandera al activar la interrupcion. En el header del ccs no esta el INTCON asi que para el que le sirva lo puden hacer asi tambien
Código:
#byte INTCON = 0xFF2
....
       bit_clear(INTCON,1);
       enable_interrupts(GLOBAL);

PD. Con lo del comentario sobre por que usaba la global en vez de solo la interrupcion, es solo por que se tienen que activar y desactivar las 3 interrupciones al mismo tiempo asi que mejor 1 linea de codigo a 3 lineas
 
..para mi que el compilador o el propio pic deberia de limpiar esa bandera al activar la interrupcion.

El compilador es simplemente un traductor de tu código, solo hace lo que vos le decis que haga :D .

Hay uC que automáticamente limpian esos flags una vez que entras en la interrupción, incluso habría que ver como son los flags de los timers, tal vez en este uC se limpien solos.

... En el header del ccs no esta el INTCON ...

Si es así, eso está muy mal por parte del compilador (o más bien de las librerías con las que vino), si bien C está bueno para aislarte de ciertas cosas, de vez en cuando tenés que saber con que registros estas tratando y que no todo sea transparente.

PD. Con lo del comentario sobre por que usaba la global en vez de solo la interrupcion, es solo por que se tienen que activar y desactivar las 3 interrupciones al mismo tiempo asi que mejor 1 linea de codigo a 3 lineas

Si, efectivamente para este programa va todo bien, yo lo decía que a futuro si querés usar este mismo código para reciclarlo (no hacerlo una y otra y otra vez), sería piola que no afectaras a otros periféricos, osea sería simplemente deshabilitar la interrupción EXT0 y listo.

Supone que a ese código le querés reemplazar el delay por una demora usando el timer, ahí ya tendrías problemas para usar la interrupción del timer.

Bahh... no sé, supongo que dependerá de cada uno, yo soy de pensar el código de los periféricos en forma muy modular (bloques separados que sean independientes unos de otros) y que a futuro se puedan insertar fácilmente en algo más complejo.
 
Última edición:
Atrás
Arriba