Vous êtes sur la page 1sur 17

8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Inicio Cursos Electrónica y Programación Cursos Habilidades Blandas Tutoriales F.A.Q. Cont

Máquinas de estado
Máquinas de estado: blink.ino nos enseña la función de reposo (sleep)
Daremos una mirada al esquema blink.ino de Arduino como una máquina de estado explícita. Posteriormente
exploraremos las máquinas de estado donde se elaborará y pondrá en práctica un diagrama de reloj despertador.

Casi todos los esquemas de Arduino terminan usualmente con al menos una máquina de estado intencional y también
un montón de máquinas de estado no intencionales. Aquí, introduciremos el concepto de máquinas de estado y las
aplicaremos a una rutina blink “Hello World” en un microcontrolador. Luego de esto exploraremos algunas máquinas d
estado más complicadas, tales como un reloj despertador.

Que es una máquina de estado


Un ‘estado’ es la condición de una cosa en un tiempo determinado. Algunos que pueden realizar tareas y que utilizan
estados como su núcleo son máquinas de estado. También son conocidas como máquinas de estado nitas, lo que
signi ca que sabemos todos los posibles estados de ella. La clave para la máquina de estado es el concepto del tiempo
la historia. El estado de la máquina es evaluada periódicamente. Cada vez que es evaluada, un nuevo estado es elegido
(el que podría ser el mismo estado nuevamente) y el resultado es presentado.

Una máquina de estado genérica:

Un diagrama de una máquina de estado genérica. El elemento de memoria  contiene el nuevo estado conocido como e
estado variable. Cuando la máquina de estado cuenta con los servicios, el estado variable es actualizado con el valor d
la próxima etapa. Acá la nueva etapa es una función de ambos; el estado actual y algunos inputs. La nube de la lógica e
un sistema que decide cual será el próximo estado, o la próxima lógica de estado. 

Una máquina de estado simple: El contador.


Un clásico ejemplo de una máquina de estado es un contador. Por ejemplo, un ‘for loop’ o un circuito integrado lógico d
74×4040 trabajan como una máquina de estado. Cada vez que la máquina cambia de estado, ya sea por la línea del relo
o por el comportamiento de bucle, el estado de la memoria cambia a un nuevo estado igualando el estado anterior má
uno. El set nito de estados que puede tener es la cantidad de números que puede contar.

cursos.mcielectronics.cl/maquinas-de-estado/ 1/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Un contador básico expresado como máquina de estado

Partes de la máquina de estado del contador:

El estado actual es el valor que ha sido contado.


El resultado es el estado actual.
La próxima etapa lógica es lo que sea el estado actual + 1.
No hay entradas. En un diagrama más avanzado, una entrada o una función de reseteo del contador será
establecido como entrada.

La máquina de estado avanza a cualquier ritmo que sea atendida.

Máquinas de Estado Moore y Mealy


Los profesores de lógica digital aman preguntar en las pruebas sobre Moore vs. Mealy y es por eso que tenemos que
mencionarlo. La distinción entre ellas muchas veces no hace sentido, mientras escribas en una maquina de estado en C
es más como una: distinción de “como hacer un hardware lógico”. Para nosotros la lección de Moore y Mealy es que
existió gente que pensó sobre este tipo de cosas e inventó formas de notarlo. Mientras ellos se centraban en el
hardware lógico, nosotros nos centraremos en el software c.

Máquina de estado Moore


Edward Moore escribió un ensayo en 1956 (Gedanken-experiments on Sequential Machines) y por lo tanto el estilo de l
máquina lleva su nombre.  El dice que la salida depende solo del estado, y el próximo estado es dependiente del estado
actual (o salida), y la entrada.

Nuestro diagrama previo

Puedes notar que no importa cuál será el estado de la entrada, la salida solo depende el estado actual contenido dentr
del elemento de la memoria.

Máquina de estado Mealy


George Mealy escribió un ensayo un año antes que Moore, titulado “A Method for Synthesizing Sequential Circuits”,  en
el cual entra en profundidad acerca de crear máquinas de estado desde funciones matemáticas, y describe esas salidas
de máquinas de estado en términos de sus entradas.

Para diagramar la máquina Mealy, la salida está hecha para depender de ambos: el estado actual y la entrada. Aquí la
nube de la lógica de la próxima etapa contiene la lógica de salida también:

Una forma de dibujar la máquina Mealy

También puede ser dibujado separando la nube en la lógica del próximo estado o lógica de salida.

