Paso 6: Llevar su sistema al mundo real
Vale, nos haga clic alrededor, utiliza un editor gráfico (normalmente asociado con lenguajes de bajo nivel), hagamos que esa cosa a la vida. En primer lugar, necesitamos un generador de código que transforma nuestro estado en C código. Es asombrosamente simple, aunque al principio puede parecer como magia negra.
Haga clic con el botón derecho la carpeta modelo y seleccione nuevo -> modelo de generador de código. Usted haga clic en el asistente y conecte el generador de código para el diagrama de estado que hizo antes. Atención: En esa misma ventana, hay un selector en la parte superior que es fácilmente supervisada. Utilícelo para seleccionar el generador de código C en vez de la de Java y haga clic en terminar después de que haya verificado la casilla de verificación al lado de su estado. Normalmente, el generador debe ahora trabajar directamente y automáticamente todo el tiempo. Comprobar si dos carpetas creadas, fuente y fuente-gen. Si ese no es el caso, ir a proyecto en el menú principal y compruebe si construir automáticamente está activado. Hacerlo si no, haga clic derecho en tu proyecto y seleccione crear proyecto. Debería aparecer una barra de progreso así como tanto las carpetas mencionadas. Cuando usted hace los cambios, también puede haga clic derecho en el archivo del generador y seleccionar Generar código artefactos.
El contenido de la carpeta src-gen es bastante interesante. El archivo LightCtrl.c contiene la implementación del estado. Inspeccionarlo, encontrará una función LightCtrlIface_raise_button (LightCtrl * manija). Usted puede llamar a esta función para el evento de botón que declaramos antes – por ejemplo, cuando se compruebe pin de su hardware botón y ver que tiene un alto nivel. Entonces es el archivo LightCtrlRequired.h, en que es necesario echar un vistazo. Declara funciones a implementar. Para este estado, hay sólo dos funciones: lightCtrl_setTimer y lightCtrl_unsetTimer. Necesitamos estas funciones porque el estado utiliza la construcción después de 5s. Esta es una función muy conveniente, pero nuestro generador de código de estado no entregar un servicio de sincronización, ya es altamente dependiente de la plataforma – ordenador puede manejar diferentemente que el Arduino pequeños temporizadores, temporizador en Mac y Linux funciona de modo distinto que en Windows.
Por suerte, voy a darle un servicio de sincronización, por lo que no necesitará implementar su propio. En su proyecto, cree una nueva carpeta, vamos a llamarlo scutils para statechart utilbolsa. Lo que sea lo que desea o no decide crear esa carpeta, es sólo una cuestión de organización. Vamos a crear dos archivos allí, sc_timer_service.c y sc_timer_service.h. Copia el
código en GitHub en el interior (también puede descargar el proyecto completo desde GitHub aquí):
Ahora, podemos empezar a trabajar en el código de Arduino en el archivo *.ino generado el asistente.
Adicionalmente a la Arduino.h, también son avr/sleep.hy por supuesto nuestra máquina de estado y el servicio de temporizador: LightCtrl.h, LightCtrlRequired.h y sc_timer_service.h. Ahora, es necesario regular lo de Arduino: definimos los pines para el botón y el LED y éstos establecer dentro de la función de configuración (que es lo que se hizo). Entonces, debemos definir las funciones que el estado espera que definir - lightCtrl_setTimer y lightCtrl_unsetTimer, como se explicó antes. Aquí, sólo utilizamos el servicio de temporizador y hemos terminado. Ahora, debemos repuesto un pensamiento sobre cómo queremos realmente activar el LED Cuando alcanzamos el estado de Luz. Básicamente, tenemos tres opciones:
- Podemos comprobar si el statemachine está en el estado de luz y activar o desactivar la el LED basado en esa información
- Podemos ir a nuestro estado y fijar una variable cuando lleguemos a los Estados, que podemos sondear
- Podríamos añadir una operación que dirige la luz que es llamada por el estado en transición.
La primera solución es realmente mala. Tiene lógica sobre el estado fuera de ella. Si cambiar nuestros Estados, dejaría de trabajar correctamente; pero esos nombres son significados para ser prosaico y relacionados con la no lógica. Uso de variables está bien, especialmente cuando se trabaja con aplicaciones de escritorio. Podemos sincronizar con ellos cada milisegundos x más o menos. Aquí, queremos hacer una operación. Añadir la siguiente declaración de interfaz de estado:
operation setLight(LightOn: boolean): void
Esto declara una función que acepta un valor booleano como argumento y devuelve nada (void). Esto no debería ser nuevo para usted, sólo la sintaxis aquí es diferente. Recuerda – gráficos de estado no están limitados a un idioma específico, por lo que la sintaxis es genérica. Esta función aparece en LightCtrlRequired.h automáticamente. Si no lo hace, guardar su estado, haga clic derecho sobre el proyecto y construirlo.
La función declarada aquí este aspecto:
extern void lightCtrlIface_setLight(const LightCtrl* handle, const sc_boolean lightOn);
El mango del parámetro de entrada es del tipo LightCtrl, es el referente para el estado. Si no en C: la estrella denota un supuesto puntero, por lo que la variable contiene la dirección de la variable de estado. Esto nos ayuda porque puede operar sobre el objeto original y no tiene que crear una copia de la misma. Por lo tanto, vamos a implementar esta función:
void lightCtrlIface_setLight(const LightCtrl* handle, const sc_boolean lightOn) { if(lightOn) digitalWrite(LED_PIN, HIGH); else digitalWrite(LED_PIN, LOW); }
Como se puede ver, esta función es sangrienta simple – incluso no utiliza la manija para el estado, sólo escribimos un alto en el pin del LED si argumento del funcionamiento es verdadera y bajo otra forma.
Cambiamos el estado sí mismo para que se vea como en la primera foto.
Paso 1 ¿recuerdas? Izquierda de la barra es el insumo necesario para la transición, derecha es la salida de la máquina de estado si se toma esta transición. El resultado aquí es llamar a la operación especificada con estos argumentos.
#include "Arduino.h"#include "avr/sleep.h" #include "src-gen/LightCtrl.h" #include "src-gen/LightCtrlRequired.h" #include "scutil/sc_timer_service.h"#define BUTTON_PIN 3 #define LED_PIN 6 #define MAX_TIMERS 20 //number of timers our timer service can use #define CYCLE_PERIOD 10 //number of milliseconds that pass between each statechart cyclestatic unsigned long cycle_count = 0L; //number of passed cycles static unsigned long last_cycle_time = 0L; //timestamp of last cycle static LightCtrl lightctrl; static sc_timer_service_t timer_service; static sc_timer_t timers[MAX_TIMERS];//! callback implementation for the setting up time events void lightCtrl_setTimer(LightCtrl* handle, const sc_eventid evid, const sc_integer time_ms, const sc_boolean periodic){ sc_timer_start(&timer_service, (void*) handle, evid, time_ms, periodic); }//! callback implementation for canceling time events. void lightCtrl_unsetTimer(LightCtrl* handle, const sc_eventid evid) { sc_timer_cancel(&timer_service, evid); }void lightCtrlIface_setLight(const LightCtrl* handle, const sc_boolean lightOn) { if(lightOn) digitalWrite(LED_PIN, HIGH); else digitalWrite(LED_PIN, LOW); }//The setup function is called once at startup of the sketch void setup() { pinMode(BUTTON_PIN, INPUT); pinMode(LED_PIN, OUTPUT); sc_timer_service_init( &timer_service, timers, MAX_TIMERS, (sc_raise_time_event_fp) &lightCtrl_raiseTimeEvent ); lightCtrl_init(&lightctrl); //initialize statechart lightCtrl_enter(&lightctrl); //enter the statechart }// The loop function is called in an endless loop void loop() { unsigned long current_millies = millis(); if(digitalRead(BUTTON_PIN)) lightCtrlIface_raise_button(&lightctrl); if ( cycle_count == 0L || (current_millies >= last_cycle_time + CYCLE_PERIOD) ) { sc_timer_service_proceed(&timer_service, current_millies - last_cycle_time); lightCtrl_runCycle(&lightctrl); last_cycle_time = current_millies; cycle_count++; } }
También, revisa el código en este esencial con números de línea.
- Líneas 1-6 contienen incluye como anteriormente.
- Líneas 8 y 9 definen pins hardware que queremos utilizar para nuestro arduino.
- Las líneas 11 y 12 definen cuántos temporizadores nuestro estado puede utilizar, y cuántos milisegundos que deben pasar entre cada ciclo de informática del estado.
- Líneas 15 y 16 declaran variables que podemos utilizar para contar los ciclos y a gestionar el tiempo del último ciclo.
- Líneas 17, 19 y 21 declaran variables importantes para el uso de las gráficas de estado: el estado sí mismo, el servicio de temporizador y una amplia gama de temporizadores.
- Líneas 24 y 33 definen las funciones que el estado necesita para el temporizador, y 33 es la función de fijar el LED ya comentamos anteriormente.
- En la línea 41, void setup() es una función estándar de Arduino. Se llama una vez al inicio. Lo usamos para iniciar cosas, nuestros pasadores LED y botón de Obtén su dirección configurada (entrada estándar, que hacemos para mayor claridad), se inicializa el servicio de temporizador, el diagrama de estado es inicializado y entró. Entrando en los medios para iniciar la máquina del estado, por lo que el primer estado es activado, este es el estado de los puntos de estado de la entrada en. Así, en el arranque, la luz está apagada.
- En la línea 59, sigue la función loop, que se llama todo el tiempo por el Arduino.
- En la línea 61, capturamos la hora actual con la función millis(), definido por la biblioteca de Arduino.
- En la línea 63, compruebe si el botón es presionado y levantar el evento de botón si es.
- En la línea 66, comprobamos si pasado más de milisegundos CYCLE_PERIOD ya que pasado un ciclo de nuestro estado.
- Esto lleva alguna carga de nuestro arduino y significa que confiablemente podemos utilizar hasta 10 milisegundos para nuestras propias funciones.
- En la línea 68, Dile que el servicio de contador de tiempo cuánto tiempo ha pasado desde la última invocación, Dile el estado para ejecutar un ciclo en línea 70, guardar la hora actual en línea 72 e incrementar la cuenta de ciclo en la línea 73.
Usando el plugin de arduino, usted puede ahora conectar el arduino con el LED y el botón conectado al ordenador y utilice el botón en la barra de herramientas superior para cargar el programa en el arduino.
El circuito se muestra en las fotos dos y tres.
El LED está conectado a un pin digital (6) con una resistencia de 200 ohmios rotonda. El cátodo está conectado a tierra.
Botones tienen cuatro pines, por favor que estos siempre están conectados y que están conectadas al pulsar el botón. Luego, conecta el pin digital (3 se utiliza aquí) a un lado y un resistor de desconexión a tierra. Esto deja el pin de "flotante", un estado indefinido y mantiene en 0 voltios. Cuando se presiona el botón y del otro lado está conectado a VCC, que lado es "más fuerte" porque no tiene ninguna resistencia y el voltaje va a 5 voltios – básicamente un divisor de voltaje en una resistencia es 0 Ohms. Utilice una resistencia bastante alta, ya que limita el pasando actual a través del botón. 1 kR es el mínimo.
Como se puede ver, la lógica de este programa es totalmente independiente del tamaño real de nuestro estado. No importa si nuestro estado tiene 2 o 20 Estados – por supuesto, si queremos hacer algo, necesitamos implementar una función aquí y allá. Pero el código principal dentro de void loop() siempre se queda muy pequeño y permite una arquitectura de programa modular. Sólo tenemos que cuidar de las interfaces de lo diagrama de estado para el hardware de nuestro Arduino dentro de nuestro código, el estado genera automáticamente encarga de su lógica interna. ¿Recuerdas cómo discutimos el temporizador se restablece cuando se vuelva a pulsar el botón? Podría ahora agregar una transición de luz en estado a sí mismo con el "botón" como evento de guardia, y no necesita cambiar o añadir una sola línea en el código. ¡ Pruébalo!