Go Down

Topic: Qué es y cómo funciona una máquina de estados (Read 737 times) previous topic - next topic

cgriell

Buenos días a todos. Llevo siguiendo a veces este foro, y me encanta su espontaneidad. Y por otra parte, a veces sale algun forero que se lía programando una máquina CNC y por sus preguntas, se ve claramente que no sabría lograr hacer el programa para mandar un led con un pulsador.

Debo decir que aquí no vais a encontrar código de Arduino, si no ideas y conceptos. Porque no nos hagamos ilusiones, hay que entender los conceptos básicos para que un tutorial sirva para algo. Si no, el tutorial es un corta y pega, que tal vez logre que el sistema funcione, pero no habrá servido para aprender.

Hecha esta introducción, os explico lo que es una máquina de estados, que es algo que aparece regularmente en los foros y me parece que algunos no entienden de que va la historia.

Una máquina de estados es un sistema secuencial cerrado. Dicho de otra manera, es un sistema en el cual se realizan acciones, una despues de otra, y el sistema está siempre en una situación que pertenece al sistema.

Pero la idea que tengo es que hay que "bajar a terreno", vamos a definir una máquina de estados muy simple, un toldo, de pocas variables, y vamos a trabajar sobre ella. Una vez entendido qué son los estados del toldo, y que variables de contexto afectan al toldo, se comprenderá mejor la teoría de lo que es una máquina de estados.

Asi que vamos a ello.

Un toldo puede
- estar arriba del todo
- estar abajo del todo
- estar en movimiento hacia arriba
- estar en movimiento hacia abajo
- estar detenido en medio

Por lo tanto, el sistema "toldo" tiene, en este caso, 5 estados, tantas como "cosas distintas" puede estar esperando. El concepto de "estar esperando" es importante, los estados son estables en tanto no actúa sobre ellos una variable a la que son sensibles, por ejemplo, si el toldo esta arriba, no es sensible a la orden de subir, se la de quien se la de.

Una vez definidos los estados, vamos a definir las variables llamadas "variables de contexto", y son aquellos valores que afectan a cualquiera de los estados del toldo.

Existen variables de contexto físicas (es decir, un pulsador), y variables de contexto "lógicas", construidas a partir de elementos de software (una variable de contexto lógica sería un flag en programacion convencional, pero no os quiero complicar la vida con algo que es tabú)

En el caso de nuestro toldo, las variables son

- un pulsador que envía el toldo abajo (una pulsación es suficiente, no hay que mantener pulsado)
- un pulsador que envía el toldo arriba
- un pulsador que
a.) con una pulsacion breve
 i.) detiene el movimiento cuando el toldo está en marcha
 ii.) envia el toldo a una posicion predeterminada cuando el toldo esta detenido
b.) con una pulsacion larga
 iii.) programa la posicion predeterminada, alli donde este el toldo en ese momento
- un sensor de vibraciones que envia el toldo arriba (para cuando el viento mueve el toldo)
- una variable interna, compuesta de un contador, que permite determinar la posicion del toldo


Y no existen mas variables... podríamos ir complicando el sistema, añadiendo un sensor que determinase automaticamente, en funcion de la luz y la hora, en cual de las tres posiciones debe estar el toldo, o unos sensores de final de carrera que detuviesen el motor "si o si" al llegar al limite (para evitar fundir el motor), pero creo que con los tres pulsadores anteriores hay suficiente.

Y finalmente estan las acciones, que en nuestro caso son muy sencillas
MONB Motor ON en bajada
MONS Motor ON en subida
MOFF  Motor OFF

Para simplificar, voy a establecer una nomenclatura

Para los estados:

E0 es estado 0, toldo arriba
E1 es estado 1, toldo bajando
E2 es estado 2, toldo abajo
E3 es estado 3, toldo subiendo
E4 es estado 4, toldo detenido


Para las variables de contexto

PS es Pulsador subida
PB es Pulsador bajada
PCC es Pulsador central, pulsacion corta
PCL es Pulsador central, pulsación larga
SV es el Sensor de Vibraciones
POS es un contador que se incrementa cada 500 bucles de programa, por ejemplo
MEM es la posicion de memoria del toldo