cursos.mcielectronics.cl/maquinas-de-estado/ 2/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Otra forma de dibujar una máquina Mealy

Diagramas de Estado Abstractos


Hasta ahora, hemos visto que las máquinas de estado tienen una memoria que almacena el estado actual, que debe
provenir de algún estado, y que irá al siguiente estado. Aunque nuestro diagrama actual no muestra como se mueve a
través de estados, el propósito debiese ser dibujar un mapa de movimiento entre los estados para que podamos escrib
un código que emule nuestro diseño. Esto se llama diagrama de estado.

Este es un ejemplo de cómo se pueden diagramar los estados de una máquina de estado, usando ideas de Moore y
Mealy.

Un diagrama de estado abstracto

Partes del diagrama:

El círculo es el estado
El nombre coloquial del estado esta dado en la mitad superior del circulo
La salida del estado está dada en la mitad inferior del círculo. A veces esto es explicito, como “X=1,” y el estado se
comporta como Moore, aunque a veces puede ser “SALIDA = ENTRADA” donde durante ese estado, hace la salida
igual a lo que haya sido la entrada. En este sentido, la máquina es muy Mealy. Normalmente se engloban los dos
para escribir máquinas de estado C porque realmente no importa la construcción C de la máquina.
La echa es el recorrido de la transición de estado.
Las Xs, arriba de la línea, son las condiciones para que esa transición de estado ocurra. Si se dan las condiciones,
ese será el recorrido de transición.
Las Ys, bajo la línea, son cosas que pasan durante la transición. Este concepto se desvía estrictamente del mundo
lógico digital de Moore y Mealy y se origina de la naturaleza de ejecución consecutiva de C. Mientras utilizamos un
programa, es fácil chequear las condiciones de transición y realizar algunas acciones de una sola vez mientras
cambian los estados, entonces se deben poner las acciones bajo las condiciones.

Siempre ten en mente que estas son representaciones abstractas de códigos y son una herramienta para crear niveles
más altos de operación. Agrega cuantos detalles necesites en el diagrama.

Considera un estado básico que se pueda mover hacia un nuevo estado.

cursos.mcielectronics.cl/maquinas-de-estado/ 3/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Estado simple con un set de transiciones de estado incompleto

¿Qué pasa si no se cumplen las condiciones de salida? El diagrama está incompleto y no se han  de nido todas las
posibles acciones del estado. Usualmente no sabríamos la solución completa del programa hasta que estén hechos los
diagramas, y los vayamos completando. Con este diagrama, podemos asumir que si las condiciones no son concretada
el estado volverá a sí mismo.

Estado especi cado completamente

Acá, se de nen todas las posibles transiciones de estado.

Diagrama de estado del contador


Revisa el comportamiento del contador como se dibuja con un diagrama de estado.

Diagrama de estado de un contador simple

Acá todos los estados posibles son representados con un círculo único. La acción del estado es agregar uno. Para
determinar el próximo estado, es fácil ver que sólo tenemos una opción, que es regresar al estado en que estábamos.

El Sketch de blink.ino
blink_fsm.ino
Salgamos del mundo teórico al re-escribir el familiar sketch de blink.ino con el comportamiento y sintaxis de una
máquina de estado, usando el caso de un interruptor. El ejemplo es iluminar el LED por 1 segundo, apagarlo 1 segundo
repetir el proceso. Acá hay dos estados, LED_ON y LED_OFF.

cursos.mcielectronics.cl/maquinas-de-estado/ 4/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Parpadeo básico de un LED

En cada estado, el valor del LED se muestra bajo la línea. Las fechas están cada una etiquetadas como VERDADERO
porque no importa qué, nos moveremos al próximo estado de todas maneras. Esta máquina de estado no tiene ningun
entrada. Cada segundo, evaluaremos la máquina de estado. Si el estado es 1, la salida es 1 y se mueve al estado 0. Aqu
está la implementación C.

Fuente archivo completo (github): blink_fsm.ino

Para realizar la máquina de estado en C, debes crear una variable que sostiene el valor actual del estado, de ne las
palabras para cada valor numérico en que puede estar el estado y escribe un estado del interruptor para evaluar el
próximo estado.

De nir los estados:

//Define the states of the machine


#define LED_OFF 0
#define LED_ON 1

Crear el estado variable (global):

uint8_t fsm_state = LED_OFF;

Hasta ahora, el estado puede tener 1 o 2 opciones, entonces se selecciona el tipo de datos de tamaño más pequeño

