Buenas prácticas de bandera - energia msp430

Estoy haciendo un programa para el msp430 usando energia launchpad, el primer código que tuve es el siguiente:

// display flag
boolean flag_display = false;

void setup() {
  // define ISR to activate the display
  attachInterrupt(PUSH2, display_ISR, CHANGE);
}

void display_ISR() {
  clean_leds();
  flag_display = !flag_display;
}

void loop() {
  if(flag_display == true) {

    // prints the number 45 on the display
    pick_digit(1);
    pick_number(4);
    delay(8);
    pick_digit(2);
    pick_number(5);
    delay(8);

  }
}

Básicamente, el programa presenta el número 45 en la pantalla cada vez que se presiona el botón PUSH2 y limpia la pantalla cada vez que se deja de presionar el botón, el problema es que a veces (cuando no se presiona el botón y el programa todavía está en el primer retraso) el número 5 en el segundo dígito permanece presente, así que usé lo siguiente para evitar este problema:

// display flag
boolean flag_display = false;

// delay flag from the display
boolean flag_delay = true;

void setup() {
  // define ISR to activate the display
  attachInterrupt(PUSH2, display_ISR, CHANGE);
}

void display_ISR() {
  flag_display = !flag_display;
}

void loop() {
  if(flag_display == true) {

    // prints the number 45 on the display
    pick_digit(1);
    pick_number(4);
    delay(8);
    pick_digit(2);
    pick_number(5);
    delay(8);

    // if the code runs till the end, un-flag the delay flag
    flag_delay = false;

  }

  // Keeps cleaning the leds until the delayed code is over processing
  if(flag_display == false && flag_delay == false) {
    clean_leds();
    flag_delay = !flag_delay;
  }
}

Pero leí que el uso excesivo de banderas en su programa es una mala práctica de programación y mi solución no parece elegante ni eficiente, ya que la línea:

flag_delay = false;

Se seguirá procesando cada vez que se encienda la pantalla, y la función clean_leds() se seguirá procesando hasta que termine el código retrasado. ¿Hay una forma más eficiente de usar los ISR y las banderas en este caso particular? Gracias.

La función clean_leds() tiene lo siguiente:

void clean_leds()
{
  digitalWrite(P1_7, LOW);
  digitalWrite(P1_6, LOW);
  digitalWrite(P2_5, LOW);
  digitalWrite(P2_4, LOW);
  digitalWrite(P2_3, LOW);
  digitalWrite(P2_2, LOW);
  digitalWrite(P2_1, LOW);
}
¿Qué hace realmente clean_leds()? No puedo encontrar documentos al respecto.
Es una función, creada por mí, que simplemente limpia los LED de la pantalla.
No estoy seguro de lo que eso hace. Y puede importar. Creo que alternar una bandera en una rutina de interrupción que se llama en ambos bordes del botón pulsador puede estar bien. Pero si es así, no creo que el ciclo deba cambiarlo. A menudo, una rutina de interrupción establece un indicador que luego se borra mediante el código que lo maneja en loop() como parte de una declaración if. Pero es posible que no necesite eso en su caso. Supongo que también quería ver ese código antes de redactar alguna respuesta.
Cambió la pregunta para mostrar el código de la función clean_leds().

Respuestas (3)

Todavía no he trabajado con este procesador, pero estoy 100% seguro de que hay alguna forma de rastrear los estados de transición del botón pulsador

es decir, un_button_pressed(low) -> pressed_button (high) transición y viceversa

Si no desea utilizar la bandera, debe verificar la

pressed_button( high ) -> un_pressed_button( low ) transición en el pulsador

el código sudo sería como,

if(current_state_of_button == LOW && previous_state_of_button == HIGH)
{
    clean_leds();
}

tendrá que realizar un seguimiento de los estados con dos variables. O configure dos ISRS que se activen en las dos transiciones posibles. Espero que esto ayude

La variable flag_display ya realiza un seguimiento cuando se presiona/despresiona el botón. Lo que me molesta es que necesito una segunda bandera (flag_delay) para evitar que el código pick_digit(2) y pick_number(5) se procesen después de que no se presiona el botón (porque, en el primer ejemplo, si por casualidad des- presione el botón entre los 8 milisegundos de ese período de tiempo de retraso, eso es lo que sucede).
Oh, eso es simple, simplemente puede deshabilitar las interrupciones mientras realiza una sección crítica (sección que no desea que la interrumpa la acción de liberación del botón pulsador) Para deshabilitar las interrupciones: cli(); // deshabilitar las interrupciones globales y habilitarlas: sei(); // habilitar interrupciones
el flujo de su código es muy complicado aquí es un flujo propuesto, de nuevo, no creo que comprenda la gravedad de mantener dos variables (estado_actual_del_botón y estado_anterior) Es algo que se requiere si desea deshacerse de la bandera. El bucle () solo debe escanear el botón en busca de cambios, si el botón ISR1 presionado debe activarse, la rutina para ISR1 debe contener el código para pick_digit () y retrasar y este ISR no se puede interrumpir. Puede deshabilitar las interrupciones al ingresar al ISR. Una vez que está fuera del ISR, debe verificar si prev_state == presionado y current_state == no presionado
y limpiar_lcd()

Aquí hay un código psudo para lo que estoy tratando de explicar

bool prev_state
bool current state

setup{
//attach ISR 
}
ISR1.subroutine{
cli();   //disable interrupts
//Print your digits to LCD
sei();   //enable interrupts
}


loop{

 if(prev_state == HIGH && current_state == LOW)
 {
    //if this routine takes time also you might want to disable the interrupts here too
clead_leds();
 }

Hay una serie de problemas en su código original y creo que es un malentendido de los ISR.

Su código original se puede arreglar eliminando clean_leds() del ISR y moviéndolo a la rutina de bucle. No hay necesidad de flag_delay en absoluto.

if(flag_display == true) 
{
   // prints the number 45 on the display
   pick_digit(1);
   pick_number(4);
   delay(8);
   pick_digit(2);
   pick_number(5);
   delay(8);
}
else
{
   clean_leds();
}

La ISR (rutina de servicio de interrupción) interrumpirá literalmente cualquier código existente a menos que se hayan deshabilitado las interrupciones (como lo explica Dexobox).

Esto significa que clean_leds() puede ejecutarse después de que se muestre el número 4 pero antes del número 5, dejando solo '5' en la pantalla en lugar de '45'. Como regla general, si va a renderizar '45' en el bucle principal, también debería borrarlo en el bucle principal. Esto reduce la posibilidad de condiciones de carrera y comportamiento no deseado.

Alternativamente, puede limpiar_leds () y dibujar el '45' en el ISR, pero dado que el dibujo está usando retrasos y puede llevar algún tiempo, no lo recomendaría.

Estoy de acuerdo, pero en este caso, ¿la función clean_leds() no intentaría limpiar continuamente los LED incluso después de que las pantallas estuvieran apagadas? ¿Eso no consumiría más energía?
Todo depende de lo que realmente haga clean_leds(), pero si solo desea ejecutarlo una vez, quizás una mejor alternativa a las banderas booleanas sea una enumeración de máquina de estado o algo similar. De esta forma, puede pasar de tres estados: 1: Pantalla, 2: Limpio, 3: Nada. Después de llamar a su pantalla o limpiar la lógica, simplemente pasa al estado de nada, lo que podría poner su procesador en algún tipo de modo de suspensión de menor consumo o simplemente girar en el bucle principal.