Como podeis apreciar, he transformado una entrada física (el pulsador central) en dos entradas lógicas, PCC y PCL y he creado dos variables logicas nuevas POS y MEM que no corresponden a entradas fisicas.

nota: Podría haber hecho que POS se incrementase a cada interrupción de un reloj externo, o a cada vuelta del motor - lo cual seria mas correcto desde el punto de vista técnico - pero asi se puede ver que el sistema crea sus propias variables cuando las necesita.

Me seguís hasta aqui?

Y ahora, modelo mi sistema sobre el papel

Cuando el toldo esta arriba, es sensible a PB, PCC y PCL, es decir al pulsador de bajada y al central, pero no al PS (Pulsador de subida) ni al SV (sensor de vibraciones) ni a POS ni a MEM (es decir, al sistema no le afecta "no es sensible a" ninguna de estas entradas)

Escrito podría quedar asi
E0 (PB) [MONB] -> E1
E0 (PCC) [MONB] -> E1
E0 [PCL] [MEM <- POS]-> E0

Es decir, el "toldo arriba" pasa a "toldo bajando" cuando se actúa sobre el pulsador de bajada y el pulsador central en pulsacion corta, ambos poniendo en marcha el motor en bajada, y se queda en el mismo estado cuando se pulsa el central en pulsacion larga, copiando la posicion a la memoria y por lo tanto, borrando la posicion almacenada anteriormente.

Ahora bien, no solo cambia de estado, si no que el sistema "hace algo" en la "transición" de cambio de estado

En resumen, tenemos
Estados (mientras el sistema esta en un estado, no hace ninguna accion)
Variables de contexto (provocan los cambios de estado)
Transiciones (momento en el cual se ordenan las acciones)

Y yo lo dejo aqui por el momento, si hay interés entre los lectores, lo continuo otro día

Mientras podeis ir pensado que variables actuan sobre el toldo bajando...


 

cgriell

Parte 2

Sobre el toldo bajando actúan tres variables

- el sensor de vibracion. No vamos a bajar el toldo si hay un vendaval, verdad? Cuando actúa, detiene el motor
- la variable de preposicionamiento memorizado Cuando actúa, detiene el motor
- el pulsador central en pulsacion corta Cuando actúa, detiene el motor
- la variable de preposicionamiento en final de carrera. Cuando actúa, detiene el motor

Vemos que la acción es siempre la misma, por lo tanto, existe una subrutina asociada a la accion. En este caso es simplemente la orden de detener el motor, pero si lo ponemos en forma de subrutina podremos añadir funciones adicionales (por ejemplo, un led que indique el funcionamiento del motor, y que se apaga siempre que se detiene el motor, y asi lo tenemos siempre reunidos, y no quedan bucles sueltos..)

Introduzco pues, tras los estados y las variables de contexto las acciones
Las acciones son las actuaciones del sistema, lo que espera que haga
Si las variables de contexto son los inputs, las acciones son los outputs.

En el caso del toldo las acciones (ver el post anterior) son
MOFF: Detener el motor
MONS: Poner en marcha el motor en Subida
MONB: Poner en marcha el motor en Bajada
En este caso implica que el sistema actúa directamente sobre los reles del motor

Este conjunto, formado por Estados, Variables de contexto y Acciones es un Autómata de Estados. Informáticamente existen muchas representaciones del mismo, la más cómoda, en todo caso para mí, es una matriz, en la que se indica, por cada estado (línea), y para cada variable de contexto (columna), la dupla [Accion, estado de llegada]

Quedando asi, para la bajada del toldo

E0,  /* estado 0, toldo arriba */

(PB) /* Primera variable Pulsador bajada */
[MONB], E1 /* dupla accion, Estado de llegada */

(PCC) /* Segunda variable, pulsador preposicionamiento */
[MONB], E1 /* dupla accion, Estado de llegada */

(PCL) /* Tercera variable, pulsador memorizacion posicion */
[MEMO], E0 /* dupla accion, Estado de llegada */

(FF) /* Indicador de final de variables de contexto que afectan a este estado */

E1, /* estado 1, toldo bajando */
(SV) /* primera variable estado 1, sensor de vibraciones */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio */

(VPREPOS) /* segunda variable estado 1, llegado a preposicionamiento? */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio) */

(PCC) /* tercera variable estado 1, pulsacion detencion */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio) */

