lunes, 31 de agosto de 2015

RTC y PUERTO SERIE

OBJETIVO.
Realizar un programa simulando las tareas de una alarma que está siendo monitoreada en fecha y hora por medio del periférico RTC (Real Time Clock) en la tarjeta FRDM K64f.
INTRODUCCIÓN.
En esta práctica se va a describir cómo programar la interface del periférico “Real Time Clock (RTC)”. El periférico controla y establece cuando obtener los valores de un reloj que corre en tiempo real, esto permite obtener tiempos de alarma y recibir notificaciones de cuando la alarma es disparada (sucede un evento).
El Driver se inicializa con la función RTC_DRV_Inint(). Como primer parámetro se escribe el número de componente RTC. En la mayoría de los casos las tarjetas sólo cuentan con un solo periférico RTC. Por lo tanto el número default es cero. La función del controlador de inicio es que dispara el módulo del RTC, e inicializa las interrupciones del mismo, un ejemplo de inicialización es: RTC_DRV_Init(0);
El RTC utiliza un tipo de estructura rtc_datetime_t para configurar o leer la fecha y la hora. Para esto se llama a la función RTC_DRV_SetDatetime(), esta función configura el periférico a la fecha y hora actual, para conocer o leer la fecha y hora actual se llama a la función RTC_DRV_GetDatetime(). Un ejemplo de cómo inicializar y leer los valores del RTC para la fecha y hora es el siguiente:
//Crear una variable para inicializar los parámetros del RTC
rtc_datetime_t datetimeToSet;
RTC_DRV_Init(0);
datetimeToSet.year = 2015;
datetimeToSet.month = 07;
datetimeToSet.day = 24;
datetimeToSet.hour = 18;
datetimeToSet.minute = 30;
datetimeToSet.second = 45;
// Establecer los parámetros inicializados en el RTC //
result = RTC_DRV_SetDatetime(0, &datetime);
// leer los valores de tiempo y fecha del RTC //
RTC_DRV_GetDatetime(0, &datetime);
printf("Current datetime: %04hd-%02hd-%02hd %02hd:%02hd:%02hdnrnn",
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute, datetime.second);


El periférico cuenta con la opción de establecer alarmas con la función RTC_DRV_SetAlarm() y con la funcón RTC_DRV_GetAlarm() se puede obtener información sobre la alarma configurada, estas alarmas pueden ser programadas para provocar una interrupción utilizando la función RTC_DRV_SetAlarmIntCmd() o transferir un argumento a la funcón para establecer la alarma. Se pueden tener diversos tipos de alarma, por ejemplo una alarma que se active a una hora específica del día y se repita por cinco minutos un tiempo especificado.
Los otros módulos como el UART, y el GPIO ya se estudiaron en las prácticas pasadas. Por lo que esos periféricos se utilizarán con la misma configuración anterior.



DESARROLLO DE LA PRÁCTICA.
El objetivo de la práctica es: Programar una Alarma que indique la fecha y hora después de haber inicializado el “Real Time Clock” por medio de los Switches 2 y 3 de la tarjeta FRDM k64f, así como utilizando la terminal de Kinetis Design Studio para poder ver los valores del RTC sin necesidad de una comunicación serial.
Desarrollo Parte 1.
Creamos un proyecto nuevo en KDS, seleccionando como tarjeta a utilizar “FRDM K64F”, habilitando la opción para utilizar Procesor Expert.
Desarrollo Parte 2.
Agregamos al proyecto Nuevo el periférico del RTC, GPIO, PIT_timer y UART. Las configuraciones de éstos están en las prácticas pasadas, lo que se va a mostrar es la configuración del RTC en la figura 1.


Figura 1. “Configuración del RTC”

Como se observa en la figura 1 la modificación que se hace es marcar la “Auto inicialización” del periférico.
Y en esta parte configuramos KDS para poder utilizar el comando printf en la terminal del software, para esto se consulta la página en internet MCU ON ECPLISE y una vez que KDS está configurado se procede a la programación, basándose en el diagrama de flujo mostrado en la figura 2.


Figura 2. “Diagrama De Flujo General para Programación”


Como se observa en el diagrama de flujo el programa inicializa el RTC, con la hora y fecha actuales, y posteriormente se estará monitoreando por medio de los botones (Botón 2 y Botón 3) de la tarjeta FRDM K64f para verificar que el RTC efectivamente lleva una cuenta del tiempo y la fecha en tiempo real.
Ahora las funciones que están declaradas en el proceso también tienen un diagrama de flujo para ejecutar una tarea específica de acuerdo al programa principal, estas tareas se declaran en el programa principal pero se ejecutan fuera del programa principal cuando son llamadas, La primer función es la que pone la alarma en estado inicializar, su diagrama de flujo se muestra en la figura 3.


