Saltar al contenido
Nivel inicial

Construir y programar un semáforo

Realizar el montaje sencillo de un circuito en una protoboard

Colocamos un LED verde en la protoboard, como indica el esquema.

Esquema de conexión: placa Arduino UNO conectada a una protoboard con un LED verde y una resistencia de 220 ohm. Un cable rojo une el pin 13 con la pata larga del LED y un cable negro une GND con la línea de la resistencia.
Esquema 1 — Un LED verde en la protoboard, con su resistencia de 220 ohm (figura original del proyecto).

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 resistencia 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 Arduino UNO, y la línea de GND de la protoboard a uno de los pines GND de la placa.

En la placa ESP32 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.

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:

  1. 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().
  2. Un bloque de código que se ejecuta repetidamente luego de setup(). Este bloque está contenido dentro de la función loop().

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 de setup(), que ese pin va a usarse como salida.
  • digitalWrite(pin, HIGH) enciende la salida (y con LOW la apaga).
  • delay(1000) detiene el programa durante 1000 milisegundos, es decir, un segundo.
Ver el código completo · parpadeo.ino
parpadeo.ino Arduino UNO
// 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.ino ESP32
// 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);
}
Primer programa: el LED parpadea en intervalos de un segundo.

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.

Subir el código a la placa

Para subir el código de nuestro programa a la placa, necesitamos:

  1. Conectar la placa a la computadora con el cable USB.
  2. Chequear que en el selector de placa del Arduino IDE esté seleccionada la placa correcta.
  3. Seleccionar el puerto al que está conectada la placa.
  4. 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.

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.

Esquema de conexión: Arduino UNO con tres LED (verde, amarillo y rojo) en la protoboard, cada uno con su resistencia de 220 ohm hacia la línea de GND.
Esquema 2 — El circuito expandido a tres LED, uno por cada luz del semáforo (figura original del proyecto).

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
semaforo-simple.ino Arduino UNO
// 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.
}
semaforo-simple.ino ESP32
// 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.
}
El semáforo completo: la secuencia de las tres luces con sus tiempos.

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.

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.

Render del modelo 3D del cuerpo del semáforo: una pieza vertical con tres alojamientos circulares para los LED y una base de encastre.
El modelo 3D original del semáforo, diseñado para alojar los tres LED (figura original del proyecto).

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 .stl. 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 G: 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.

Render translúcido del modelo 3D del semáforo donde se ven los tres LED (rojo, amarillo y verde) alojados en su interior con sus cables bajando por el poste.
Los tres LED soldados y alojados dentro del cuerpo del semáforo; los cables bajan por el poste hacia la placa (figura original del proyecto).

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).