(VFINCARR) /* cuarta variable estado 1, final de carrera */
[MOFF], E3 /* dupla accion, Estado de llegada (toldo detenido abajo */

(FF) /* Indicador de final de variables de contexto que afectan a este estado */

(observareis que no se miran las variables que no afectan a este estado, por ejemplo la de memorizacion de posicion

Pero... en la descripción de las acciones se aprecia un posible conflicto... si el toldo esta bajando, se detiene al llegar al punto de preposicionamiento motorizado, y obligaría a volver a pulsar bajada del toldo

La decisión de si debe detenerse al llegar al preposicionamiento o no depende de si toldo bajando es una orden que ha dado el pulsador de bajada (y entonces no se detiene) o una pulsacion breve del pulsador de ir a predeterminada.

En programacion convencional se pone un "flag" que indica si la orden de bajada la ha dado el pulsador de bajada o el de predeterminada. Los flags son fuente de conflictos, al setearse en un lugar y resetearse en varios... siempre queda alguno suelto. (si, ya se que hay informaticos que solo juran por ellos, y dicen que las cosas no se pueden hacer de otra manera, y que siempre ha sido asi.. pues bueno)

En una máquina de estados simplemente se crean dos transiciones, una disparada por el pulsador de bajada, que no es sensible a la posicion predeterminada, y otra que si que lo es. Y como veremos en el proximo post, la implementación informática de esto es trivial, es una linea más en el automata de estados

hasta la proxima

cgriell

Parte 3

Como os decía, si no queremos que al dar la orden de toldo abajo se detenga al llegar a la posicion de preposición, cambiamos el automata de estados, creando dos transiciones identicas (las que ponen el motor en bajada), que llevan a estados distintos de toldo en bajada, uno en el que se espera solo la señal de final de carrera (y el sensor sismico) y otro en que se espera las mismas, mas la señal de preposicionamiento.

Estado 0, toldo arriba (seria conveniente detectar que esta el final de carrera arriba, y si no, subirlo hasta que lo estuviese, pero por el momento lo obviamos)

Estado 1, toldo en bajada hasta el final de carrera (o pulsador de detencion, o sensor de vibraciones)

Estado 2, toldo detenido entre los dos finales de carrera

Estado 3, toldo en final de carrera inferior

Estado 4, toldo en bajada hasta preposicionamiento, final de carrera, pulsador de detencion o sensor

Estado 5, toldo subiendo hasta final de carrera

Estado 6, toldo subiendo hasta preposicionamiento


El automata  quedaría asi

E0,  /* estado 0, toldo arriba */

(PB) /* Primera variable Pulsador bajada */
[MONB], E1 /* dupla accion, Estado de llegada */

(PCC) /* Segunda variable, pulsador preposicionamiento */
[MONB], E4 /* dupla accion, Estado de llegada distinto al anterior, sera estado en bajada esperando prepos */

(PCL) /* Tercera variable, pulsador memorizacion posicion */
[MEMO], E0 /* dupla accion, Estado de llegada */

(FF) /* Indicador de final de variables de contexto que afectan a este estado */

E1, /* estado 1, toldo bajando hasta el final de carrera en bajada */
(SV) /* primera variable estado 1, sensor de vibraciones */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio */

(VPREPOS) /* segunda variable estado 1, llegado a preposicionamiento? */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio) */


(PCC) /* tercera variable estado 1, pulsacion detencion */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio) */

(VFINCARR) /* cuarta variable estado 1, final de carrera */
[MOFF], E3 /* dupla accion, Estado de llegada (toldo detenido abajo */

(FF) /* Indicador de final de variables de contexto que afectan a este estado */

E2, /* estado 2, toldo detenido entre dos finales de carrera[/b] */
sensible a las variables
1.) PCL que resetea la posicion memorizada y lo deja en el mismo estado
2.) SV que da la orden de subir el toldo y lo pone en estado 5 (motor en subida hasta final de carrera)
3.) PS que pone el motor en marcha en subida y lo pone en estado 5, motor en subida
4.) PB que pone el motor en marcha en bajada y lo pone en estado 1, toldo bajando hasta fin de carrera
5.) PCC, que debe determinar si el toldo esta encima o debajo del preposicionamiento, para determinar si debe poner en marcha el motor hacia arriba o hacia abajo

