Ejercicio 02 — El potenciómetro controla el brillo de un LED

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

Enunciado

El potenciómetro controla el brillo de un LED. Leer 0-1023, mapear a 0-255 y sacarlo por PWM con analogWrite.

Montaje (Arduino UNO)

Pot SIG=A0,VCC=5V,GND=GND | LED en pin 9 (~PWM) 220ohm GND

Cómo se resuelve

Aquí es donde el módulo 04 se junta con el 03: la lectura analógica deja de ser un número en pantalla y pasa a controlar algo. El potenciómetro entra por A0 y el brillo del LED sale por PWM en el pin 9. Es el primer sistema completo del curso: entrada, proceso y salida.

El montaje añade el LED al del ejercicio anterior. El potenciómetro sigue igual (extremos a 5 V y GND, cursor a A0) y el LED va del pin 9 a una resistencia de 220 Ω, de ahí al ánodo (patilla larga), y el cátodo a GND. Que sea el pin 9 y no otro cualquiera no es casual: es uno de los pines marcados con ~ en la placa, los únicos capaces de generar PWM. Si lo montas en un pin sin ~, analogWrite no regulará nada y el LED se comportará como si fuera digital, encendido del todo o apagado del todo.

Los dos pines llevan nombre:

const int PIN_POT = A0;   // entrada analógica del potenciómetro
const int PIN_LED = 9;    // salida PWM (pin con ~) para regular el brillo

En setup() hay dos preparaciones. Serial.begin(9600) abre el puerto serie, igual que antes, y pinMode(PIN_LED, OUTPUT) configura el pin 9 como salida. Aquí se ve de golpe la asimetría que confunde a todo el mundo: el pin de salida necesita su pinMode, y el pin analógico de entrada no. La razón es que para sacar corriente hay que declarar la intención, mientras que para medir no hay nada que declarar.

El loop() son tres líneas que forman una cadena:

int valor  = analogRead(PIN_POT);          // 0..1023 (resolución del ADC)
int brillo = map(valor, 0, 1023, 0, 255);  // reescalar al rango del PWM (8 bits)
analogWrite(PIN_LED, brillo);              // duty cycle = brillo/255

La primera línea mide y devuelve algo entre 0 y 1023, porque el ADC del UNO es de 10 bits. La tercera necesita algo entre 0 y 255, porque el PWM del UNO es de 8 bits. Los dos rangos no coinciden, y la línea del medio existe exactamente para eso.

map(valor, 0, 1023, 0, 255) se lee así: coge valor, que viene del rango 0-1023, y dame el equivalente proporcional en el rango 0-255. El 0 sigue siendo 0, el 1023 se convierte en 255, y el 512 de la mitad de recorrido se convierte en unos 127, la mitad del brillo. La proporción se conserva, que es justo lo que quieres: que todo el recorrido del mando se reparta sobre todo el rango del brillo.

Y aquí está la pregunta que hay que saber contestar: ¿por qué no pasar el 0-1023 tal cual a analogWrite? Porque analogWrite solo entiende hasta 255. Con la lectura sin mapear, el LED llegaría al máximo brillo cuando el mando llevase apenas un cuarto de su recorrido, y los otros tres cuartos no harían absolutamente nada. No es que “no funcione”: es que pierdes tres cuartas partes del control.

Merece la pena aclarar qué hace de verdad analogWrite, porque el nombre miente un poco. No pone el pin a una tensión intermedia: lo enciende y lo apaga a gran velocidad, cientos de veces por segundo, variando qué proporción del tiempo está encendido. Eso es el duty cycle, y aquí vale brillo/255: con brillo a 255 el pin está encendido el 100 % del tiempo, con 127 la mitad, con 0 nunca. El LED parpadea demasiado rápido para que el ojo lo distinga y lo percibes como un brillo intermedio. analogRead mide algo analógico de verdad; analogWrite lo finge.

Las tres líneas siguientes sacan las dos cifras por el puerto serie:

Serial.print("Pot: ");   Serial.print(valor);
Serial.print("  Brillo: "); Serial.println(brillo);