Figura 3. Función Inicializar alarma
La siguiente función que se muestra en el diagrama de Flujo Principal es “BOTONES”, en la cual se reconocerá cuando un botón ha sido presionado, y cómo ha sido presionado si fue sólo un pulso o si fue presionado por un tiempo corto (tipo HOLD), el diagrama de flujo se muestra en la figura 4.


Figura 4. Diagrama de Flujo función Botones.
Las tres últimas funciones (Desactivar Alarma, Reconocimiento Alarma y Activar Alarma) ejecutan una tarea simple ya que el objetivo de la práctica es aprender a utilizar el periférico RTC. El diagrama de Flujo es el mismo para las 3 funciones, por lo tanto sólo se utilizará un solo diagrama para representar a las tres funciones, en la figura 5 se muestra el diagrama de flujo para las funciones a realizar de la alarma.


Figura 5. Diagrama de Flujo Funciones de la Alarma.
Una vez que se tienen los diagramas de Flujo se procede a la programación, utilizando PE y con forme al diagrama de flujo mostrado en la figura 2 lo primero en KDS es inicializar el RTC con una variable la cual asignará los parámetros de fecha y hora a la configuración del RTC, posteriormente se declaran las funciones del programa, como se requiere hacer una alarma se ponen 4 estados, (Inicializar, Desactivar, Activar y Reconocimiento). Cada función realizará tareas diferentes y no regresarán resultado alguno entonces serán de tipo void. Al iniciar el programa la primer función que se llama es Inicializar Alarma, la cual estará ejecutándose mientras no se presione ningún botón, esta función hará que el Led RGB de la tarjeta FRDM K64f parpadee en color amarillo indicando que la alarma está en estado de Inicialización. Esto es la inicialización del programa el código se muestra en la figura 6.

Figura 6. Principio del Programa Alarma con RTC
El programa principal o rutina principal Figura 7. Muestra la siguiente parte correspondiente al diagrama de bloques, en la cual se llama a la función botones (Diagrama de flujo Figura 4) para saber si algún botón fue presionado, en caso de que algún botón haya sido presionado la alarma cambiará de estado y por medio de un switch case se llevará a cabo una tarea determinada.
La programación de la función botones de acuerdo al diagrama de flujo en la Figura 4, muestra el procedimiento para detectar cuando el botón 3 es presionado en tipo pulso o sostenido (Hold), el primer condicional if detecta cuando hay un cambio en el estado del botón es decir si estaba normalmente abierto y fue presionado (hay un cambio de cero a uno), entonces inicializa los valores de tiempo para determinar el tipo de pulso (PULSE o HOLD) y también un tiempo para que no existan “rebotes” al pulsar el botón, es decir que no se presione más de una vez seguida el botón. El segundo condicional detecta cuando hay un cambio en el botón de uno a cero esto quiere decir que el botón ha sido “soltado” y que el tiempo para detectar un pulso HOLD aún no ha terminado entonces el botón ha sido pulsado (PULSE). El tercer condicional funciona cuando el tiempo HOLD ha terminado entonces indica que el botón ha estado presionado por un tiempo y el botón detecta que el tipo de activación fue HOLD.
En todos los condicionales if de la función de botones se pregunta por una bandera, ya que puede ocurrir que el botón sea presionado por más tiempo del establecido en HOLD entonces el botón reconocerá varias veces el tipo de activación HOLD, además al soltar el botón en este caso detectará un tipo PULSE, esta bandera sirve como protección para asegurar que se presione una sola vez el botón ya sea tipo PULSE o tipo HOLD.


El último condicional de la función botones es para indicar que no hay cambio en el botón (que no ha sido presionado o soltado), entonces el botón continua en el mismo estado.  

Figura 7. Rutina Principal del Programa.

