Ejercicio 04 — Umbral

Dificultad: amarillo · Módulo 04 (Entradas analogicas)

Enunciado

Umbral. Si está oscuro (LDR por debajo de un umbral) enciende un LED; si hay luz, lo apaga.

Montaje (Arduino UNO)

LDR en divisor A0 (como ej03) | LED en pin 8 220ohm GND

Cómo se resuelve

El reto del módulo, y el primer programa del curso que decide algo por sí mismo a partir del mundo real: una luz de emergencia que se enciende sola cuando oscurece. Todas las piezas ya las tienes; lo nuevo es juntarlas con un if.

El montaje es el del ejercicio 03 más un LED. La LDR sigue en su divisor con la resistencia de 10 kΩ y el nodo central en A0, y el LED va del pin 8 a una resistencia de 220 Ω y de ahí al ánodo, con el cátodo a GND. Fíjate en que aquí el LED está en el pin 8, que no es un pin PWM, y no pasa nada: en este ejercicio el LED solo se enciende o se apaga, no se regula. Elegir un pin normal cuando no necesitas PWM es lo correcto; los pines con ~ son un recurso limitado y se reservan para cuando hagan falta.

Las tres constantes de arriba definen el sistema entero:

const int PIN_LDR = A0;     // lectura de luz
const int PIN_LED = 8;      // LED indicador (salida digital ON/OFF)
const int UMBRAL  = 400;    // ajusta según tu montaje/iluminación (0..1023)

Que el umbral esté ahí arriba, con nombre y en mayúsculas, junto a los pines, es una decisión de diseño y no una manía de estilo. El umbral es un parámetro de configuración del sistema, exactamente igual que el número de pin: es lo que vas a tener que tocar cuando muevas el montaje a otra habitación. Enterrado dentro del if en forma de if (luz < 400) funcionaría igual, pero para cambiarlo habría que ir a buscarlo entre la lógica, y el número suelto no diría qué significa.

El 400 no es un valor sagrado. El propio comentario lo avisa: ajusta según tu montaje. Depende de tu LDR, de la resistencia fija que hayas puesto y de la luz que haya en tu mesa. La forma correcta de fijarlo es la que preparaste en el ejercicio 03: mira en el Serial qué valor da con luz y qué valor da tapando el sensor, y elige un número cómodo en medio de los dos. Si con luz lees 700 y tapado 150, un umbral de 400 es razonable; si tu montaje se mueve entre 150 y 300, el 400 haría que el LED estuviese encendido siempre, y no porque el código esté mal.

setup() prepara las dos cosas: Serial.begin(9600) para poder ver los valores, y pinMode(PIN_LED, OUTPUT) porque el pin 8 va a sacar corriente. Vuelve a verse el contraste del módulo: el pin de salida se configura, el pin analógico de entrada no.

El loop() es el patrón que vas a repetir el resto del curso: medir, informar, decidir, esperar.

int luz = analogRead(PIN_LDR);
Serial.print("Luz: ");  Serial.println(luz);
 
if (luz < UMBRAL) {                 // poca luz = oscuro
    digitalWrite(PIN_LED, HIGH);    // enciende el LED
} else {
    digitalWrite(PIN_LED, LOW);     // hay luz suficiente -> apaga
}
delay(200);

La comparación es luz < UMBRAL, con menor que, y el sentido depende directamente del cableado del divisor que viste en el ejercicio 03: con 5V → LDR → A0 → 10k → GND, menos luz significa número más pequeño, así que “estar por debajo del umbral” es “estar a oscuras”. Si hubieras montado el divisor al revés, la condición correcta sería luz > UMBRAL. Escribir el if sin haber comprobado antes hacia dónde se mueve el número es la forma más rápida de acabar con un sistema que hace justo lo contrario de lo que quieres.

El else no es opcional y conviene entender por qué. Sin él, el LED se encendería la primera vez que oscureciese y ya no se apagaría nunca: digitalWrite fija el estado del pin y ahí se queda hasta que alguien lo cambie. El pin no vuelve solo a LOW al empezar una nueva vuelta del loop(). Cada iteración tiene que dejar la salida en el estado que le corresponde a la lectura de ese momento, y eso significa decir explícitamente qué pasa en los dos casos. Es la misma idea del semáforo del módulo 01: un estado es “esto encendido y aquello apagado”, no solo “esto encendido”.

La línea de Serial no está de adorno ni es un resto de depuración que habría que quitar. Es lo que te permite calibrar el UMBRAL con el sistema funcionando: ves el número real y ves al mismo tiempo lo que hace el LED, así que puedes ajustar el corte con datos delante en vez de por prueba y error a ciegas.

Los 200 ms del final ponen el ritmo de reacción: cinco comprobaciones por segundo. Para una luz que responde a que anochezca es exageradamente rápido, y aun así es cómodo para probar tapando el sensor con la mano.

Cuando lo tengas funcionando, deja el sensor en una luz intermedia, justo en el filo del umbral, y observa: el LED se pone a parpadear de forma errática. No es un fallo tuyo. Las lecturas tiemblan un par de unidades por el ruido de la medida, y cuando el valor real está pegado al corte, unas veces cae a un lado y otras al otro. El problema tiene nombre y solución conocida: se llama histéresis, y consiste en usar dos umbrales separados, uno para encender (por ejemplo 380) y otro más alto para apagar (por ejemplo 420), de modo que una vez encendido haga falta un cambio apreciable de luz para volver atrás. Implementarlo es un buen ejercicio extra, y es la puerta a la idea de que un sistema que reacciona al mundo real tiene que ser tolerante al ruido del mundo real.

Para practicar — cópialo y complétalo

Pega este esqueleto y completa los TODO. Es la mejor forma de aprender: inténtalo antes de mirar la solución.

/*
 * Curso de Arduino — Módulo 04: Entradas analógicas
 * Ejercicio 04 — PRÁCTICA (rellena los TODO)  [reto del módulo]
 * Enunciado: Umbral. Si está oscuro (LDR por debajo de un umbral) enciende un LED; si hay luz, lo apaga.
 * Dificultad: amarillo
 * Placa: Arduino UNO
 * Montaje: LDR en divisor -> A0 (como ej03) | LED en pin 8 -> 220ohm -> GND
 * Correr: Arduino IDE / Wokwi (wokwi/ej04) / arduino-cli (ver README)
 */
const int PIN_LDR = A0;     // lectura de luz
const int PIN_LED = 8;      // LED indicador (salida digital ON/OFF)
const int UMBRAL  = 400;    // ajusta según tu montaje/iluminación (0..1023)
 
void setup() {
    // TODO: Serial.begin(9600)
    // TODO: pinMode(PIN_LED, OUTPUT)
}
 
void loop() {
    // TODO: lee la LDR -> int luz = analogRead(PIN_LDR)
    // TODO: (opcional) muestra "Luz: " y el valor por Serial
    // TODO: if (luz < UMBRAL) enciende el LED -> digitalWrite(PIN_LED, HIGH)
    // TODO: else apaga el LED -> digitalWrite(PIN_LED, LOW)
    // TODO: delay(200)
}

Solución — cópiala y ejecútala

/*
 * Curso de Arduino — Módulo 04: Entradas analógicas
 * Ejercicio 04 — MODELO (resuelto)  [reto del módulo]
 * Enunciado: Umbral. Si está oscuro (LDR por debajo de un umbral) enciende un LED; si hay luz, lo apaga.
 * Dificultad: amarillo
 * Placa: Arduino UNO
 * Montaje: LDR en divisor -> A0 (como ej03) | LED en pin 8 -> 220ohm -> GND
 * Correr: Arduino IDE / Wokwi (wokwi/ej04) / arduino-cli (ver README)
 */
const int PIN_LDR = A0;     // lectura de luz
const int PIN_LED = 8;      // LED indicador (salida digital ON/OFF)
const int UMBRAL  = 400;    // ajusta según tu montaje/iluminación (0..1023)
 
void setup() {
    Serial.begin(9600);
    pinMode(PIN_LED, OUTPUT);
}
 
void loop() {
    int luz = analogRead(PIN_LDR);
    Serial.print("Luz: ");  Serial.println(luz);
 
    if (luz < UMBRAL) {                 // poca luz = oscuro
        digitalWrite(PIN_LED, HIGH);    // enciende el LED
    } else {
        digitalWrite(PIN_LED, LOW);     // hay luz suficiente -> apaga
    }
    delay(200);
}

Cómo ejecutar la simulación

Sin instalar nada, en el navegador

  1. Abre wokwi.com y crea un proyecto nuevo de la placa que pide el ejercicio.
  2. Pega la solución (o tu intento) en la pestaña sketch.ino.
  3. Abre la pestaña diagram.json, borra lo que haya y pega el circuito de aquí abajo.
  4. Dale al play. Verás el circuito funcionando: LEDs, pantallas y monitor serie.
Circuito del ejercicio (diagram.json)
{
  "version": 1,
  "author": "ESIBot",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} },
    { "type": "wokwi-photoresistor-sensor", "id": "ldr1", "top": -130, "left": 150, "attrs": {} },
    { "type": "wokwi-led", "id": "led1", "top": -130, "left": 40, "attrs": { "color": "red" } },
    { "type": "wokwi-resistor", "id": "r1", "top": -60, "left": 30, "attrs": { "value": "220" } }
  ],
  "connections": [
    [ "ldr1:VCC", "uno:5V", "red", [] ],
    [ "ldr1:GND", "uno:GND.1", "black", [] ],
    [ "ldr1:AO", "uno:A0", "green", [] ],
    [ "uno:8", "r1:1", "green", [] ],
    [ "r1:2", "led1:A", "green", [] ],
    [ "led1:C", "uno:GND.2", "black", [] ]
  ],
  "dependencies": {}
}

En VS Code, con el repo del curso

El paquete de simulación de este ejercicio está en practica/04-entradas-analogicas/wokwi/ej04/. Con la extensión Wokwi instalada y la licencia activada (lo cuenta el onboarding del curso):

make sim EJ=04-entradas-analogicas/ej04

y después, en VS Code, Ctrl+Shift+PWokwi: Start Simulator. La extensión no compila: simula un firmware ya compilado, y de compilarlo se encarga ese make.

Cómo usarlo

Con placa: abre el .ino en el Arduino IDE, elige placa y puerto y pulsa Subir. Sin placa: simulalo en Wokwi con cualquiera de las dos vias de arriba. Antes de mirar la solucion, intenta completar tu el esqueleto: es la mejor forma de aprender.

Conexiones