Un detalle que yo uso mucho y que elimina una buena parte de lo conflictos que se generan al usar interrupciones.
Hay una regla de oro que siempre es conveniente aplicar:
Dentro de la rutina de tratamiento de una interrupción haz exactamente lo mínimo para tratar convenientemente dicha interrupción.Te pongo por ejemplo tu propia rutina:
Modo 1.-#int_EXT
EXT_isr()
{
output_high(PIN_B5); //Se activa el led
delay_ms(1000); //Hacemos una pausa de 1 segundo
output_low(PIN_B5); //Se desactiva el led
delay_ms(1000);
menu();
}
Ahí llamas a la función
menu() que puede ser corta o larga, que puede generar estados incompatibles con lo que estas tratando en la interrupción, o que simplemente mantiene durante mucho tiempo la interrupción viva, sin ser tratada del todo y que por lo tanto puede solaparse con otras interrupciones o incluso consigo misma ....
Una sana practica es habilitar un
flag dentro de la interrupción para que sea disparada tu funcion pero ejecutada desde el
main() no desde la interrupción.
Yo modificaría tu código de la siguiente forma:
Modo 2.-int1 ejecutar_menu=0;
#int_EXT
EXT_isr()
{
output_high(PIN_B5); //Se activa el led
delay_ms(1000); //Hacemos una pausa de 1 segundo
output_low(PIN_B5); //Se desactiva el led
delay_ms(1000);
ejecutar_menu = 1;
}
main(){
While(true){
if(ejecutar_menu==1){
ejecutar_menu = 0;
menu();
}
}
}
Esta forma de hacerlo es muy simple y te aseguras que la funcion
menu() no te retrasa la liberación de la rutina de interrupción.
Por otro lado si también deseas que al producirse la interrupción se ejecute cierta rutina
una y solo una vez y que hasta que no acabe dicha rutina no permitas una nueva interrupción solo tienes que deshabilitar la interrupción al entrar en ella y habilitarla al terminar ...
Modo 3.-int1 ejecutar_1_rutina=0;
#int_EXT
EXT_isr()
{
ejecutar_1_rutina = 1;
}
main(){
While(true){
if(ejecutar_1_rutina==1){
disable_interrupts(int_ext);
ejecutar_1_rutina=0;
output_high(PIN_B5); // Se activa el led
delay_ms(1000); // Hacemos una pausa de 1 segundo
output_low(PIN_B5); // Se desactiva el led
delay_ms(1000);
menu();
disable_interrupts(int_ext);
}
}
}
Y por último una mezcla de ambos mundos, una parte de tu rutina se dispara
siempre y otra, el menu, solo
una vez y hasta que no concluya completamente no puede volver a dispararse:
Modo 4.-int1 ejecutar_menu=0;
int1 ejecutando_menu=0;
#int_EXT
EXT_isr()
{
output_high(PIN_B5); //Se activa el led
delay_ms(1000); //Hacemos una pausa de 1 segundo
output_low(PIN_B5); //Se desactiva el led
delay_ms(1000);
if(ejecutando_menu==0){
ejecutar_menu = 1;
}
}
main(){
While(true){
if(ejecutar_menu==1){
ejecutando_menu=1;
ejecutar_menu = 0;
menu();
ejecutando_menu=0;
}
}
}
Con este último método si se producen varias interrupciones consecutivas que se solapen te aseguras de que menu() solo se ejecutará cada vez que
haya terminado la ejecución anterior, no todas la veces que ocurra.
Si deseas detectar si has
perdido alguna interrupción por el camino solo tienes que unar una variable que las cuente cada vez que se produzcan y poner dicha variable a cero cuando sean convenientemente tratadas ....
Modo 5.-int1 ejecutar_menu=0;
int1 ejecutando_menu=0;
int n_interrupciones=0;
#int_EXT
EXT_isr()
{
++n_interrupciones;
output_high(PIN_B5); //Se activa el led
delay_ms(1000); //Hacemos una pausa de 1 segundo
output_low(PIN_B5); //Se desactiva el led
delay_ms(1000);
if(ejecutando_menu==0){
ejecutar_menu = 1;
}
}
main(){
While(true){
if(ejecutar_menu==1){
ejecutando_menu=1;
ejecutar_menu = 0;
if(n_interrupciones==1){
menu_para_una();
}
else{
menu_para_varias();
}
n_interrupciones=0;
ejecutando_menu=0;
}
}
}
Bueno, con esto cubres el
90% de casos que se te pueden presentar.
Te suelto todo este rollo porque he aprovechado que he completado mi proyecto
Analizador lógico de 3 Canales monitorizado en el PC en el que he estado tratando tres interrupciones externas hasta volverme loco ...
un saludo.