Figura 8.Función Botones para botón 3 tipo HOLD y PULSE.
En la figura 8 se observa que los estados de los botones dependen de tiempos, estos tiempos se modifican por medio del Programable Interrupt Timer (PIT timer), el cual está declarado en los eventos del programa, dependiendo de la configuración de tiempo en el PIT timer se produce una interrupción la cual ejecutará una tarea, estas tareas se observan en la figura 9.
Para la práctica se configuró el PIT timer en 1ms por ciclo, con lo cual cada mili segundo se producirá una interrupción la cual preguntará si el valor del tiempo para flash de los leds (time_delay) es diferente de cero, si es así este valor será decrementado, cuando llegue a cero la salida del RGB tendrá un “togle bit”, lo cual generará una acción de flash. Los siguientes dos condicionales (time_deb_sw2 y time_deb_sw3) preguntan por el tiempo anti rebote con el cual el push botón no tendrá pulsaciones repetidas, y el último condicional es para decrementar el tiempo del HOLD del botón 3, mientras el botón 3 esté presionado y el tiempo HOLD sea mayor a cero para evitar desbordamientos, se va a decrementar ese tiempo, cuando el tiempo llega a cero en la función botones se detecta que el botón ha sido pulsado por un tiempo “largo” y se considera pulsación tipo HOLD.
 

Figura 9. Eventos del programa, interrupciones en el PIT timer.
La última parte del programa son las funciones de acuerdo al estado de la alarma, estas funciones se muestran en la figura 10, cada función lee el momento en el que ocurre un cambio en la alarma por medio del RTC, muestra en pantalla la fecha y hora del evento, establece el estado de la alarma con el que se ejecutará una tarea en el programa principal. La primer función es la de inicializar, que es la función por defecto al iniciar el programa, las siguientes funciones son la de Activar y Desactivar, estas funciones son muy parecidas, se muestra un mensaje en pantalla del estado de la alarma, la fecha y hora en la que ocurrió el cambio, posteriormente se modifica el estado de la alarma para llevar a cabo una tarea específica en el programa principal.

Figura 10. Funciones de Estados de la Alarma.
Con lo mostrado anteriormente se completa el programa de Alarma utilizando RTC. Este programa ejecuta una tarea básica en cada estado de la alarma, como prender un led que indica el estado, pero esta tarea se puede complementar por medio de un sistema el cual se desee monitorear y ver cuando ocurren eventos importantes o cambios. El objetivo de la práctica es también utilizar el Real Time Clock que es un reloj en tiempo real, con el cual se puede monitorear cualquier aplicación o programar actividades a cierta hora y día específico de la semana.

Proyecto de la práctica:
https://www.dropbox.com/sh/ec91i98x9hdkg3a/AADEGlCoy9U6foWCkjRT9eT-a?dl=0

viernes, 28 de agosto de 2015

PUERTO SERIE


INTRODUCCIÓN.
En esta práctica se va a explicar cómo utilizar el puerto de comunicación serial de la tarjeta FRDM K64F de Freescale, primero se va a explicar cómo trabaja el puerto serial de acuerdo  a la información encontrada en el manual de referencia “K64 Sub-Family Reference Manual”, el Manual de referencia rápida “Kinetis Peripheral Module Quick Reference” y el manual de referencia para Kinetis SDK 1.1 V 1.2 “Kinetis SDK v.1.2 API Reference Manual “ los cuales se encuentran en la página oficial de Freescale  Freescale.com/FRDM-K64F.
“Universal Asynchronous Receiver and Transmitter (UART) Module” El módulo de la familia de dispositivos Kinetis soporta comunicación serial asíncrona con dispositivos periféricos u otros CPUs. El módulo UART tiene tres modos principales de operación: UART, IrDA, y ISO-7816.
En la práctica se va a trabajar con el modo UART, como si fuera comunicación por un puerto serial RS-232. El controlador (Driver) periférico de datos del UART permite transferir o recibir datos de otros dispositivos, por medio de un bus serial con sólo llamar una función.
El Diver utiliza estructura para el dispositivo UART de tipo uart_state_t para mantener activo y corriendo el estado de una instancia del módulo del driver del UART. Esto quiere decir que la estructura mantiene los datos que son usados por el Driver periférico del UART para comunicarse entre el transmisor y el receptor, recibir funciones de transferencia o interrupciones. Las interrupciones utilizan la información obtenida por el Driver periférico para saber su progreso.
Las estructuras de configuración de usuario del UART son de tipo uart_user_config_t. Estas habilitan la configuración de la mayoría de las opciones más comunes para configurar el UART, con sólo llamar una función. Las configuraciones más comunes son:
  • UART baud rate: Des habilitada (por defecto).
  • UART parity mode: Des habilitada (por defecto).
  • Number of stop bits.
  • Number of bits per data Word.
