Pregunta inicial
Tengo una pregunta general sobre el manejo de interrupciones en microcontroladores. Estoy usando el MSP430, pero creo que la pregunta puede extenderse a otras uC. Me gustaría saber si es o no una buena práctica habilitar / deshabilitar las interrupciones con frecuencia a lo largo del código. Quiero decir, si tengo una porción de código que no va a ser sensible a las interrupciones (o peor aún, no debe escuchar las interrupciones, por alguna razón), es mejor:
- Deshabilite las interrupciones antes y luego vuelva a habilitarlas después de la sección crítica.
- Ponga una bandera dentro del ISR respectivo y (en lugar de deshabilitar la interrupción), establezca la bandera en falso antes de la sección crítica y restableciéndola a verdadero, justo después. Para evitar que se ejecute el código del ISR.
- Ninguno de los dos, así que las sugerencias son bienvenidas.
Actualización: interrupciones y gráficos de estado
Proporcionaré una situación específica. Supongamos que queremos implementar un gráfico de estado, que está compuesto por 4 bloques:
- Transiciones / Efecto.
- Condiciones de salida.
- Actividad de entrada.
- Hacer actividad
Esto es lo que nos enseñó un profesor en la universidad. Probablemente, la mejor manera de hacerlo no es siguiendo este esquema:
while(true) {
/* Transitions/Effects */
//----------------------------------------------------------------------
next_state = current_state;
switch (current_state)
{
case STATE_A:
if(EVENT1) {next_state = STATE_C}
if(d == THRESHOLD) {next_state = STATE_D; a++}
break;
case STATE_B:
// transitions and effects
break;
(...)
}
/* Exit activity -> only performed if I leave the state for a new one */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(current_state)
{
case STATE_A:
// Exit activity of STATE_A
break;
case STATE_B:
// Exit activity of STATE_B
break;
(...)
}
}
/* Entry activity -> only performed the 1st time I enter a state */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(next_state)
{
case STATE_A:
// Entry activity of STATE_A
break;
case STATE_B:
// Entry activity of STATE_B
break;
(...)
}
}
current_state = next_state;
/* Do activity */
//----------------------------------------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
}
Supongamos también que, por ejemplo STATE_A
, quiero ser sensible a una interrupción proveniente de un conjunto de botones (con sistema de debouce, etc., etc.). Cuando alguien presiona uno de estos botones, se genera una interrupción y la bandera relacionada con el puerto de entrada se copia en una variable buttonPressed
. Si el rebote se establece en 200 ms de alguna manera (temporizador de vigilancia, temporizador, contador, ...), estamos seguros de que buttonPressed
no se puede actualizar con un nuevo valor antes de 200 ms. Esto es lo que te pregunto (y a mí :) por supuesto)
¿Necesito habilitar la interrupción en la actividad de OD STATE_A
y deshabilitar antes de irme?
/* Do activity */
//-------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
Enable_ButtonsInterrupt(); // and clear flags before it
// Do fancy stuff and ...
// ... wait until a button is pressed (e.g. LPM3 of the MSP430)
// Here I have my buttonPressed flag ready!
Disable_ButtonsInterrupt();
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
De manera que estoy seguro de que la próxima vez que ejecute el bloque 1 (transición / efectos) en la próxima iteración, estoy seguro de que las condiciones verificadas a lo largo de las transiciones no provienen de una interrupción posterior que ha sobrescrito el valor anterior de buttonPressed
ese I necesidad (aunque es imposible que esto suceda porque deben transcurrir 250 ms).