Construir y programar un semáforo
Recorrido del nivel
Esa barra de arriba te dice en qué paso estás. Tocala para ver el índice completo y saltar a cualquier paso.
Realizar el montaje sencillo de un circuito en una protoboard
Colocamos un LEDLEDComponente electrónico tipo diodo que emite luz. Tiene polaridad: la pata larga es la positiva y la corta (o el lado plano del encapsulado) la negativa. Conectado al revés no se daña, pero no enciende. verde en la protoboardProtoboardPlaca experimental para el prototipado rápido de circuitos: sus orificios permiten insertar y conectar componentes sin soldadura. Las líneas superior e inferior recorren la placa de punta a punta y suelen usarse para la alimentación., como indica el esquema.
En un LED, la pata larga siempre es la pata positiva y es donde se conecta nuestro pin. La pata corta es la negativa; también podés reconocerla por el lado plano del encapsulado. Si lo conectás con la polaridad invertida no se va a romper, pero tampoco va a encender.
La resistenciaResistenciaComponente que se opone al paso de la corriente eléctrica. Su valor se mide en ohm (Ω). Se usa para determinar la cantidad de corriente de una rama del circuito, por ejemplo para evitar que un LED se queme por exceso de corriente. de 220 ohm limita la cantidad de corriente que circula por esa rama del circuito: sin ella, el LED podría quemarse por exceso de corriente. Va conectada entre la pata corta del LED y la línea de GND de la protoboard.
Conectamos la pata larga del LED al pin 13 de la placa ArduinoArduinoPlaca electrónica con un microcontrolador programable y comunicación USB/serial. Desde la computadora, un IDE permite escribir el código, compilarlo y cargarlo en la placa. Tiene entradas y salidas digitales (0 a 13) y entradas analógicas (A0 a A5). UNO, y la línea de GND de la protoboard a uno de los pines GND de la placa.
En la placa ESP32ESP32Placa con un microcontrolador de Espressif que trae WiFi (y Bluetooth) integrados. Se programa desde el Arduino IDE igual que un Arduino, con pines llamados GPIO. En este proyecto reemplaza al conjunto Arduino UNO + módulo OBLOQ para el nivel IoT. el armado es el mismo, pero los pines se llaman
GPIO y usamos otros números (los GPIO 0, 2, 12 y 15 se reservan porque intervienen en el
arranque de la placa). Conectá la pata larga del LED al GPIO que indica la constante
PIN_LED al comienzo del código del paso siguiente, y la línea de GND de la protoboard a
un pin GND de la placa.
Antes de pasar al programa, podés explorar el circuito completo del semáforo en el simulador. Es el mismo esquema que vas a armar sobre la mesa, y responde al comportamiento real del código:
Simulación del comportamiento
La misma máquina de estados del firmware, portada a TypeScript, maneja el
comportamiento del dispositivo. No se ejecuta el binario real: la ejecución
del .hex con avr8js está en el roadmap.
Simulación lista. Presioná «Iniciar» para arrancar la secuencia.
Verificá
Todavía no cargamos ningún programa, así que el LED no va a encender. Antes de seguir, revisá: la pata larga del LED va hacia el cable que llega al pin de la placa, la resistencia conecta la pata corta con la línea de GND, y esa línea llega a un pin GND de la placa.
Escribir tu primer programa
Ahora vamos a escribir el programa que hace parpadear el LED que acabamos de conectar. La programación la realizaremos directamente en el lenguaje de Arduino (C++), usando el Arduino IDE en su versión 2.x, que se descarga gratis desde arduino.cc/en/software. IDE proviene de la sigla en inglés de entorno de desarrollo integrado: es el programa donde escribimos el código, lo compilamos y lo enviamos a la placa.
Un programa de Arduino se llama sketch y tiene una estructura mínima de dos bloques:
- Un bloque de código que se ejecuta por única vez al inicializarse el dispositivo. Este
bloque está contenido dentro de la función
setup(). - Un bloque de código que se ejecuta repetidamente luego de
setup(). Este bloque está contenido dentro de la funciónloop().
Después de // se incluyen comentarios para el lector, que no tienen ningún efecto en el
programa. Estos comentarios sirven para clarificar el código y que sea más fácil de
interpretar para otras personas.
Con esa estructura, nuestro primer programa necesita tres ideas nuevas, una por línea:
pinMode(pin, OUTPUT)le avisa a la placa, dentro desetup(), que ese pin va a usarse como salida.digitalWrite(pin, HIGH)enciende la salida (y conLOWla apaga).delay(1000)detiene el programa durante 1000 milisegundos, es decir, un segundo.
Ver el código completo · parpadeo.ino
// Parpadeo de un LED: el "Hola Mundo" de la electrónica.
// Enciende y apaga un LED cada 1 segundo.
//
// Plataforma: Arduino UNO. El pin 13 tiene un LED integrado en la placa,
// así que este programa funciona incluso antes de conectar el LED externo.
//
// Basado en: Fragmento de código 1 — Sistema de Semaforización,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: se reemplazó el código generado por mBlock3 (_delay, _loop)
// por C++ idiomático de Arduino, con constantes nombradas para pin y tiempos.
// Constantes con nombre en lugar de "números mágicos": si mañana movemos
// el LED a otro pin o queremos otro ritmo, tocamos UNA línea acá arriba
// y no hace falta revisar el resto del programa. Este hábito es la base
// de todos los programas que siguen en la guía.
const int PIN_LED = 13; // LED integrado del UNO
const unsigned long DURACION_ENCENDIDO_MS = 1000;
const unsigned long DURACION_APAGADO_MS = 1000;
void setup() {
// Un pin digital puede leer o escribir. Acá declaramos que este pin
// va a ESCRIBIR (encender y apagar el LED).
pinMode(PIN_LED, OUTPUT);
}
void loop() {
// delay() detiene TODO el programa durante ese tiempo. Para un primer
// programa es ideal: el código se lee de arriba hacia abajo igual que
// la secuencia real de la luz. En el nivel avanzado veremos por qué
// esto se vuelve un problema (código "bloqueante") y cómo resolverlo
// con millis().
digitalWrite(PIN_LED, HIGH); // encender
delay(DURACION_ENCENDIDO_MS);
digitalWrite(PIN_LED, LOW); // apagar
delay(DURACION_APAGADO_MS);
} // Parpadeo de un LED: el "Hola Mundo" de la electrónica.
// Enciende y apaga un LED cada 1 segundo.
//
// Plataforma: ESP32 (DevKit v1). El GPIO 2 tiene un LED azul integrado
// en la placa, así que este programa funciona incluso antes de conectar
// el LED externo.
// Nota eléctrica: el ESP32 trabaja a 3,3 V (no 5 V como el UNO). Con la
// misma resistencia de 220 ohm el LED enciende un poco más tenue, y NUNCA
// hay que inyectar 5 V en un GPIO del ESP32: se puede dañar la placa.
//
// Basado en: Fragmento de código 1 — Sistema de Semaforización,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: se reemplazó el código generado por mBlock3 (_delay, _loop)
// por C++ idiomático de Arduino con constantes nombradas, y se portó la
// guía (pensada para Arduino UNO) a ESP32.
// Constantes con nombre en lugar de "números mágicos": si mañana movemos
// el LED a otro pin o queremos otro ritmo, tocamos UNA línea acá arriba
// y no hace falta revisar el resto del programa. Este hábito es la base
// de todos los programas que siguen en la guía.
const int PIN_LED = 2; // LED integrado del DevKit v1
const unsigned long DURACION_ENCENDIDO_MS = 1000;
const unsigned long DURACION_APAGADO_MS = 1000;
void setup() {
// Un pin digital puede leer o escribir. Acá declaramos que este pin
// va a ESCRIBIR (encender y apagar el LED).
pinMode(PIN_LED, OUTPUT);
}
void loop() {
// delay() detiene TODO el programa durante ese tiempo. Para un primer
// programa es ideal: el código se lee de arriba hacia abajo igual que
// la secuencia real de la luz. En el nivel avanzado veremos por qué
// esto se vuelve un problema (código "bloqueante") y cómo resolverlo
// con millis().
digitalWrite(PIN_LED, HIGH); // encender
delay(DURACION_ENCENDIDO_MS);
digitalWrite(PIN_LED, LOW); // apagar
delay(DURACION_APAGADO_MS);
} Leelo en voz alta como si fuera una receta: “encendé la luz, esperá un segundo, apagala,
esperá un segundo… y volvé a empezar”. Eso es exactamente lo que loop() repite sin
descanso mientras la placa tenga energía. Antes de cargarlo en la placa, podés probar el
mismo comportamiento en el simulador del paso anterior.
Para el aula
El material original de 2019 enseñaba este paso con bloques en mBlock3, que hoy está discontinuado. La función didáctica de los bloques —bajar la barrera de entrada— la cumple acá la combinación de un código muy corto, comentado línea por línea, y el simulador en el navegador, que permite equivocarse sin miedo antes de tocar la placa. La experiencia de aula muestra que un sketch de ocho líneas leído como receta es tan abordable como el programa de bloques equivalente, y evita la transición posterior bloques → código, que el propio original ya señalaba como necesaria en el nivel superior.
Verificá
En el Arduino IDE, apretá el botón de verificar (el tilde ✓). Si abajo aparece “Compilación completada” sin mensajes en rojo, tu programa está bien escrito. Si aparece un error, revisá los punto y coma al final de cada línea y que las llaves abran y cierren.
Subir el código a la placa
Para subir el código de nuestro programa a la placa, necesitamos:
- Conectar la placa a la computadora con el cable USB.
- Chequear que en el selector de placa del Arduino IDE esté seleccionada la placa correcta.
- Seleccionar el puertoPuerto COMPuerto de comunicaciones por el cual el sistema operativo se comunica con un dispositivo externo, como la placa. Se asigna automáticamente al conectarla por USB y puede cambiar de número; en el IDE hay que indicar cuál usar. al que está conectada la placa.
- Cliquear el botón Subir (la flecha →) en la parte superior de la interfaz.
En el Arduino IDE 2.x, la placa y el puerto se eligen juntos en el menú desplegable de la barra superior: al conectar la placa suele aparecer directamente como opción. Si no aparece, entrá a “Select other board and port” y buscala por nombre.
Para el Arduino UNO: usá el cable USB tipo B, elegí la placa Arduino UNO y el puerto
que se agregó al conectarla (en Windows es un puerto COM numerado; en Linux suele
llamarse /dev/ttyACM0 o similar).
Para el ESP32 hay dos pasos previos que se hacen una sola vez: instalar el soporte de placas ESP32 desde el gestor de placas del IDE (buscá “esp32” e instalá el paquete de Espressif) y, si el puerto no aparece, instalar el driver del conversor USB-serie de tu placa (generalmente CP210x o CH340). Después, elegí la placa ESP32 Dev Module (o “DOIT ESP32 DEVKIT V1”) y el puerto correspondiente. Si al subir el IDE queda esperando en “Connecting…”, mantené apretado el botón BOOT de la placa hasta que empiece la carga.
Al terminar de subir nuestro código, veremos el mensaje de carga completada en la barra inferior del IDE.
Verificá
Con la conexión previamente realizada, el LED debería encenderse y apagarse siguiendo intervalos de un segundo. Si no parpadea, repasá la polaridad del LED y que el pin del código sea el mismo al que conectaste el cable.
Expandir el circuito a tres LED
Continuamos agregando tres LED, uno de cada color (verde, amarillo y rojo), con sus respectivas resistencias de 220 ohm, como indica el circuito.
Colocamos todas las resistencias hacia la línea de GND de la protoboard, que se conecta al pin GND de la placa.
Conectamos el LED rojo al pin 13, el amarillo al pin 12 y el verde al pin 11.
En el ESP32 usamos tres GPIO de propósito general seguros para salidas. Los números
exactos están en las constantes PIN_LED_ROJO, PIN_LED_AMARILLO y PIN_LED_VERDE
al comienzo del código: conectá cada LED al GPIO que indica su constante.
Ahora modificamos el programa anterior para que realice ciclos de encendido y apagado para las luces de los tres colores, con los intervalos de demora de un semáforo real: verde 5 segundos, amarillo 1 segundo, rojo 5 segundos y, antes de volver al verde, rojo y amarillo juntos durante 1 segundo (el aviso de “preparate para avanzar”).
Ver el código completo · semaforo-simple.ino
// Semáforo simple de tres luces (un solo semáforo).
// Secuencia: verde 5 s → amarillo 1 s → rojo 5 s → rojo+amarillo 1 s,
// y vuelve a empezar. La fase rojo+amarillo avisa que está por venir
// el verde, como en los semáforos reales de varios países.
//
// Plataforma: Arduino UNO.
// Conexión: LED verde → pin 11, LED amarillo → pin 12, LED rojo → pin 13,
// cada uno con su resistencia de 220 ohm a GND.
//
// Basado en: Fragmento de código 2 — Sistema de Semaforización,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: se reemplazó el código generado por mBlock3 (_delay, _loop)
// por C++ idiomático de Arduino, con constantes nombradas para pines y tiempos.
// Pines del semáforo 1 (los mismos del esquema original de la guía).
const int PIN_SEM1_VERDE = 11;
const int PIN_SEM1_AMARILLO = 12;
const int PIN_SEM1_ROJO = 13;
// Tiempos de cada fase. Son los MISMOS en toda la guía (y en el simulador):
// si acá se cambian, el comportamiento deja de coincidir con el resto.
const unsigned long DURACION_VERDE_MS = 5000;
const unsigned long DURACION_AMARILLO_MS = 1000;
const unsigned long DURACION_ROJO_MS = 5000;
const unsigned long DURACION_ROJO_AMARILLO_MS = 1000;
void setup() {
pinMode(PIN_SEM1_VERDE, OUTPUT);
pinMode(PIN_SEM1_AMARILLO, OUTPUT);
pinMode(PIN_SEM1_ROJO, OUTPUT);
}
void loop() {
// En cada fase escribimos las TRES luces, aunque alguna no cambie:
// así cada bloque describe el estado completo del semáforo y no hay
// que "acordarse" de qué quedó encendido en la fase anterior.
// Fase 1: VERDE — los autos circulan.
digitalWrite(PIN_SEM1_VERDE, HIGH);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, LOW);
delay(DURACION_VERDE_MS);
// Fase 2: AMARILLO — atención, prepararse para frenar.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, LOW);
delay(DURACION_AMARILLO_MS);
// Fase 3: ROJO — detenerse.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
delay(DURACION_ROJO_MS);
// Fase 4: ROJO + AMARILLO — aviso de que está por venir el verde.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, HIGH);
delay(DURACION_ROJO_AMARILLO_MS);
// Al terminar la fase 4, loop() vuelve a ejecutarse desde arriba:
// ese "volver a empezar" automático es lo que hace el ciclo infinito.
} // Semáforo simple de tres luces (un solo semáforo).
// Secuencia: verde 5 s → amarillo 1 s → rojo 5 s → rojo+amarillo 1 s,
// y vuelve a empezar. La fase rojo+amarillo avisa que está por venir
// el verde, como en los semáforos reales de varios países.
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: LED verde → GPIO 16, LED amarillo → GPIO 17, LED rojo → GPIO 18,
// cada uno con su resistencia de 220 ohm a GND.
// Nota eléctrica: el ESP32 trabaja a 3,3 V (no 5 V como el UNO). Con la
// misma resistencia de 220 ohm los LED encienden un poco más tenues, y
// NUNCA hay que inyectar 5 V en un GPIO del ESP32.
//
// Basado en: Fragmento de código 2 — Sistema de Semaforización,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: se reemplazó el código generado por mBlock3 (_delay, _loop)
// por C++ idiomático de Arduino con constantes nombradas, y se portó a ESP32
// usando GPIO seguros (16/17/18, lejos de los pines de arranque o "strapping").
// Pines del semáforo 1.
const int PIN_SEM1_VERDE = 16;
const int PIN_SEM1_AMARILLO = 17;
const int PIN_SEM1_ROJO = 18;
// Tiempos de cada fase. Son los MISMOS en toda la guía (y en el simulador):
// si acá se cambian, el comportamiento deja de coincidir con el resto.
const unsigned long DURACION_VERDE_MS = 5000;
const unsigned long DURACION_AMARILLO_MS = 1000;
const unsigned long DURACION_ROJO_MS = 5000;
const unsigned long DURACION_ROJO_AMARILLO_MS = 1000;
void setup() {
pinMode(PIN_SEM1_VERDE, OUTPUT);
pinMode(PIN_SEM1_AMARILLO, OUTPUT);
pinMode(PIN_SEM1_ROJO, OUTPUT);
}
void loop() {
// En cada fase escribimos las TRES luces, aunque alguna no cambie:
// así cada bloque describe el estado completo del semáforo y no hay
// que "acordarse" de qué quedó encendido en la fase anterior.
// Fase 1: VERDE — los autos circulan.
digitalWrite(PIN_SEM1_VERDE, HIGH);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, LOW);
delay(DURACION_VERDE_MS);
// Fase 2: AMARILLO — atención, prepararse para frenar.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, LOW);
delay(DURACION_AMARILLO_MS);
// Fase 3: ROJO — detenerse.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
delay(DURACION_ROJO_MS);
// Fase 4: ROJO + AMARILLO — aviso de que está por venir el verde.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, HIGH);
delay(DURACION_ROJO_AMARILLO_MS);
// Al terminar la fase 4, loop() vuelve a ejecutarse desde arriba:
// ese "volver a empezar" automático es lo que hace el ciclo infinito.
} Fijate que el programa es una estructura secuencial: las órdenes se ejecutan una detrás
de la otra, en el orden exacto en que están escritas, y al llegar al final loop() vuelve a
empezar. Ese orden es la “coreografía” del semáforo.
Podés volver al simulador del paso 1 para comparar el comportamiento esperado con el de tu circuito real.
Los tiempos de tu semáforo
Los intervalos del modelo son un punto de partida. Observen con el grupo un semáforo real cercano y cronometren cuánto dura cada luz. Después, modifiquen los valores de demora del programa para que el prototipo imite al semáforo observado. ¿Qué pasa si el amarillo dura demasiado poco? ¿Y si el verde de una calle muy transitada dura demasiado?
Verificá
El semáforo debería repetir en ciclo: verde 5 segundos → amarillo 1 segundo → rojo 5 segundos → rojo y amarillo juntos 1 segundo → verde otra vez. Si algún color no enciende, revisá su resistencia y su pin; si encienden en el orden equivocado, revisá qué pin quedó asignado a cada color en el código.
Soldar y ensamblar la maqueta
En este momento se procederá a construir la maqueta del semáforo. Para ello se debe soldar cada componente e imprimir el modelo 3D del semáforo que alojará el circuito de las luces. Tené en cuenta que si se pretende seguir con el nivel intermedio y agregar un segundo semáforo, puede resultar más conveniente saltar este paso y continuar con los siguientes, para programar la conexión de los dos semáforos en la protoboard antes del armado final.
Para armar la maqueta, se deben imprimir las piezas en la impresora 3D. El modelo original del semáforo se distribuía de forma libre y gratuita en el repositorio Saberes Digitales; sus archivos están en re-publicación como paquete de fabricación de este proyecto (vas a encontrarlo en la ficha, junto con un rediseño de la maqueta para corte láser en MDF de 3 mm). Cuando estén listas todas las piezas, las ensamblamos para construir el semáforo.
En caso de querer realizar una modificación en el modelo, independientemente del programa de modelado que utilicemos, debemos exportar nuestras piezas en formato .stlFormato .stlFormato de archivo que contiene la forma de un objeto sólido 3D, sin color, texturas ni propiedades físicas. Es el más usado para intercambiar e imprimir modelos 3D; funciona como la 'exportación final' de un diseño, como un PDF de un documento de texto.. El .stl es un formato de archivo de diseño asistido por computadora (CAD) que define la geometría de objetos sólidos 3D; es el más popular a la hora de intercambiar digitalmente modelos para ser impresos en 3D. El programa laminador de la impresora convierte ese .stl en código GCódigo GConjunto de acciones que la impresora 3D (o cualquier máquina CNC) debe realizar para completar un trabajo. Se genera analizando un archivo STL, y es específico de cada modelo de impresora.: las instrucciones de movimiento que tu impresora ejecuta para materializar la pieza.
Una vez que las conexiones han sido probadas y el sistema de luces funciona correctamente, podemos pasar a armar los circuitos de la maqueta prescindiendo de la protoboard. Para hacerlo, soldamos cada LED con su cable y su resistencia. Luego, lo colocamos dentro de la pieza correspondiente del semáforo.
Verificá
Con los LED ya soldados y montados en la maqueta, volvé a conectar la placa: la secuencia del paso 4 tiene que seguir funcionando igual que en la protoboard. Una soldadura fría (opaca, granulosa) suele ser la causa de una luz que titila o no enciende.
Cierre del nivel
Al terminar este nivel, tu semáforo tiene que estar funcionando solo: el circuito de tres LED montado con sus resistencias, el programa cargado desde el Arduino IDE, y la secuencia verde → amarillo → rojo → rojo + amarillo repitiéndose en ciclo con sus tiempos. Si además ensamblaste la maqueta impresa en 3D, ya tenés un prototipo digno de una esquina de verdad. En el nivel intermedio ese semáforo deja de estar solo: vamos a sumarle el segundo semáforo de la intersección y a sincronizarlos.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- El circuito de tres LED (rojo, amarillo y verde) está montado en la protoboard, cada uno con su resistencia de 220 ohm y con la polaridad correcta.
- La placa ejecuta el programa del semáforo: verde 5 segundos, amarillo 1 segundo, rojo 5 segundos y rojo + amarillo 1 segundo, en un ciclo que se repite solo.
- Sabés subir un programa desde el Arduino IDE 2.x: elegir la placa, elegir el puerto y verificar que el código quedó cargado.
- La maqueta del semáforo está ensamblada con los LED soldados (o el paso quedó planificado para después del nivel intermedio).