Inicialización del módulo UART.
  1. Para inicializar el Driver del UART, se llama a la función UART_DRV_INIT() , como “Procesor Expert” pone el argumento que en este caso es el número del periférico del UART utilizado,  el segundo argumento es la memoria para el estado de la estructura “run-time”.
  2. Una vez que transfiere la memoria para la estructura “run-time”, el tercer argumento de la función de inicialización es la dirección de la configuración de usuario uart_user_config_t.
  3. Este es un ejemplo de cómo inicializar el Driver:
UART_DRV_Init(uartInstance, &uartConfig, &uartState);
Una configuración de usuario básica puede ser la siguiente:
uart_user_config_t uartConfig;
uartConfig.baudRate = 9600;
uartConfig.bitCountPerChar = kUart8BitsPerChar;
uartConfig.parityMode = kUartParityDisabled;
uartConfig.stopBitCount = kUartOneStopBit;
DESARROLLO DE LA PRÁCTICA.
El objetivo de la práctica es: Configurar el módulo UART para enviar y recibir mensajes por medio de la terminal “Cool Term”, utilizando “Kinetis Design Studio” y “Procesor Expert”.
Desarrollo Parte 1.
Creamos un proyecto nuevo en KDS, seleccionando como tarjeta a utilizar “FRDM K64F”, habilitando la opción para utilizar Procesor Expert.
Desarrollo Parte 2.
Agregamos al proyecto Nuevo el periférico de comunicación para el UART: fsl_uart de la librería de componentes en la vista por categorías la dirección: (KSDK1.2.0\Peripherial Drivers/Hal\Communication\). Como se muestra en la figura 1.
Figura 1. “Agregar componente fsl_uart de la librería de componentes”
Una vez que se tiene el componente en el proyecto se procede a su configuración, en la ventana “Component Inspector”, como se muestra en la figura 2. Procesor Expert (PE) configura la mayoría de los parámetros, en este caso llama al componente “uartCom1” y el dispositivo es “UART0” en el modo del componente  PE pone por defecto “interrupt mode” ya que el otro modo es DMA, pero no será utilizado.
En la configuración del dispositivo se tiene el tipo de estructura definido en la introducción de esta práctica y como nombre PE asigna “uartCom1_InitConfig0”, Es importante porque al iniciar el Driver del UART un argumento será la dirección del nombre de la configuración. PE pide que ingresemos el parámetro “Baud rate” que es la velocidad a la cual se estará comunicando el módulo UART, hay que recordar que como es una comunicación asíncrona debemos configurar la velocidad en los dispositivos en los cuales se establecerá comunicación, en este caso en la tarjeta en la teminal "Cool Term", más adelante se mostrará como configurar la velocidad en esta.
Los otros dos parámetros los establece por defecto PE, el modo de comunicación Por paridad “Parity mode” des habilitado, y los bits por palabra los establece en 8.



Figura 2. “Configuración del Módulo UART”
Lo siguiente en la configuración son los pines que se van a utilizar para recibir o transmitir datos (RX/TX), éstos pines son los que están relacionados al UART0, FIGURA 3, se muestran los pines que están conectados al módulo UART0.
Figura 3. “Pines del Módulo UART0 para Transmisión y Recepción de Datos”
En la Configuración de Pins/Signals escribimos los pines de acuerdo a los mostrados en la figura 4, dichos pines son el PTA15 (UART0_RX), y el PTA14 (UART0_TX)

Figura 4. “Configuración de Pines Para Transmisión y recepción de datos”
En la parte de la inicialización se selecciona “Auto initialization”, y PE automáticamente activará las opciones Rx/Tx Callback.
Figura 5. “Inicialización del periférico UART0”
Posterior a la configuración se genera el código en el proyecto y posteriormente se procede a la programación.
Como Ejemplo se realizará un programa en el cual se enviará un mensaje al microcontrolador por medio de un mensaje en la terminal “Cool Term”, y éste responda con un mensaje “Aleatorio”, el programa utilizará la función de envío y recepción de datos sin utilizar un método de bloqueo de datos.