E3, /* estado 3, toldo detenido en punto inferior */
sensible a las variables
1.) PCL que resetea la posicion memorizada y lo deja en el mismo estado
2.) SV que da la orden de subir el toldo y lo pone en estado 5 (motor en subida hasta final de carrera)
3.) PS que pone el motor en marcha en subida y lo pone en estado 5, motor en subida hasta final carrera
4.) PCC que pone el motor en marcha en subida y lo pone en estado 6 (motor en subida hasta prepos)

E4, /* estado 4, toldo bajando hasta encontrar preposicionamiento o final de carrera */
(SV) /* primera variable estado 1, sensor de vibraciones */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio */

(VPREPOS) /* segunda variable estado 1, llegado a preposicionamiento? */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio) */[/s]

(PCC) /* tercera variable estado 1, pulsacion detencion */
[MOFF], E2 /* dupla accion, Estado de llegada (toldo detenido punto intermedio) */

(VFINCARR) /* cuarta variable estado 1, final de carrera */
[MOFF], E3 /* dupla accion, Estado de llegada (toldo detenido abajo */

(FF) /* Indicador de final de variables de contexto que afectan a este estado */

Parte añadida para crear una segunda transicion sensible al preposicionamiento


E5, /* estado 5, toldo subiendo hasta final de carrera[/b] */
sensible a las variables
1.) Final de carrera superior, detiene el motor y deja el automata en estado 0
2.) Pulsador detencion, detiene el motor y deja el automata en estado 2

E6, /* estado 6, toldo subiendo hasta preposicionamiento */
sensible a las variables
1.) Llegada a preposicionamiento, detiene el motor y lo deja en estado 2
2.) Final de carrera superior, detiene el motor y deja el automata en estado 0
3.) Pulsador detencion, detiene el motor y deja el automata en estado 2



Estando esto definido, en el proximo y probablemente ultimo post sobre el tema desarrollaré una posible implementación informática, no en arduino, sino en un metalenguage (aproximado) de programacion


Hector_A


Hector_A


cgriell

Parte 4

En resumen, tenemos un automata de estados que es sensible a unas variables, unas externas, y otras internas. Los estados son sensibles a algunas de las variables que influyen en el sistema, y la activacion de una variable a la que es sensible lleva el autómata de un estado a otro, realizando las acciones asociadas. Y si cambia una variable a la cual el automata no es sensible, sencillamente, la ignora.

Las variables pueden ser estados (es decir, un interruptor que estará en on o en off) o o bien ser flancos (es decir, cambios en la señal)

Voy a usar una especie de lenguaje de programación que trata de ser una mezcla entre un lenguaje de programación verdadero (en el que la existencia o no de una coma, o de un separador hace que el sistema actue distinto) y un lenguaje mas natural

Como estructuras de este pseudo lenguaje voy a usar, ademas de los valores TRUE y FALSE que se llaman booleanos

Vectores que son conjuntos ordenados de variables en los que cada variable se distingue por su indice. Asi, si escribo Vector (5), quiero decir que me refiero a la sexta variable del vector (la primera es el 0)

Matrices que son conjuntos ordenados de vectores, en los que cada variable se distingue por dos indices, el indice del vector, y el indice de la variable dentro del vector, asi, si el vector del ejemplo anterior era el 3, la variable anterior se identifica por Matriz (3,5)

Sentencias simples:
   Matriz (3,5) <- TRUE

Bloques de sentencias simples:
   son un conjunto de sentencias que se realizan agrupadas (es decir, que se ejecutan juntas secuencialmente)

Estructuras condicionales
  IF (Boleano) THEN (bloque) ELSEIF (bloque) ENDIF
 
DOWHILE (Boleano) (bloque) ENDDOWHILE


Estructuras de ruptura de secuencia
  DO (CASEOF Variable)
     0: (Bloque) ENDCASE
     1: (Bloque) ENDCASE
     2: (Bloque) ENDCASE
   ENDDO

Con estos mimbres vamos a hacer el cesto.

Esencialmente el programa realizará lo siguiente:

A.) Inicialización de estado. El sistema debe partir de un estado conocido, es decir, primero, ponemos el toldo en su lugar, motor en marcha subiendo, y si hay un final de carrera fisico, hasta el final de carrera, si no lo hay, durante el tiempo máximo que puede tardar en subir el toldo (ojo, que se puede quemar el motor, pero eso es otra historia)

DOWHILE TRUE

B.) Bucle de exploracion y seteado de TODAS las variables de contexto

C.) Busqueda en el Automata de estados para comprobar si el estado es sensible a una de las variables de contexto seteadas.

IF sensible THEN

D.) si es sensible ejecuta las acciones asociadas

Accion <- numero de acción en el autómata
Estado <- numero de estado en el automata

CASEOF Accion
0: ejecuta la primera accion, por ejemplo, poner el motor en marcha en descenso
1: ejecuta la segunda acción, detener el motor
etc.
...
ENDCASEOF

Como ya hemos cambiado el estado por el nuevo estado y ejecutado la accion correspondiente, podemos cerrar el IF

ENDDIF


En resumen, el programa explora en un bucle infinito todas las entradas, prepara un vector que indica todas las entradas activas, sin preocuparse del estado del sistema

Esto es lo mas importante para una programación segura, TODAS las variables que afectan al sistema se resetean primero y se setean despues, y eso, en cada bucle de programa

Este el elemento básico, a cada vuelta de programa se toma "una foto" de todas las variables del sistema, y se actúa con ellas. Oigo desde aqui a los programadores convencionales diciendo: Para que voy a perder ciclos de CPU mirando variables que se que no me interesan? Y le contestaré que de esa manera el sistema no se perderá en un bucle esperando que cambie una variable, que se está seteando en otra parte del programa que ahora no se ejecuta.. queridos amigos, cuántas veces habeis oido: "¡¡¡Pero si esto funcionaba!!!"

Pues con la programación por automata de estados, como que se oye menos :)

animo






cgriell

Parte 5 (y última)

Y ya para finalizar esta exposición, voy a tratar de definir la parte más compleja de la preparación del "vector descriptivo" que es un vector que tiene a TRUE todas las variables que estan activas en ese bucle, independientemente de que afecten, o no, al estado.

Variables que afectan:

PS: Pulsador de subida. Se copia el estado del pulsador (como todos los pulsadores e interruptores, es importante añadir un retraso, para eliminar rebotes).

Para ello se crea una variable temporal, para recordar el valor que tenia el pulsador en la vuelta anterior, y un contador de vueltas, que cuando llega a un maximo, actualiza la variable que llamamos PS. Es decir, PS no es una copia de la entrada, sino una copia retrasada de la entrada

El algoritmo de filtrado es el siguiente

Si la entrada ha variado, se inicia un contador de ciclos, que llamamos Cont
Si la entrada es identica, y Cont < Parametro esta en periodo transitorio, se incrementa Cont
Si la entrada es identica, y Cont => Parametro, la señal es estable, la copiamos

Queda algo asi como:

IF PulsadorTemp anterior = INPUT_Pulsador  /* input ciclo anterior (memorizado)  = input real ciclo anterior? */

IF Cont = MaxCont THEN /* Se ha llegado al parametro de numero de bucles, el valor se calcula aprox.  viendo cuantas instrucciones tiene el bucle principal */
PS = PulsadorTemp

ELSE
PulsadorTemp = INPUT_Pulsador
Cont = Cont + 1 /* se incrementa un contador de bucles */

ENDIF

ELSE /* ha variado la entrada, inicia el contador de vueltas */
Cont = Cont + 1

ENDIF

Pulsador de Bajada
el mismo algoritmo

Pulsador central
Este debe activar dos variables de estado distintas, PCC y PCL
Para determinar lo que es una pulsacion corta y una larga primero se filtra la señal del pulsador igual que antes, y una vez filtrada se pone en marcha un segundo contador, si llega al maximo, es PCL, y si no llega al maximo y ha superado el filtro, es PCC. O si es necesaria mayor precision, se dispara un temporizador de hardware (supongo que Arduino los tendrá) que avise cuando haya transcurrido el tiempo