La máquina de estado es construida en loop():

void loop(){ //state machine

switch (fsm_state) {

case LED_OFF: //Statements to execute every time LED_OFF is reached

digitalWrite(13, LOW);

fsm_state = LED_ON;

cursos.mcielectronics.cl/maquinas-de-estado/ 5/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

break;

case LED_ON: //Statements to execute every time LED_ON is reached

digitalWrite(13, HIGH);

fsm_state = LED_OFF;

break;

default:

break;

delay(1000); // wait for a second

Cada vez que la función loop es ejecutada, se evalúa la máquina de estado. El estado variable (fsm_state) es global,
entonces retiene el estado.

En este caso se puede notar que en cada segundo esperamos 1 segundo y evaluamos la máquina de estado. El código
extra asociado al proceso de la máquina de esta causará que el ciclo de tiempo sea mucho mayor a un segundo y
correrá un poco lento. Esto podría ser interrumpido con el n de obtener mayor precisión.

blink_fsm_ms.ino
No quiero tener que esperar un segundo completo. Durante ese tiempo podría estar realizando otras cosas! Preferiría
que el proceso de la máquina de estado fuera a un intervalo más rápido. Como 1 microsegundo y se quede en un
mismo estado 1000 veces con el n  de crear retrasar.

cursos.mcielectronics.cl/maquinas-de-estado/ 6/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Un programa básico de cambio de estado que funciona más rápido de lo que fue programado

Con este diseño, no dejaré el estado a menos que el msCounts alcance 1000. El loop se retrasa por 1 microsegundo en
vez de 1000 microsegundos. Cuando la condición es verdadera para que una transición de estado ocurra, el estado del
LED es escrita y el contador se resetea.

Fuente de archivo completo (github): blink_fsm_ms.ino

Como antes, los mismos estados y la variable del estado es utilizada. La máquina de estado se expande para proveer
funcionalidad si y solo si la transición del estado va a ocurrir.

switch (fsm_state)

case LED_OFF:

//Statements to execute every time LED_OFF is reached

//Statements to execute when it's time to move to the next state

if(msCounts >= 1000) {

digitalWrite(13, HIGH); //Process the next state's function

fsm_state = LED_ON;

msCounts = 0;

cursos.mcielectronics.cl/maquinas-de-estado/ 7/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

break; case LED_ON: //Statements to execute every time LED_ON is reached

//Statements to execute when it's time to move to the next state

if(msCounts >= 1000) {

digitalWrite(13, LOW); //Process the next state's function

fsm_state = LED_OFF;

msCounts = 0; }

break; default:

break;

Ahora, cada estado solo se mueve si la transición lógica de estado es verdadero usando un enunciado “IF”. Aquí es
donde es obvio cuán fácil es agregar tareas de 1 tiempo a la acción de estados de transición. Ellos son solo agregados a
enunciado “IF”, y serán ejecutados solo cuando el estado se mueve.

La máquina de estado funciona pero no como quisiéramos. Noten que el estado LED está en LOW durante el estado
LED_ON y HIGH durante el estado LED_OFF. Es fácil ejecutar el código de una sola vez dejando un estado, pero no
durante la entrada del estado.  Es contablemente intuitivo y puede ser realizado claramente al agregar dos estados má
cada uno sólo espera.

blink_fsm_ nal

cursos.mcielectronics.cl/maquinas-de-estado/ 8/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Un programa de cambio de estado que utilice un estado adicional de espera.

Acá los estados LED_ON y LED_OFF escriben al LED, limpian el contador y continúan adelante.

Nota lateral de sincronización y exactitud: El contador ha sido modi cado a una cuenta de 999 para tener en cuenta el
estado extra, pero no ayuda mucho. Llegamos más lejos mientas más rápido hacemos correr el reloj. Esto es debido a
que el tiempo que toma evaluar la máquina de estado está comenzando a alcanzar el total de tiempo para ejecutar el
loop() INCLUYENDO el retraso(1); enunciado.

Fuente de archivo completo (github): blink_fsm_ nal.ino

Primero, los dos estados extra son agregados a la lista de #de nes.

blink_fsm_ nal

//Define the states of the machine

#define LED_OFF 0

#define LED_ON_WAIT 1

#define LED_ON 2

#define LED_OFF_WAIT 3

El estado variable es el mismo entonces nos moveremos a la implementación de la máquina de


estado actual.

//state machine

switch (fsm_state){
cursos.mcielectronics.cl/maquinas-de-estado/ 9/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

case LED_OFF: //Statements to execute every time LED_OFF is reached

digitalWrite(13, LOW);

fsm_state = LED_ON_WAIT;

break;

case LED_ON_WAIT: //Statements to execute every time LED_OFF_WAIT is reached

if(msCounts >= 1000) {

fsm_state = LED_ON;

msCounts = 0;

break;

case LED_ON: //Statements to execute every time LED_ON is reached

digitalWrite(13, HIGH);

fsm_state = LED_OFF_WAIT;

break;

case LED_OFF_WAIT: //Statements to execute every time LED_ON_WAIT is reached

cursos.mcielectronics.cl/maquinas-de-estado/ 10/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

if(msCounts >= 1000) {

fsm_state = LED_OFF;

msCounts = 0;

break;

default:

break;

Vemos que los estados extra se han convertido en casos extras en la sentencia Switch. Los estados que siempre se
mueven hacia delante de forma simple asignan el próximo estado al estado variable. El estado de retraso chequea las
cuentas antes de asignar un nuevo estado, además retiene el estado en el que estaban.

Más notas sobre sincronización: Ejecutar el incrementador msCounts con una Rutina de Servicio de Interruptor de 1
microsegundo (ISR). Mientras tanto utilizar el loop en el FSM tan rápido como sea posible. Esto corregirá la
sincronización. Debemos tener en cuenta que si el tiempo de ejecución del código entre las llamadas ISER (el tiempo de
proceso de la máquina de estado) es más largo que el intervalo de la llamada ISER, el programa probablemente se
bloqueará

Si ¿Y qué? ¡El LED estaba parpadeando para empezar!


Por favor considera las funciones de alarma de un reloj despertador. ¿Cómo se vería su modelo de comportamiento? E
reloj despertador tiene varios estados que pueden existir dentro y tiene un par de entradas que pueden ser utilizadas
para controlarlo.

Estados:

Mantener el tiempo agradablemente


Ejecución de alarma
Espera con impaciencia el nal del ciclo de repetición de alarma por lo que puede que la alarma se active
nuevamente

Entradas

Interruptor de brazo (Arm switch)

cursos.mcielectronics.cl/maquinas-de-estado/ 11/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Botón de reposo (sleep)

Hay algunas más, como entradas para establecer hora y establecer alarma, pero este ejemplo está limitado a las
operaciones de alarma solamente.

Descrito como máquina de estado:

Las funciones de alarma del reloj despertador.

Si intentamos caminar mentalmente a través de la operación de la máquina de estado veremos que podemos obtener
del ‘idle’ al sonar si el reloj despertador no está armado. También podemos volver a ‘idle’ al presionar el botón de repos
(sleep). Tenemos que desarmar la alarma, esto cumple nuestra de nición interna de cómo actúa un reloj despertador,
entonces proseguimos.

No existe una manera en que realmente demos seguimiento al tiempo, incluso si solo fuera para el experimento. En ve
de darle seguimiento a los días, horas, etc., solo queremos darle seguimiento a los segundos. Entonces necesitaremos
contar los segundos. La máquina de estado de parpadeo de LED ya hace eso! Solo lo cambiaremos para mantener el
seguimiento y agregar a toda la máquina de estado dentro.

Re-usando la máquina de estado de parpadeo para contar segundos.

Como un bene cio, se puede bloquear el parpadeo del LED a menos que la alarma se apague y usar eso como resultad
de depuración.

Acá esta el archivo fuente completo (github): alarm_clock.ino

cursos.mcielectronics.cl/maquinas-de-estado/ 12/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

Conexiones de Hardware:

Conecta un botón de apertura normal entre el pin 7 y el GND de un Arduino. Esto servirá como “REPOSO” (sleep).
Conecta el switch SPST entre el pin 9 y la tierra. Esto servirá como “ARM” (brazo).

El código es muy similar a los ejemplos previos, pero tiene dos máquinas de estado construidas sobre él.

Primero, los estados y las variables de la máquina de estado del temporizador:

//Timer FSM numbers

uint16_t msCounts = 0;

uint16_t sCounts = 0;

#define LED_OFF 0

#define LED_ON_WAIT 1

#define LED_ON 2

#define LED_OFF_WAIT 3

uint8_t timer_fsm_state = LED_OFF;

Luego, los estados y las variables de la máquina de estado de alarma. La hora de la alarma se establece en 15 segundos
del reinicio (de hecho cerca de 20 con error), y el ciclo de reposo se establece por 5 segundos.

//Alarm FSM numbers

#define ALARM_SECONDS 15

#define SNOOZE_SECONDS 5

uint8_t alarmActive = 0;

cursos.mcielectronics.cl/maquinas-de-estado/ 13/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

uint16_t nextAlarmTime = 65535;

#define ALARM_IDLE 0

#define ALARM_RINGING 1

#define ALARM_SNOOZING 2

uint8_t alarm_fsm_state = ALARM_IDLE;

Loop() evalúa ambas máquinas de estado cada vez que funciona.

//timer state machine

switch (timer_fsm_state)

case LED_OFF:    //Statements to execute every time LED_OFF is reached

digitalWrite(13, LOW);

timer_fsm_state = LED_ON_WAIT;

break;

case LED_ON_WAIT:    //Statements to execute every time LED_OFF_WAIT is reached

if(msCounts >= 1000)    {

timer_fsm_state = LED_ON;

msCounts = 0;    }

break;

case LED_ON:    //Statements to execute every time LED_ON is reached

if(alarmActive == 1)    {

digitalWrite(13, HIGH);

timer_fsm_state = LED_OFF_WAIT;

break;

cursos.mcielectronics.cl/maquinas-de-estado/ 14/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

case LED_OFF_WAIT:    //Statements to execute every time LED_ON_WAIT is reached

if(msCounts >= 1000)    {

timer_fsm_state = LED_OFF;

msCounts = 0;

if( sCounts < 0xFFFF )      {

sCounts++;

break;

default:

break;

uint8_t buttonValue = digitalRead(7);

uint8_t switchValue = digitalRead(9); //alarm state machine

switch (alarm_fsm_state){

case ALARM_IDLE:

if((sCounts >= nextAlarmTime)&&(switchValue == 0))    {      //Goto next state

alarm_fsm_state = ALARM_RINGING;

alarmActive = 1;    }

break;

case ALARM_RINGING:

if(buttonValue == 0)    {

nextAlarmTime = sCounts + SNOOZE_SECONDS;

alarm_fsm_state = ALARM_SNOOZING;

alarmActive = 0;    }

if(digitalRead(9) == 1)//If switch went o , goto idle instead

alarm_fsm_state = ALARM_IDLE;  // this overwrites the snooze button option

cursos.mcielectronics.cl/maquinas-de-estado/ 15/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's

alarmActive = 0;    }

break;

case ALARM_SNOOZING:

if(sCounts >= nextAlarmTime)    {      //Goto next state

alarm_fsm_state = ALARM_RINGING;

alarmActive = 1;    }

if(switchValue == 0)    {      //Goto alarm idle

alarm_fsm_state = ALARM_IDLE;    }

break;

default:

break;

Para operar, cierra el  switch “ARM” (brazo) y carga el programa.

Conclusión
En nuestra experiencia, cualquier programador creador de códigos que puede diagramar un programa antes de
escribirlo tendrá éxito con el programa. Se han escrito muchos programas que han terminado como un montón de
“enunciados if” anidados porque no nos adelantamos a los hechos. Inevitablemente, se necesita agregar una cosa
pequeña que corrompe enormemente el programa y somos forzados a re-evaluar las decisiones. El usar herramientas
tales como diagramas de máquinas de estado, diagramas de ujo, diagramas de clase y tests de unidad que nos
permiten escribir códigos más complejos pero mantenibles (mientras permanece relativamente cuerdo). La máquina de
estado es solo otra idea para tener en la caja de herramientas y esperamos que les ayude en el futuro.

← Configuración Raspbian (y el juego ¡¡DOOM!!) Como utilizar Cron Job →

MCI Capacitación – MCI Electronics Links Rápidos Visita nuestros sitios

cursos.mcielectronics.cl/maquinas-de-estado/ 16/17
8/5/2019 Máquinas de estado - MCI Capacitación - Cursos de Arduino, Raspberry, Domótica y diseño de PCB's
Viana 405, Local 7, Viña del Mar Cursos arduino.cl
Tel:+ 56 32 2710559 Tutoriales ibutton.cl
Luis Thayer Ojeda 0115 of 1105, Santiago F.A.Q xbee.cl
Tel:+ 56 22 3339579 Contacto mcielectronics.cl
Tienda mcitelecom.com

cursos.mcielectronics.cl/maquinas-de-estado/ 17/17

Vous aimerez peut-être aussi