Figura 6. “Diagrama de Flujo de programación para envío y transmisión de datos.”
En la Figura 7  se muestra como se declaró el arreglo de cadenas de caracteres por medio de un apuntador, cada cadena de caracteres es una respuesta obtenida al enviar un mensaje por medio de la terminal “Cool Term”.
Figura 7. “Declaración de un arreglo de cadenas de caracteres.”
La declaración de las variables locales se muestra en la figura 8, como se observa la variable error tiene que ser tipo “uart_status_t” ya que ahí almacenaremos la condición de que el mensaje se ha recibido correctamente.
Figura 8. “Declaración de variables locales”
La figura 9 muestra el programa principal, dentro de éste, primero se lleva un conteo de n desde 0 hasta 4 que es el número de mensajes que se tienen para responder declarados al inicio del programa, posteriormente se asigna a la variable error  el estado de la recepción de los datos, en caso de ser correcta la recepción, se prosigue a enviar una respuesta por medio del arreglo de cadena de caracteres en la posición “n”. y cómo n es un número que está cambiando a la velocidad que está corriendo el programa (velocidad de frecuencia de reloj interno del microcontrolador) no se tiene un control sobre el mensaje que se va a recibir por eso al inicio se dijo que era un mensaje de respuesta “aleatorio”.
Figura 9. “Programa Principal”

En el programa “Cool Term” configuramos la velocidad de comunicación, el tamaño de la palabra de bits a transmitir, la paridad y el bit de paro, con los mismos parámetros que se configuró el periférico del UART, una observación es que por defecto pone el puerto, este puerto es dependiendo el driver que tenga instalado la tarjeta (Jlink Segger, PE Micro ó Open SD Debugging) el sistema de la PC va  a reconocer a la tarjeta como si estuviera conectado en un puerto serial, (En la figura 10 cómo ve el sistema a la tarjeta conectada en un puerto serie.)
Figura 10. “Configuraciones de Cool Term”
En la figura 11 se muestra cómo se ven los dispositivos conectados a la computadora PC. (Panel de control-> Administrador de dispositivos), en puertos (COM y LPT) se muestra un dispositivo llamado Jlink CDC UART Port (COM3), que es el Driver que se cargó previamente a la tarjeta, y el cual indica que existe una tarjeta conectada a la PC en el puerto serial COM3, se dice serial debido al Driver que se cargó pero físicamente está conectada por USB.
Figura 11. “Administrador de dispositivos de Windows”
Resultados del Programa.
La terminal Cool Term permite enviar mensajes al Microcontrolador por medio del puerto al que se encuentra conectado, una de las ventajas es que podemos recibir los mensajes que envía el micro en la misma interfaz, de esta manera podemos comprobar que exista comunicación serial en tiempo real con el microcontrolador, la Figura 12 muestra cómo se ven los mensajes una vez que el programa está cargado y en modo “run”.


Figura 12. “Entorno de la Interfaz Cool Term”
Como se observa en la figura 12 el botón CONECT debe estar marcado para poder mantener comunicación con la tarjeta, además cada vez que se está escribiendo se encienden los “LEDS” TX o cuando se recibe “RX”, de esta manera se puede obtener información de alguna aplicación por medio de comunicación serial, este es un ejemplo de cómo enviar y recibir mensajes, pero se puede estar monitoreando el valor de una variable, o incluso modificar su valor sólo habría que hacer una conversión ASCII.

Proyecto de la práctica:

https://www.dropbox.com/sh/is2geo6qjnvavwf/AAAjKt_1g1WcFQHdjwgrDHmOa?dl=0

Semáforo

INTRODUCCIÓN

Ahora que hemos visto la utilización de los switches y leds en las prácticas anteriores, los utilizaremos en un ejemplo de aplicación. Así que realizaremos una aplicación de un semáforo el cual no solo cambiará el color del led de entre vede amarillo y rojo, sino que tendrá otras opciones propias de los semáforos.
La práctica se pensó con una máquina de estados. A continuación presentamos el diagrama.



En el diagrama anterior presentamos los estados que tendrá el semáforo. Los estados principales son los 4 círculos grandes, estos son: estado rojo, estado verde, verde parpadeo y amarillo. Estas son los estados normales de un semáforo. Cada uno tiene un tiempo asignado, tiempo que da la duración activa de cada estado. Así mismo las flechas gruesas de color azul son las que indican el funcionamiento en operación normal.
Adicionalmente tendremos opción de emular el funcionamiento del semáforo en operación inusual, por ejemplo un estado de falla, o las veces en que un policía opera manualmente los semáforos para intentar liberar un atascamiento de carros en tráfico intenso. Estos casos se muestran en la máquina de estados con flechas delgadas y rojas, para el caso de falla tendremos un nuevo estado al que le llamaremos: parpadeo amarillo. Este estado emula las veces cuando un semáforo se descompone y solo parpadea en color amarillo. Este estado también puede ser usado para el funcionamiento nocturno de algunos semáforos, en el que el semáforo solo parpadea en amarillo como signo de precaución. Para poder utilizar estos estados necesitaremos presionar los botones que se encuentran integrados en la tarjeta. Se presentan las siguientes condiciones:
  • Sin importar en qué estado se encuentre el semáforo (rojo, verde, etc), siempre podremos pasar al estado de falla (parpadeo amarillo). En el cual permanecerá indefinidamente hasta una nueva interacción por parte del usuario. Para poner el semáforo en este estado deberemos presionar el sw2.
  • Podremos salir del estado de falla si, y solo si, presionamos el sw3, el cual nos enviará directamente al estado rojo.
  • Podremos pasar rápidamente del estado rojo o verde solo presionando el sw3. Si el semáforo se encuentra en estado rojo y presionamos el sw3, pasará inmediatamente al siguiente estado (estado verde). Se igual manera si es semáforo se encuentra en estado verde y presionamos el sw3 cambiará inmediatamente al siguiente estado (verde parpadeo). Sin embargo el usuario no tendrá ningún dominio de cambio rápido de estado en los estados amarillo y verde parpadeo. Por lo que deberá pasar el tiempo programado para que pase al siguiente estado.

DESARROLLO DE LA PRÁCTICA

Lo primero que analizaremos serán los componentes que agregamos y la configuración de cada uno de estos componentes. Ya no se abordará tan afondo como en la práctica 1 la manera de agregar los componentes puesto que ya se mostró en esa práctica.  Así que los componentes que se utilizan son:

Figura 1. “COMPONENTES UTILIZADOS EN LA PRÁCTICA”
Primero veremos la configuración del CPU y el reloj del CPU. Es importante mencionar que la configuración del CPU (y el reloj) es exactamente la misma que la de la práctica 1. Así que para mayor información es aconsejable revisar dicha práctica.

Figura 2. “CONFIGURACIÓN DEL MODULO Cpu:MK64FN1M0VLL12”

Figura 3. “CONFIGURACIÓN DE RELOJ DEL CPU clockMan1:fsl_clock_manager”
Ahora continuaremos con la configuración del siguiente componente el cual es para la configuración de los pines. Este es el apartado donde se asigna un nombre personalizado a determinado pin de la tarjeta para poder llamarlo con mayor facilidad en el código. El componente que analizaremos es el pin_mux:PinSettings. Cabe mencionar que esta configuración es exactamente igual que la de la práctica 1. Así que para más información es recomendable analizar esa práctica
Primero veremos la configuración del GPIO

Figura 4.“CONFIGURACIÓN DE PINES PARA EL GPIO”
El último componente a analizar es el pitTimer1:fls_pit. La configuración es parecida a la de la práctica 1, pero en este caso el periodo está ajustado a 1 ms en lugar de 1000 ms.

Figura 5. “CONFIGURACIÓN DEL pitTimer”
Ya hemos terminado de ver la configuración de los componentes que se utilizarán en la práctica. Como pudimos ver la configuración es exactamente la misma que la de la práctica pasada. A continuación vamos a ver el diagrama de flujo que representa lo que vamos a realizar en esta práctica.


Figura 6. “DIAGRAMA DE FLUJO PARA EL SEMÁFORO”
Lo primero son las definiciones. Declaramos 3 constantes llamadas FLASH_SLOW, FLASH_MEDIUM y FLASH_FAST. Cada uno será un contador de 0x200, 0x100 y 0x80 ms respectivamente.
Luego declaramos 4 variables. Dos de estas son variables enteras de 16 bits, la primera se llama ‘TiempoLed’ y la segunda ‘TiempoCambio’. Las dos variables restantes son 2 variables de un tipo creado por nosotros, lo veremos más adelante. El tipo de variable es status_semaforo y las variables que son de este tipo son una llamada ‘estado’ y la otra llamada ‘next_state’
Ahora declaramos dos estados llamados ‘DOWN’ y ‘UP’ junto con 4 variables que pueden tomar este estado, una llamada state_sw3, la segunda se llama last_state_sw3. La tercera y cuarta reciben el nombre de las 2 primeras pero en lugar del sw3 será para el sw2.
En el siguiente renglón declaramos tres estados llamados ‘NONE’, ‘PULSE’ y ‘HOLD’ junto con 2 variables que pueden tomar estos estados. La primera se llama boton_sw2 y la segunda boton_sw3
En la siguiente línea definimos un tipo de variable llamado ‘colors’ y 3 estados de este tipo, llamados BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN y WHITE.
Por ultimo tendremos otra enumeración llamada rgb_color que tendrá 3 estados R=1, G=2 y B=4
Antes de continuar debemos agregar un nuevo archivo llamado Semaforo_APP.h el cual contendrá el siguiente código.
Dentro de este nuevo archivo tendremos, primero, una enumeración que define un tipo de variable, el tipo se llama ‘status_semaforo’. Habrá 5 estados que serán de este tipo: ESTADO_ROJO, ESTADO_VERDE, ESTADO_PARPADEO, ESTADO_AMARILLO y ESTADO_FLASH_AMARILLO.
Además declaranos 6 constantes: TIEMPO_ROJO=5000, TIEMPO_VERDE=5000, TIEMPO_AMARILLO=2000, TIEMPO_PARPADEO=2000, TIEMPO_ANTIREBOTE=100 Y TIEMPO_CAMBIO=250. También agregaremos 3 de las variables que tenemos en el archivo main.c. Estas variables son TiempoLed, TiempoCambio y estado.
Al agregar este nuevo archivo Semaforo_APP.h necesitamos incluir el archivo para que pueda ser leído desde el archivo main.c así que agregaremos la siguiente instrucción.
Ahora analicemos el otro archivo que nos compete que es el Events.c. En este archivo utilizaremos las interrupciones generadas por el pitTimer. Y agregaremos 3 variables que nos serán de utilidad.
Las variables agregadas son las siguientes
Y dentro de las interrupciones del pitTimer pondremos lo siguiente:
La variable time_delay será la que nos ayude a hacer en tiempo las transiciones entre un estado y otro del semáforo. Las variables time_deb_sw2 y time_deb_sw3 serán para evitar el tiempo de rebote del switch, esto debido a que el microcontrolador lee con demasiada velocidad los puertos y al momento de apretar el switch manualmente, el microcontrolador puede leer es estado presionado durante mucho más de un ciclo y hacer cosas que no deseamos.
El conter_ms  será la variable que nos ayudará a controlar el tiempo del flasheo del led.
Ahora, regresando al archivo main.c debemos agregar las variables del archivo de eventos que también utilizaremos en él. Así que dentro de main.c agregaremos lo siguiente:
Ahora declaramos las subrutinas que utilizaremos antes del inicio de la función main. Las subrutinas son las siguientes
Vamos a ver, en primer lugar la función led
Esta función tiene como argumento una variable de tipo ‘colors’ llamada x, este tipo de variable que se declaró previamente. Según la variable que se ingrese habilitará la salida de los los leds necesarios para dar el color deseado, ya sea verde, rojo, amarillo etc. Esto gracias al peso de los bits. Ahora continuaremos con la función main, la iremos analizando poco a poco con la secuencia en la que van ocurriendo las instrucciones.
La primera instrucción que podemos ver es la inicialización del Processor Expert PE_low_level_init( );
A continuación asignará ESTADO_ROJO a la variable next_state y asignará el valor de cero a la variable time_delay. Esto con el fin de que el semáforo inicie en el color rojo, la razón la veremos un poco más adelante.
Ahora entramos en el for infinito que se encargará de que nuestro programa entre en un loop que nos permitirá pasar indefinidamente por el mismo conjunto de instrucciones.
Lo primero es la función botones
Esta función se encargara de hacer que los botones tengan un tiempo anti-rebote. Esto es que el microcontrolador no detecte un botón pulsado como si se presionara dos veces. Esto se debe a que el microcontrolador trabaja a una alta frecuencia, y lo que para el usuario pude ser un pulso inmediato, el micro puede leer que la entrada permanece apretada durante 10, 100 o 1000 ciclos (por poner un ejemplo). Así que esta función fue creada para evitar que esto pase realizando una serie de condicionantes junto con un TIEMPO_ANTIRREBOTE que nos ayudará a evitar esto. Esto es útil cuando un solo botón hace funciones sucesivas en una secuencia de trabajo. En esta práctica el sw3  nos sirve para “apurar” el color rojo y verde, si no se tuviera una función como esta, haría que termine el tiempo del color rojo, y de inmediato haría lo mismo con el tiempo del color verde, y esta no es la función deseada.  
La siguiente función es la función ‘falla’. En esta función preguntaremos si el estado del botón_sw2 es igual que PULSE (o sea que se encuentre pulsado). Si la condición se cumple haremos que el time_delay sea igual a cero, a la variable next_state le asignaremos el valor de ESTADO_FLASH_AMARILLO y diremos que es estado del botón_sw2 es none.


En caso de que el botón sw2 se presionara  el estado de la variable next_state ahora sería ESTADO_FLASH_AMARILLO. Como podemos apreciar dentro de la función main asignamos el valor de la función next_state a la variable estado. Además decimos que si el time_delay es cero entrará a la función SWITCH que está más abajo. La función switch tendrá como elemento de selección el valor de la variable estado. Así que en este caso el valor de la variable estado sería ESTADO_FLASH_AMARILLO, por lo que el switch entrará al case:ESTADO_FLASH_AMARILLO. El cual tiene como única instrucción el llamado de función de fflashamarillo (), vamos a analizar la función:
Esta función manda el color YELLOW a la función de parpadeo ‘flash_led’ y después tendrá una condición por medio de un if. Esta condición preguntará si el botón_sw3 está presionado, de ser así hará que el time_delay tenga un valor de cero. Además le asignará a la variable ‘next_state’ el ESTADO_ROJO y pondrá el boton_sw3 en estado NONE.


Al pasar de esta función el next_state tiene como valor ESTADO_ROJO y el time delay tiene cero como valor, por lo que estaremos en el estado inicial del programa, recordemos que así se inicializan estas variables. Así que si no se entrara dentro de la función de falla iniciaríamos el switch en el case ESTADO_ROJO. La cual tiene como instrucción el llamado de función a la variable frojo. Vamos a analizar las instrucciones de esta función.
La función ‘frojo’ es la que contiene las instrucciones necesarias para que funcione el estado rojo del semáforo. La primera instrucción es un if que  pregunta si el tiempo de retardo ‘time_delay’ es igual a cero. Además pregunta si al mismo tiempo el valor de la variable ‘next_state’ es ESTADO_ROJO. La primera instrucción se asegura de que el tiempo del estado anterior haya concluido, la segunda se asegura de que el estado que está próximo a entrar sea ESTADO_ROJO. Si ambas condiciones se cumplen hará lo siguiente:
  • Asignará el tiempo para el estado rojo ‘TIEMPO_ROJO’ al tiempo del contador ‘time_delay’.
  • Mandan el color rojo (RED) a la función led.
  • Hace que la variable ‘next_state’ tome el valor ‘ESTADO_VERDE’.
Además habrá otra condición en la que se pregunta si el estado del ‘botón_sw3’ es ‘PULSE’, si se cumple cambiará el tiempo del time_delay a cero. Esto es para emular la función cuando el policía aprieta el botón para apresurar los tiempos del semáforo, así que al mandar el tiempo a cero cambiará inmediatamente de estado.
Como pudimos apreciar el next_state tendrá como valor ESTADO_VERDE por lo que el switch entrará dentro del case ESTADO_VERDE. Pero esto lo hará solo hasta que el time_delay haya terminado su conteo, recordemos que aprovechamos la interrupción del pitTimer para decrementar el conteo del time_delay cada milisegundo.
La función fverde tendrá un funcionamiento análogo a la función frojo, pero activará el tiempo y led de color verde, además hará que el siguiente estado guardado en la variable ‘next_state’ sea el estado de parpadeo.
Ahora de la misma manera que en el caso anterior cambiaremos al estado ESTADO_PARPADEO, dentro del switch nos mandará a la función fparpadeo.
La función fparpadeo comenzará con una comparación similar a la de las funciones frojo y fverde, preguntando si el tiempo de retraso ‘time_delay’ es cero, además si el siguiente estado next_state es igual  a ESTADO_PARPADEO. Si esta condición se cumple asignara el tiempo de TIEMPO_PARPADEO a la variable ‘time_delay’, además hará que el siguiente estado sea el ESTADO_AMARILLO, guardado en la variable ‘next_state’ fuera de las instrucciones del if mandará el color GREEN a la función flash_led.  
El siguiente estado por analizar es el ESTADO AMARILLO el cual manda a llamar a la función famarillo
La siguiente función es famarillo. Esta función podemos analizarla de manera análoga a las funciones fverde y frojo, aplicado al color amarillo, sin embargo no tiene las instrucciones necesarias para cambiar de estado inmediatamente a través de un botonazo, esto debido a que no es posible omitir el color amarillo (preventivo) de un semáforo en la realidad.
Al terminar esta función el time_delay quedara con valor cero y el siguiente estado será ESTADO_ROJO, por lo que volveremos al estado inicial y comenzaremos nuevamente con el flujo normal de los colores del semáforo.

Proyecto de la práctica:

https://www.dropbox.com/sh/rtiuvtkls4dii03/AABRajbFkd_tTiKQr9M8Zxeja?dl=0