operating-system - moore - maquinas de estado verilog
Diseño de programa de máquina de estado en FreeRTOS-vTaskStartScheduler en una declaración de cambio (2)
Tengo una pregunta de diseño de programa en FreeRTOS:
Tengo una máquina de estado con 4 estados y 6 tareas. En cada estado, se deben ejecutar diferentes tareas, excepto Task1, que siempre está activo:
Estado 1: Tarea1, Tarea2, Tarea3
Estado 2: Tarea1, Tarea2, Tarea3, Tarea4
Estado 3: Tarea1, Tarea5
Estado 4: Tarea1, Tarea6
Tarea1, Tarea3, Tarea4, Tarea5 y Tarea6 son periódicos, y cada uno lee un sensor diferente.
Task2 es aperiódico, envía una alarma GPRS solo si se alcanza un umbral.
La conmutación entre los estados está determinada por eventos de la entrada del sensor de cada tarea.
El enfoque inicial para el diseño de main () es tener un interruptor para controlar los estados, y dependiendo del estado, suspender y activar las tareas correspondientes:
void main ()
{
/* initialisation of hw and variables*/
system_init();
/* creates FreeRTOS tasks and suspends all tasks except Task1*/
task_create();
/* Start the scheduler so FreeRTOS runs the tasks */
vTaskStartScheduler();
while(true)
{
switch STATE:
case 1:
suspend(Task4, Task5, Task6);
activate(Task2, Task3);
break;
case 2:
suspend(Task5, Task6);
activate(Task2, Task3, Task4);
break;
case 3:
suspend(Task2, Task3, Task4, Task6);
activate(Task5);
break;
case 4:
suspend(Task2, Task3, Task4, Task5);
activate(Task6);
break;
}
}
Mi pregunta es: ¿a dónde debo llamar vTaskStartScheduler (), en relación con el cambio? Me parece que en este código, una vez que se llama al vTaskStartScheduler, el programa nunca ingresará la instrucción switch.
¿Debería crear otra tarea siempre activa para controlar la máquina de estado, que tiene el tiempo anterior y cambiar las instrucciones dentro, como el siguiente pseudocódigo?
task_control()
{
while(true)
{
switch STATE:
case 1:
suspend(Task4, Task5, Task6);
execute(Task2, Task3);
and so on...
}
}
Cualquier consejo será muy apreciado ...
Como mencionó Ed King, su solución contiene un defecto de diseño importante. Es decir, después de iniciar el planificador, ningún código que se especifique después de él en la función principal se ejecutará hasta que se detenga el planificador.
Sugiero implementar su lógica de estado en la tarea Inactivo (recuerde incluir retrasos en sus tareas para no privar al gancho Inactivo del tiempo de procesamiento). La tarea inactiva podría bloquear y desbloquear las tareas según el estado actual mediante menas de semáforos. Sin embargo, recuerde que el gancho Idle es una tarea con la prioridad más baja posible, así que tenga cuidado al diseñar su sistema. La solución que sugiero puede ser completamente incorrecta cuando las tareas consumen la mayor parte del tiempo de procesamiento y no permiten que la tarea inactiva cambie de estado.
Alternativamente, puede crear una tarea superior como la mencionó Ed King, con la más alta prioridad.
Para ser sincero, todo depende de lo que la tarea realmente esté haciendo.
Para responder a su pregunta, vTaskStartScheduler()
, como su nombre indica, iniciará el programador. Cualquier código posterior solo se ejecutará cuando se detenga el planificador, que en la mayoría de los casos es cuando finaliza el programa, por lo que nunca. Es por eso que su switch
no se ejecutará.
Como ya has eludido, para tu diseño podrías usar una tarea "principal" para controlar a los demás. vTaskStartScheduler()
haberlo creado y haberlo registrado en el programador antes de llamar a vTaskStartScheduler()
.
En una nota lateral, si sigues este enfoque, solo deseas suspender / reanudar tus tareas en la primera entrada en un estado, no en cada iteración de la tarea "principal".
Por ejemplo:
static bool s_first_state_entry = true;
task_control()
{
while (true)
{
switch (STATE)
{
case 1:
if (s_first_state_entry)
{
// Only do this stuff once
s_first_state_entry = false;
suspend(Task4, Task5, Task6);
execute(Task2, Task3);
}
// Do this stuff on every iteration
// ...
break;
default:
break;
}
}
}
void set_state(int state)
{
STATE = state;
s_first_state_entry = true;
}