Alternativas de hilo para sistemas integrados

Aug 16 2020

Actualmente estoy estudiando ingeniería eléctrica. Debido a las pandemias, mis clases se suspendieron y estoy aprovechando este tiempo para aprender más sobre electrónica y programación.

Actualmente estoy tratando de usar una Pic16f628apantalla digital genérica y una para construir un reloj digital con algunas características. El caso es que tuve que acceder a un menú presionando un botón en tiempo de ejecución, mientras se muestra el reloj. Normalmente, llamaría a un hilo para la visualización del reloj y el hilo principal estaría atento a las entradas, pero debido a la simplicidad del controlador de imagen no puedo usar el recurso.

Entonces, mi código C (aún no implementado específicamente para la imagen) es algo como esto:

void display_timer(){
  static struct current_time timer;
  static int is_time_set = 0;
  set_current_time(&timer, &is_time_set);

  while (is_time_set){
    system("clear");
    printf("########\n");
    printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
    printf("########\n");
    sleep(1);
    update_timer(&timer, &is_time_set);
  }
}
int main ()
{
  while (1){
    display_menu();

  }
}

Durante el sueño (), el controlador debería poder estar atento a nuevas entradas y actuar en consecuencia.

Una alternativa que pensé fue usar una máquina de estado para almacenar la pulsación de un botón, dividiendo la función de suspensión en 4 u 8 intervalos, algo como esto:

  while (is_time_set){
    system("clear");
    printf("########\n");
    printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
    printf("########\n");
    for (int i = 0; i<8; i++){
    if (state_machine_input == 1){state_machine_input = 0; break;}
    sleep(1/8);
    }
    update_timer(&timer, &is_time_set);

Se podría hacer, pero agradecería que no tuviera que agregar más complejidad al proyecto, agregando otra máquina de estado, por ejemplo. ¿Qué puedo hacer en términos de software para implementar esta funcionalidad?

Respuestas

28 Lundin Aug 17 2020 at 07:04

Threading es un concepto de nivel superior al de la programación de microcontroladores. En pocas palabras, los subprocesos se implementan como un programador que usa interrupciones del temporizador, que a su vez guarda el contador del programa + el puntero de la pila, etc. y los establece en diferentes ubicaciones. Por lo tanto, es bastante posible y fácil implementar un concepto similar usando interrupciones, con la ventaja de que obtiene interrupciones especializadas en lugar de múltiples subprocesos genéricos.

Esa es la única forma sensata de hacerlo con un legado 8 amargo restringido como PIC, que es extremadamente limitado cuando se trata de uso de pila. Olvídese de usar librerías de hilos, incluso aquellas escritas para microcontroladores. Eso solo agregará un exceso de hinchazón y complejidad, por nada. En general, es una mala idea arrastrar los conceptos de programación de PC al mundo integrado.

Lo que debería hacer es colocar el escaneo de su botón dentro de una interrupción cíclica del temporizador que se ejecuta una vez cada 10 ms aproximadamente. Desde dentro de la interrupción, sondea los botones y compara el botón leído con el anterior una vez, con el fin de eliminar los rebotes. El resultado de esto se almacena en una variable compartida con el programa principal, declarado como volatiley protegido de las condiciones de carrera. Dado que solo escribe en la variable desde dentro de las interrupciones, puede ser suficiente protección para asegurarse de que las lecturas sean de 8 bits, pero debe desmontar para estar seguro. Más información sobre eso aquí: Uso de volatile en el desarrollo de C integrado .

15 Pelle Aug 17 2020 at 13:23

Usar interrupciones

¿Quieres ejecutar algún código al presionar un botón? Utilice una interrupción de cambio de pin

¿Quieres hacer algo en un intervalo fijo? Utilice una interrupción del temporizador

En cierto modo, el hardware del microcontrolador ejecuta un 'hilo' que monitorea las fuentes de interrupción y ejecuta una 'devolución de llamada' o una rutina de interrupción para cada evento.

El programa principal se pausa automáticamente mientras se ejecuta la interrupción.

Una forma común de compartir datos entre interrupciones y código principal es a través de volatilevariables globales y deshabilitar temporalmente las interrupciones cuando se leen datos de estos globales cuando son más que el tamaño de palabra del controlador (casi siempre en un controlador de 8 bits)

11 AndrewLentvorski Aug 16 2020 at 23:38

Probablemente sugeriría una biblioteca cooperativa multitarea. Uno que he usado en el pasado es Protothreads:http://www.dunkels.com/adam/pt/

Cualquier biblioteca cooperativa multitarea decente ayudará a abstraer la máquina de estado implícita necesaria para realizar un seguimiento de las cosas.

Buena suerte.

6 bracco23 Aug 17 2020 at 12:53

En general, existen diferentes enfoques con la multitarea cuando se trata de un sistema integrado:

  • Sondeo o Multitarea Cooperativa : Todo se hace en un bucle infinito y las tareas están diseñadas para tomar el mínimo tiempo posible y volver a la ejecución principal lo más rápido posible, para evitar retrasos. Tenga en cuenta que las tareas adecuadas para esta arquitectura pueden no ser lo que pensaría en términos de concepto de nivel superior, por ejemplo, en su aplicación, una tarea podría ser update_displayy otra tarea podría ser check_buttony crearía un bucle como:
    while(1){
         check_buttons();
         update_display();
         sleep(0.1); //seconds
     }
  • Interrupciones : todas las entradas posibles están conectadas a interrupciones de hardware y la ejecución principal se deja para cosas que no se pueden interrumpir (puede que no sea nada, en cuyo caso normalmente el microcontrolador se pone en modo de suspensión para reducir los consumos de energía. Detalles de cómo esto lo que se hace generalmente depende del microcontrolador y compilador particular que se utilice.

  • RTOS : dependiendo de la cantidad de energía que proporcione el microcontrolador, podría ser posible ejecutar un sistema operativo en tiempo real (RTOS), que podría proporcionar una API para crear tareas o incluso hilos. Esto depende de la aplicación y las capacidades del hardware, y para ejemplos educativos no debería ser necesario (o aconsejable, en mi opinión)

Tenga en cuenta también que otra parte importante a la hora de decidir la arquitectura general de la aplicación es la división de tareas y cómo cooperan. Uno de los paradigmas utilizados es State Machines (el enlace es a la página general de wikipedia que puede ser abrumadora, los recursos más simples específicos para la programación integrada se pueden encontrar en su libro de texto o en Google).

5 ExpinElectronics Aug 17 2020 at 06:15

En su mayoría, los dispositivos de 8 bits tienen una fuente limitada. Creo que una solución más simple es una mejor solución en PIC de 8 bits.

Puede crear temporizadores de hardware para 2 tareas diferentes. Establezca una bandera y verifique la bandera en su ciclo infinito, haga la tarea y reinicie la bandera. No utilice retrasos. Este método garantiza realizar sus tareas en su bucle infinito, si sus banderas están arriba.

Pero debes saber que las tareas no se ejecutan en el momento exacto en que se activan las banderas. Si había dos banderas configuradas al mismo tiempo, no puede saber cuál se ejecuta primero. Porque no sabes en qué parte del bucle infinito. Pero, en general, está bien para aplicaciones de interfaz que no son críticas en el tiempo.