En una gran cantidad de problemas a resolver mediante un sistema embebido es necesario llevar a cabo un proceso estrictamente secuencial. En estos casos es muy útil y elegante estructurar nuestros programas como una máquina de estados. Quizá muchos de ustedes estén tentados a usar una estructura case para elegir un segmento de código cuando se cumple una condición. Si el numero de estados es pequeño, quizá se una opción fácil. Desafortunadamente el uso de case's es muy ineficiente cuando la máquina de estados y su tabla de transiciones es muy compleja. La implementación que se mostrará en esta entrada parecerá un tanto rebuscada pero tiene la ventaja de tener buen despeño a la hora de escalarla a numero grande de estados.
El diagrama de estados de la FSM de este ejemplo es el siguiente:
Diagrama hecho en LaTeX con TIKz |
Movámonos al programa. Primero, debemos definir un tipo enumerado para codificar nuestro conjunto de estados:
//-- Definición de tipo de estados
typedef enum {
Estado_0, // Estado inicial
Estado_1,
Estado_2,
Estado_3,
Estado_4,
No_de_Edos
} ESTADOS;
Creamos con esto una variable enumerada global que usaremos para almacenar el estado actual de la máquina:
//-- Variable global de estado
ESTADOS Estado_Actual = Estado_0;
El siguiente paso es definir una estructura que nos permitirá construir un objeto para nuestra FSM:
//-- Estructura de Maquina de Estados (FSM))
typedef struct {
ESTADOS Estado; // Estado miembro del conjunto enumerado ESTADOS
void (*func)(int); // Acciones asociadas al estado
} FSM;
Con lo anterior podemos ahora crear una instancia que sera nuestra FSM:
//-- Prototipos de funciones de estado
void Codigo_EDO_0(int);
void Codigo_EDO_1(int);
void Codigo_EDO_2(int);
void Codigo_EDO_3(int);
void Codigo_EDO_4(int);
//-- Creación de la estructura global de la FSM
FSM Maquina_de_Estados[] = {
{Estado_0,Codigo_EDO_0},
{Estado_1,Codigo_EDO_1},
{Estado_2,Codigo_EDO_2},
{Estado_3,Codigo_EDO_3},
{Estado_4,Codigo_EDO_4},
};
Es importante que los prototipos de las funciones asociadas a cada estado aparezcan antes de la creación de la estructura (estas funciones serán definidas más adelante en el código). El segmento de código principal queda reducido elegantemente de la siguiente manera:
void main(void) {
int sw = 0;
setup();
//-- FSM ---
while(1){
sw = PORTBbits.RB0;
(*Maquina_de_Estados[Estado_Actual].func)(sw);
}
return;
}
Código completo:
Circuito utilizado:
No hay comentarios:
Publicar un comentario