Posición del toldo.
Probablemente no tenga el sistema un encoder que proporcione la posicion del toldo, asi que vamos a crear nuestro propio posicionador, tal como lo hace el fabricante, que pide al instalador que setee los valores mediante una pulsacion muy larga (> 10s) del pulsador de subida, para marcar el final de carrera superior y lo mismo del de bajada para marcar el inferior. Los pulsadores tienen pues una segunda funcion, asociada al tiempo de pulsacion, que se programa como en el caso anterior.

Cuando el operario hace la pulsacion larga del pulsador de subida, marcamos eso como cero (Arriba) en el contador POS e iniciamos el proceso de programacion, que debe seguir, obligatoriamente, por una pulsacion corta del pulsador de bajada. Si no hace esto en por ejemplo, 5 segundos, se indica error con una señal, que puede ser una oscilacion del toldo si no hay otro indicador.

Mientras dura la pulsacion de bajada, el motor se mantiene bajando, y el programa incrementa un contador, el POS que es el contador de Posición. Cuando se suelta el pulsador, se detiene la bajada del toldo. Pulsador de subida permite subirlo, y decrementar el contador. Una pulsacion larga del pulsador de bajada permite validar la posicion inferior, que corresponde a un valor del contador.

Este contador, asociado al tiempo de funcionamiento del motor, es lo que va a permitir fijar, aproximadamente, los valores de toldo arriba, toldo abajo y preposicionamiento. Es MUY aproximado, ya que la velocidad del toldo depende en particular de la temperatura, pero bueno, un encoder es dinero que probablemente no se justifique. Yo si le hubiese puesto finales de carrera, pero esos son feos, caros, y dificiles de ajustar.


Variable llegada a preposicionamiento
Esta variable, en el Vector de variables, se pone a TRUE cuando el valor del contador de posicion coincide con el valor del contador de preposicion, que se ha memorizado con una pulsacion larga del pulsador central. Para hacer el sistema mas seguro, es conveniente que sea TRUE cuando

IF (motor bajando AND Pos >= Prepos) OR (motor subiendo AND Pos <= Prepos) THEN  Variable de contexto llegada a preposicionamiento = TRUE ENDIF

Y yo creo que con esto he acabado la disertación. Probablemente si lo vais a implementar encontreis dudas y/o errores, estoy a vuestra disposicion por PM para tratar de resolverlas. Y si el moderador lo cree conveniente, puede indicar mi email como respuesta, ya que a veces paso tiempo sin entrar en el foro

Hector_A


Como verás, ya tienes tu hilo pegado como importante.

Gracias por tu colaboración!

Cuando acabes me avisas para que lo cierre y así quede como obra de consulta, exclusivamente.

Abrazos!

cgriell

Gracias por ponerlo como importante. Ya esta acabado :)

saludos (puedes borrar este mensaje, pero no he visto como enviarte un PM)

flyer9876

Hola Cgriell;  Soy uno de esos novatos de los que da dolores de cabeza... (agradezco su paciencia) pero de verdad está muy interesante tu post .. yo afortunadamente cursé FORTRAN y BASIC hace ya mas de 30 años durante mi carrera en Ingeniería Civil... y logro comprender los algoritmos.. pero algo como lo que escribiste ayuda a mejorarlo si conoces un poco ó a iniciar si no sabes nada...

Estoy haciendo un proyecto que aparece en "Proyectos" valga la redundancia.. se llama " Exoequeleto inferior" piernas motorizadas para discapacitados.. ojala le des una vuelta y me des tu opinión.

Saludos
Oscar A.

Settings

Bueno por fin me tome el tiempo de leer todo, muy buen aporte, me va a servir muchísimo cuando encare mi proyecto de una CNC, hay cosas que no me quedaron claras pero espero que aun sigas en el foro cuando encare este proyectito

ENGRAL

Una buenisima descripcion !!!

Felicitaciones !!!

jmmuruzabalinartech

Para mi ha sido muy interesante. Mucas gracias

edgarman

Muy bueno y claro. Material de referencia para tener guardado y consultar. Muchas Gracias!!!!

surbyte

Habitualmente uso máquiinas de estados, ya que acabo de resolver un problema de este modo aporte el código en el post#10 de este hilo comportamiento no esperado de delay().

Justamente delay que no se lleva de la mano con casi nada mas que con blink, pierde terreno todos los dias.
Para quienes lean este hilo vean un ejemplo modesto de como usar una máquina de estados.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy