Que levante la mano quién no haya hecho el típico circuito de semáforo para probar una plataforma o un microcontrolador nuevo. El semáforo se podría considerar como el HolaMundo de la electrónica. Cualquier alumno de tecnología o de ingeniería podrá corroborar lo que digo. Tanto es así que el hashtag #nomassemaforos es cada día más popular en Twitter. Sobre este particular, José Antonio Vacas dio una interesante charla en Malakabot 2017 que os dejo aquí debajo.
Está claro que como ejemplo inicial, el semáforo puede ser un diseño útil, pero después hay que ir más allá. Si andáis faltos de imaginación, José Antonio os deja en su GitHub algunas ideas que os pueden servir de inspiración
Pero si pensabais que tras todo este movimiento se habían acabado los semáforos, estáis muy equivocados. Tras el hashtag #RetoSemaforos se encuentra un interesante reto propuesto por Cesar García del podcast La Hora Maker y David Cuartielles. Se trata de un proyecto colectivo para realizar semáforos en la mayor cantidad de modos posible. Dejo que ellos mismos os presenten el proyecto.
Si queréis participar sólo tenéis que acudir al GitHub de David y seguir las instrucciones. Yo por mi parte me he animado a enviar dos diseños: Uno con el TI MSP430 y otro con FreeRTOS.
El diseño del semáforo es muy simple y se muestra en el siguiente esquema, donde se indica a qué pines han de conectarse los LED. En este caso he usado una placa de desarrollo LaunchPad basada en el microcontrolador MSP430. También os dejo el código C del semáforo.

#include <msp430.h> enum estados { ROJO, AMARILLO, VERDE }; int color; int main(void) { WDTCTL = WDTPW + WDTHOLD; // Detiene el watchdog P3DIR |= BIT0; // P3.0 (LED rojo) como salida digital P3DIR |= BIT1; // P3.1 (LED amarillo) como salida digital P2DIR |= BIT6; // P2.6 (LED verde) como salida digital P1REN |= BIT1; // Resistencia en P1.1 (pulsador derecho) P3OUT |= BIT1; // Modo pull-up P2OUT |= BIT1; P1IE |= BIT1; // habilita la interrupción de P1.1 P1IES |= BIT1; // Interrupción por flanco de bajada P1IFG &= ~(BIT1); // baja flag de interrupción de P1.1 (por si acaso) color = ROJO; P3OUT |= BIT0; // Empezamos encendiendo el rojo P3OUT &= ~BIT1; // apagamos el amarillo P2OUT &= ~BIT6; // apagamos el verde // Activar interrupciones __bis_SR_register(GIE); // también puede usarse: __enable_interrupt() // Modo bajo consumo pero atendemos interrupciones __low_power_mode_0(); // Entrada LPM0, habilita interrupciones __no_operation(); // Para depuración } // Rutina de gestión de interrupciones de P1 #pragma vector=PORT1_VECTOR __interrupt void P1_ISR(void) { extern int color; if (P1IFG & BIT1) { // ¿fuente de la interrupción es P1.1 (pulsador)? switch (color) { case ROJO: color = AMARILLO; P3OUT &= ~BIT0; // apagamos el rojo P3OUT |= BIT1; // encendemos el amarillo break; case AMARILLO: color = VERDE; P3OUT &= ~BIT1; // apagamos el amarillo P2OUT |= BIT6; // encendemos el verde break; case VERDE: color = ROJO; P2OUT &= ~BIT6; // apagamos el verde P3OUT |= BIT0; // encendemos el rojo break; } P1IFG &= ~BIT1; // puesta a cero del flag de interrupción P1.1 } }
Para el ejemplo de semáforo con FreeRTOS he usado la placa de desarrollo LaunchPad CC3200 que utiliza una MCU ARM Cortex A4. El esquema de conexionado con la placa y el código son los siguientes.

#include <stdint.h> #include <stdbool.h> #include <stdlib.h> #include "hw_types.h" #include "hw_ints.h" #include "hw_memmap.h" #include "interrupt.h" #include "rom_map.h" #include "prcm.h" #include "gpio.h" #include "pinmux.h" #include "FreeRTOS.h" #include "task.h" // prototipos de función void BoardInit(void); // variables globales extern void (* const g_pfnVectors[])(void); //***************************************************************************** // FreeRTOS User Hook Functions enabled in FreeRTOSConfig.h //***************************************************************************** void vAssertCalled( const char *pcFile, unsigned long ulLine ) { //Handle Assert here while(1) { } } void vApplicationMallocFailedHook() { //Handle Memory Allocation Errors while(1) { } } void vApplicationStackOverflowHook( void *pxTask, signed char *pcTaskName) { //Handle FreeRTOS Stack Overflow while(1) { } } // Board Initialization & Configuration void BoardInit(void) { // Set vector table base IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // Enable Processor MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); } /*-----------------------------------------------------------*/ //Esta tarea enceinde las luces del semáforo static void SemaforoBlink( void *pvParameters ) { //La tarea debe tener un bucle infinito... for( ;; ) { // Encender LED rojo GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_3,GPIO_PIN_3); vTaskDelay(0.5*configTICK_RATE_HZ); GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_3,0); // Encender LED amarillo GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_2,GPIO_PIN_2); vTaskDelay(0.5*configTICK_RATE_HZ); GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_2,0); // Encender LED verde GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_1,GPIO_PIN_1); vTaskDelay(0.5*configTICK_RATE_HZ); GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_1,0); } } /*-----------------------------------------------------------*/ // Función main void main() { BoardInit(); // Configuración de la placa PinMuxConfig(); // Pinmux donde se configuras los puertos para los LED como salida digital // Apagamos los LED GPIOPinWrite(GPIOA1_BASE,GPIO_PIN_3|GPIO_PIN_2|GPIO_PIN_1,0); /* creamos la tarea para el semaforo */ if (xTaskCreate( SemaforoBlink, "Semaforo", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, NULL )!=pdPASS) while (1); vTaskStartScheduler(); // Inicia el planificador de tareas }
Os animo a que participéis, ya que es un proyecto, además de interesante, bastante divertido.
Sé el primero en comentar en «Semáforos y más semáforos»