Dos semáforos sincronizados en una intersección
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.
Armar el circuito de la intersección
Para armar la intersección con dos semáforos debemos conectar a 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. tres 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. más que en el circuito anterior (rojo, amarillo y verde), con sus respectivas resistenciasResistenciaComponente 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 hacia la línea de GND.
El primer semáforo conserva sus pines del nivel inicial (rojo 13, amarillo 12, verde 11). Para el segundo semáforo conectaremos el LED rojo al pin 10, el amarillo al pin 9 y el verde al pin 8.
En el 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., cada uno de los seis LED va a un GPIO de salida
seguro. Los números exactos están en las constantes del comienzo del código
(PIN_S1_ROJO, PIN_S1_AMARILLO, PIN_S1_VERDE, PIN_S2_ROJO, PIN_S2_AMARILLO,
PIN_S2_VERDE): conectá cada LED al GPIO que indica su constante.
Podés recorrer el circuito completo, con los dos semáforos funcionando en la esquina, en el simulador:
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.
Programar la secuencia para dos semáforos
En este momento vamos a sumar la secuencia de nuestro segundo semáforo al código previamente armado. La planificación de la secuencia para dos semáforos es más compleja, por lo que requiere que se le dedique un poco más de tiempo a su armado y comprensión.
Para pensar cómo armar el código, es posible imaginar esta secuencia como viñetas de un cómic en donde hay una serie de acciones a realizar y una demora entre cuadro y cuadro. Cada viñeta muestra la esquina congelada en un instante: qué luz tiene cada semáforo y cuánto tiempo dura ese cuadro antes de pasar al siguiente.
| Viñeta | Semáforo 1 | Semáforo 2 | Demora |
|---|---|---|---|
| Nº 1 | Verde | Rojo | 5 s |
| Nº 2 | Amarillo | Rojo | 1 s |
| Nº 3 | Rojo | Rojo | 1 s |
| Nº 4 | Rojo | Rojo + amarillo | 1 s |
| Nº 5 | Rojo | Verde | 5 s |
| Nº 6 | Rojo | Amarillo | 1 s |
| Nº 7 | Rojo | Rojo | 1 s |
| Nº 8 | Rojo + amarillo | Rojo | 1 s |
| Nº 9 | Verde | Rojo | — |
Como se puede ver en la tabla, el cuadro Nº 9 es igual al cuadro Nº 1: es en ese punto donde comienza a repetirse la secuencia. Por lo tanto, en total tenemos ocho pasos que se repiten y una determinada demora en cada paso.
Dos detalles de esta coreografía merecen atención:
- Nunca las dos calles tienen verde a la vez: cuando un semáforo habilita el paso, el otro está en rojo.
- En las viñetas Nº 3 y Nº 7 ambos semáforos están en rojo durante un segundo. Ese respiro le da tiempo al último vehículo a despejar la bocacalle antes de habilitar a la calle transversal.
Traducimos las ocho viñetas al programa: cada viñeta es un grupo de órdenes de encendido y apagado seguido de su demora, en estructura secuencial.
Ver el código completo · interseccion.ino
// Intersección con dos semáforos sincronizados (6 LED).
// Recorre los 8 cuadros del "cómic" de la Fig. 10 de la guía original:
//
// Cuadro | Semáforo 1 | Semáforo 2 | Duración
// -------+-----------------+-----------------+---------
// 1 | VERDE | ROJO | 5 s
// 2 | AMARILLO | ROJO | 1 s
// 3 | ROJO | ROJO | 1 s (todo rojo)
// 4 | ROJO | ROJO + AMARILLO | 1 s
// 5 | ROJO | VERDE | 5 s
// 6 | ROJO | AMARILLO | 1 s
// 7 | ROJO | ROJO | 1 s (todo rojo)
// 8 | ROJO + AMARILLO | ROJO | 1 s
//
// El cuadro 9 es igual al 1: ahí la secuencia vuelve a empezar.
// Los cuadros 3 y 7 dejan TODO en rojo un instante: es el margen de
// seguridad para que la intersección se vacíe antes de habilitar la
// otra calle. Ningún semáforo real pasa de verde a verde sin ese margen.
//
// Plataforma: Arduino UNO.
// Conexión: semáforo 1 → verde 11, amarillo 12, rojo 13;
// semáforo 2 → verde 8, amarillo 9, rojo 10 (como en la guía).
//
// Basado en: Fragmento de código 3 — 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. Además, cada
// cuadro escribe las SEIS luces completas (el original solo escribía los
// pines que cambiaban): así cada bloque de código se corresponde 1 a 1
// con un cuadro del cómic y puede leerse de forma aislada.
// Semáforo 1 (calle principal).
const int PIN_SEM1_VERDE = 11;
const int PIN_SEM1_AMARILLO = 12;
const int PIN_SEM1_ROJO = 13;
// Semáforo 2 (calle transversal).
const int PIN_SEM2_VERDE = 8;
const int PIN_SEM2_AMARILLO = 9;
const int PIN_SEM2_ROJO = 10;
// Tiempos de la secuencia (los mismos de toda la guía y del simulador).
const unsigned long DURACION_VERDE_MS = 5000;
const unsigned long DURACION_AMARILLO_MS = 1000;
const unsigned long DURACION_TODO_ROJO_MS = 1000; // margen de seguridad
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);
pinMode(PIN_SEM2_VERDE, OUTPUT);
pinMode(PIN_SEM2_AMARILLO, OUTPUT);
pinMode(PIN_SEM2_ROJO, OUTPUT);
}
void loop() {
// Cuadro 1: Semáforo 1 VERDE / Semáforo 2 ROJO.
digitalWrite(PIN_SEM1_VERDE, HIGH);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, LOW);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_VERDE_MS);
// Cuadro 2: Semáforo 1 AMARILLO / Semáforo 2 ROJO.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, LOW);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_AMARILLO_MS);
// Cuadro 3: TODO ROJO — la intersección se vacía antes del cambio.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_TODO_ROJO_MS);
// Cuadro 4: Semáforo 1 ROJO / Semáforo 2 ROJO + AMARILLO (por arrancar).
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, HIGH);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_ROJO_AMARILLO_MS);
// Cuadro 5: Semáforo 1 ROJO / Semáforo 2 VERDE — ahora circula la otra calle.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, HIGH);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, LOW);
delay(DURACION_VERDE_MS);
// Cuadro 6: Semáforo 1 ROJO / Semáforo 2 AMARILLO.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, HIGH);
digitalWrite(PIN_SEM2_ROJO, LOW);
delay(DURACION_AMARILLO_MS);
// Cuadro 7: TODO ROJO — otra vez el margen de seguridad.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_TODO_ROJO_MS);
// Cuadro 8: Semáforo 1 ROJO + AMARILLO / Semáforo 2 ROJO.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_ROJO_AMARILLO_MS);
// loop() vuelve a empezar: el cuadro 9 del cómic es igual al cuadro 1.
} // Intersección con dos semáforos sincronizados (6 LED).
// Recorre los 8 cuadros del "cómic" de la Fig. 10 de la guía original:
//
// Cuadro | Semáforo 1 | Semáforo 2 | Duración
// -------+-----------------+-----------------+---------
// 1 | VERDE | ROJO | 5 s
// 2 | AMARILLO | ROJO | 1 s
// 3 | ROJO | ROJO | 1 s (todo rojo)
// 4 | ROJO | ROJO + AMARILLO | 1 s
// 5 | ROJO | VERDE | 5 s
// 6 | ROJO | AMARILLO | 1 s
// 7 | ROJO | ROJO | 1 s (todo rojo)
// 8 | ROJO + AMARILLO | ROJO | 1 s
//
// El cuadro 9 es igual al 1: ahí la secuencia vuelve a empezar.
// Los cuadros 3 y 7 dejan TODO en rojo un instante: es el margen de
// seguridad para que la intersección se vacíe antes de habilitar la
// otra calle. Ningún semáforo real pasa de verde a verde sin ese margen.
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: semáforo 1 → verde GPIO 16, amarillo GPIO 17, rojo GPIO 18;
// semáforo 2 → verde GPIO 19, amarillo GPIO 21, rojo GPIO 22.
// Nota eléctrica: el ESP32 trabaja a 3,3 V (no 5 V como el UNO); nunca
// inyectar 5 V en un GPIO.
//
// Basado en: Fragmento de código 3 — 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
// con GPIO seguros (se evitan los pines de arranque o "strapping"). Además,
// cada cuadro escribe las SEIS luces completas (el original solo escribía
// los pines que cambiaban): así cada bloque de código se corresponde 1 a 1
// con un cuadro del cómic y puede leerse de forma aislada.
// Semáforo 1 (calle principal).
const int PIN_SEM1_VERDE = 16;
const int PIN_SEM1_AMARILLO = 17;
const int PIN_SEM1_ROJO = 18;
// Semáforo 2 (calle transversal).
const int PIN_SEM2_VERDE = 19;
const int PIN_SEM2_AMARILLO = 21;
const int PIN_SEM2_ROJO = 22;
// Tiempos de la secuencia (los mismos de toda la guía y del simulador).
const unsigned long DURACION_VERDE_MS = 5000;
const unsigned long DURACION_AMARILLO_MS = 1000;
const unsigned long DURACION_TODO_ROJO_MS = 1000; // margen de seguridad
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);
pinMode(PIN_SEM2_VERDE, OUTPUT);
pinMode(PIN_SEM2_AMARILLO, OUTPUT);
pinMode(PIN_SEM2_ROJO, OUTPUT);
}
void loop() {
// Cuadro 1: Semáforo 1 VERDE / Semáforo 2 ROJO.
digitalWrite(PIN_SEM1_VERDE, HIGH);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, LOW);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_VERDE_MS);
// Cuadro 2: Semáforo 1 AMARILLO / Semáforo 2 ROJO.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, LOW);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_AMARILLO_MS);
// Cuadro 3: TODO ROJO — la intersección se vacía antes del cambio.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_TODO_ROJO_MS);
// Cuadro 4: Semáforo 1 ROJO / Semáforo 2 ROJO + AMARILLO (por arrancar).
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, HIGH);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_ROJO_AMARILLO_MS);
// Cuadro 5: Semáforo 1 ROJO / Semáforo 2 VERDE — ahora circula la otra calle.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, HIGH);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, LOW);
delay(DURACION_VERDE_MS);
// Cuadro 6: Semáforo 1 ROJO / Semáforo 2 AMARILLO.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, HIGH);
digitalWrite(PIN_SEM2_ROJO, LOW);
delay(DURACION_AMARILLO_MS);
// Cuadro 7: TODO ROJO — otra vez el margen de seguridad.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, LOW);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_TODO_ROJO_MS);
// Cuadro 8: Semáforo 1 ROJO + AMARILLO / Semáforo 2 ROJO.
digitalWrite(PIN_SEM1_VERDE, LOW);
digitalWrite(PIN_SEM1_AMARILLO, HIGH);
digitalWrite(PIN_SEM1_ROJO, HIGH);
digitalWrite(PIN_SEM2_VERDE, LOW);
digitalWrite(PIN_SEM2_AMARILLO, LOW);
digitalWrite(PIN_SEM2_ROJO, HIGH);
delay(DURACION_ROJO_AMARILLO_MS);
// loop() vuelve a empezar: el cuadro 9 del cómic es igual al cuadro 1.
} La esquina de tu escuela
Adapten la secuencia a una esquina real: elijan una intersección conocida donde una calle tenga mucho más tránsito que la otra y decidan, con argumentos, cuánto verde le corresponde a cada una. Modifiquen las demoras del programa y defiendan su propuesta ante el resto de los grupos como si fueran la oficina de tránsito del municipio.
Verificá
Observá el ciclo completo, de punta a punta, un par de veces: mientras un semáforo está en verde o amarillo, el otro tiene que estar en rojo; entre el rojo de uno y el verde del otro tiene que aparecer el segundo de “todo rojo”; y antes de cada verde tiene que verse el rojo + amarillo. Si dos luces del mismo semáforo quedan encendidas fuera de esos momentos, revisá el orden de las órdenes en esa viñeta.
Cierre del nivel
Al terminar este nivel, la intersección completa funciona con una sola placa: los seis LED conectados, y los dos semáforos recorriendo en ciclo la secuencia de ocho estados, con sus momentos de “todo rojo” y de rojo + amarillo. Además, podés contar la secuencia cuadro a cuadro, como un cómic, que es la mejor prueba de que la entendiste. Si habías postergado la soldadura y el ensamblado de las maquetas, este es el momento de retomar el paso 5 del nivel inicial para las dos columnas. En el nivel avanzado, la central de tránsito va a poder mirar esta esquina desde internet: vamos a sumarle Internet de las Cosas.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- Los seis LED de la intersección (dos semáforos completos) están conectados a una sola placa, cada uno con su resistencia.
- Los dos semáforos recorren la secuencia completa de ocho estados en ciclo, sin habilitar nunca las dos calles al mismo tiempo.
- Podés explicar la secuencia cuadro a cuadro, como las viñetas de un cómic, incluyendo los momentos en que ambos semáforos quedan en rojo.