Cuatro print y un solo println, el último, que es el que cierra la fila. Así cada lectura ocupa una línea con las dos magnitudes juntas, y puedes comprobar de un vistazo que la relación es la esperada: cuando Pot marca alrededor de 1023, Brillo debe marcar 255. Ver los dos números a la vez es la mejor forma de detectar un map() mal escrito, porque el LED por sí solo no te dice si el problema está en la lectura o en el escalado.

El delay(50) es más corto que los 200 ms del ejercicio 01, y con motivo. Aquí no estás leyendo la pantalla, estás girando un mando y mirando el LED: si la placa solo refrescase cinco veces por segundo, notarías el brillo cambiando a saltos, con retraso respecto a tu mano. Veinte actualizaciones por segundo se perciben como una respuesta instantánea. El tiempo de espera no es un valor fijo que se copia: se elige según para quién sea la respuesta, para un humano leyendo o para un humano interactuando.

Cuando lo tengas montado, prueba a cambiar el map por map(valor, 0, 1023, 255, 0). El mando funcionará al revés, y comprobar que basta con intercambiar los dos últimos números para invertir el comportamiento deja muy claro qué está haciendo esa función.

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 02 — PRÁCTICA (rellena los TODO)
 * Enunciado: El potenciómetro controla el brillo de un LED.
 *            Leer 0-1023, mapear a 0-255 y sacarlo por PWM con analogWrite.
 * Dificultad: verde
 * Placa: Arduino UNO    Montaje: pot SIG=A0,VCC=5V,GND=GND | LED en pin 9 (~PWM) -> 220ohm -> GND
 * Correr: Arduino IDE / Wokwi (wokwi/ej02) / arduino-cli (ver README)
 */
const int PIN_POT = A0;   // entrada analógica del potenciómetro
const int PIN_LED = 9;    // salida PWM (pin con ~) para regular el brillo
 
void setup() {
    // TODO: arranca el Serial -> Serial.begin(9600)
    // TODO: configura PIN_LED como salida -> pinMode(PIN_LED, OUTPUT)
}
 
void loop() {
    // TODO: lee el potenciómetro -> int valor = analogRead(PIN_POT)
    // TODO: reescala 0..1023 a 0..255 -> int brillo = map(valor, 0, 1023, 0, 255)
    // TODO: aplica el brillo por PWM -> analogWrite(PIN_LED, brillo)
    // TODO: (opcional) muestra valor y brillo por Serial
    // TODO: delay(50)
}

Solución — cópiala y ejecútala

/*
 * Curso de Arduino — Módulo 04: Entradas analógicas
 * Ejercicio 02 — MODELO (resuelto)
 * Enunciado: El potenciómetro controla el brillo de un LED.
 *            Leer 0-1023, mapear a 0-255 y sacarlo por PWM con analogWrite.
 * Dificultad: verde
 * Placa: Arduino UNO    Montaje: pot SIG=A0,VCC=5V,GND=GND | LED en pin 9 (~PWM) -> 220ohm -> GND
 * Correr: Arduino IDE / Wokwi (wokwi/ej02) / arduino-cli (ver README)
 */
const int PIN_POT = A0;   // entrada analógica del potenciómetro
const int PIN_LED = 9;    // salida PWM (pin con ~) para regular el brillo
 
void setup() {
    Serial.begin(9600);
    pinMode(PIN_LED, OUTPUT);
}
 
void loop() {
    int valor  = analogRead(PIN_POT);          // 0..1023 (resolución del ADC)
    int brillo = map(valor, 0, 1023, 0, 255);  // reescalar al rango del PWM (8 bits)
    analogWrite(PIN_LED, brillo);              // duty cycle = brillo/255
 
    Serial.print("Pot: ");   Serial.print(valor);
    Serial.print("  Brillo: "); Serial.println(brillo);
    delay(50);
}

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-potentiometer", "id": "pot1", "top": -120, "left": 160, "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": [
    [ "pot1:SIG", "uno:A0", "green", [] ],
    [ "pot1:VCC", "uno:5V", "red", [] ],
    [ "pot1:GND", "uno:GND.1", "black", [] ],
    [ "uno:9", "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/ej02/. Con la extensión Wokwi instalada y la licencia activada (lo cuenta el onboarding del curso):

make sim EJ=04-entradas-analogicas/ej02

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