Ejercicio 01 — Encender un LED mientras se mantiene pulsado un botón

Dificultad: verde · Módulo 02 (Entradas digitales)

Enunciado

Encender un LED mientras se mantiene pulsado un botón (digitalRead + INPUT_PULLUP).

Montaje (Arduino UNO)

Botón entre pin 2 y GND; LED en pin 8 con resistencia 220 ohm a GND

Cómo se resuelve

Primer programa del curso en el que la placa escucha en vez de mandar. El objetivo es mínimo a propósito: que el LED del pin 8 esté encendido exactamente mientras mantienes pulsado el botón del pin 2.

El montaje es igual de mínimo. El botón va entre el pin 2 y GND, sin ninguna resistencia externa, y el LED va en el pin 8 con su resistencia de 220 Ω hacia GND, como en el módulo 01. Que el botón no lleve resistencia no es un olvido: la pone el propio microcontrolador, y eso es lo que hace la primera línea interesante del programa.

const int PIN_BOTON = 2;
const int PIN_LED   = 8;

Los dos pines con nombre desde el principio, la costumbre que ya viste en el módulo anterior. Aquí importa más que antes, porque el 2 y el 8 hacen cosas distintas y confundirlos en un digitalRead no da error de compilación, simplemente no funciona.

En setup() aparece lo nuevo:

pinMode(PIN_BOTON, INPUT_PULLUP);  // resistencia interna: pin = HIGH en reposo
pinMode(PIN_LED, OUTPUT);

Dos pines, dos direcciones opuestas. El 8 es OUTPUT como toda la vida. El 2 es INPUT_PULLUP, que hace dos cosas de una vez: lo configura como entrada y le conecta la resistencia de pull-up que el chip lleva dentro. Si escribieras INPUT a secas, el pin quedaría flotando cada vez que el botón está suelto (porque un pulsador abierto no conecta el pin a nada) y leerías ruido: el LED se encendería y apagaría solo. Esa es la razón de ser de la palabra PULLUP, y es el motivo de que no haga falta ninguna resistencia en el botón.

El loop() cabe en la cabeza de un vistazo:

int estado = digitalRead(PIN_BOTON);  // LOW = pulsado, HIGH = suelto
if (estado == LOW) {
    digitalWrite(PIN_LED, HIGH);      // pulsado -> LED encendido
} else {
    digitalWrite(PIN_LED, LOW);       // suelto  -> LED apagado
}

digitalRead devuelve HIGH o LOW, los mismos dos valores que usas para escribir, solo que ahora los decide el circuito y no tú. Y aquí está el detalle que hay que interiorizar de una vez: LOW significa pulsado. La comparación es estado == LOW, no == HIGH, y no es una errata.

Piénsalo desde el circuito y deja de parecer raro. Con el botón suelto, la pull-up interna tira suavemente del pin hacia los 5 V y digitalRead devuelve HIGH. Al pulsar, el botón cierra un camino directo del pin a GND; ese camino no tiene resistencia apreciable, así que gana a la pull-up y el pin cae a 0 V, o sea LOW. La lógica invertida no es un capricho de Arduino: es lo que pasa cuando eliges pull-up. Es, con diferencia, la confusión número uno de este módulo, y la señal de que has caído en ella es que el LED parece ir al revés.

Fíjate también en que no hay ningún delay. El loop() da miles de vueltas por segundo, y en cada una vuelve a preguntar por el pin y vuelve a decidir el LED. No hace falta “esperar a que pulses”: simplemente, la enésima vez que se pregunta, la respuesta ya es LOW. La reacción parece instantánea porque, a escala humana, lo es.

Merece la pena que pruebes dos variaciones. La primera, cambiar LOW por HIGH en la comparación: el LED se queda encendido siempre y se apaga al pulsar, que es la versión “al revés” que te va a salir sin querer algún día. La segunda, cambiar INPUT_PULLUP por INPUT y observar el desastre: sin la referencia interna, el pin flota y el LED hace lo que le da la gana. Ver ese fallo una vez a propósito ahorra media hora de depuración más adelante.

Un aviso sobre el montaje antes de dudar del código: el pulsador de cuatro patillas une sus patillas por pares. Si has usado las dos patillas de un mismo lado, están conectadas entre sí siempre y el pin está permanentemente a GND, con lo que el programa cree que el botón lleva pulsado desde el arranque y el LED no se apaga nunca. La solución es usar dos patillas en diagonal.

Este ejercicio funciona sin filtrar nada, y es importante entender por qué. El botón rebota, claro que rebota: durante unos milisegundos al pulsar, el contacto se abre y se cierra varias veces. Pero como aquí el LED sigue el nivel del pin instante a instante, ese parpadeo de 5 ms es invisible para el ojo. El rebote todavía no molesta. Empezará a molestar en el ejercicio siguiente, en cuanto haya que contar algo.

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 02: Entradas digitales
 * Ejercicio 01 — PRÁCTICA (rellena los TODO)
 * Enunciado: Encender un LED mientras se mantiene pulsado un botón (digitalRead + INPUT_PULLUP).
 * Dificultad: verde
 * Placa: Arduino UNO    Montaje: botón entre pin 2 y GND; LED en pin 8 con resistencia 220 ohm a GND
 * Correr: Arduino IDE / Wokwi (wokwi/ej01) / arduino-cli (ver README)
 *
 * Nota: con INPUT_PULLUP el pin está en HIGH en reposo y baja a LOW al pulsar (lógica invertida).
 */
const int PIN_BOTON = 2;
const int PIN_LED   = 8;
 
void setup() {
    // TODO: configura PIN_BOTON como entrada con resistencia interna -> pinMode(PIN_BOTON, INPUT_PULLUP)
    // TODO: configura PIN_LED como salida -> pinMode(PIN_LED, OUTPUT)
}
 
void loop() {
    // TODO: lee el botón -> int estado = digitalRead(PIN_BOTON)
    // TODO: si estado == LOW (pulsado) -> enciende el LED con digitalWrite(PIN_LED, HIGH)
    // TODO: si no (suelto) -> apaga el LED con digitalWrite(PIN_LED, LOW)
}

Solución — cópiala y ejecútala

/*
 * Curso de Arduino — Módulo 02: Entradas digitales
 * Ejercicio 01 — MODELO (resuelto)
 * Enunciado: Encender un LED mientras se mantiene pulsado un botón (digitalRead + INPUT_PULLUP).
 * Dificultad: verde
 * Placa: Arduino UNO    Montaje: botón entre pin 2 y GND; LED en pin 8 con resistencia 220 ohm a GND
 * Correr: Arduino IDE / Wokwi (wokwi/ej01) / arduino-cli (ver README)
 *
 * Nota: con INPUT_PULLUP el pin está en HIGH en reposo y baja a LOW al pulsar (lógica invertida).
 */
const int PIN_BOTON = 2;
const int PIN_LED   = 8;
 
void setup() {
    pinMode(PIN_BOTON, INPUT_PULLUP);  // resistencia interna: pin = HIGH en reposo
    pinMode(PIN_LED, OUTPUT);
}
 
void loop() {
    int estado = digitalRead(PIN_BOTON);  // LOW = pulsado, HIGH = suelto
    if (estado == LOW) {
        digitalWrite(PIN_LED, HIGH);      // pulsado -> LED encendido
    } else {
        digitalWrite(PIN_LED, LOW);       // suelto  -> LED apagado
    }
}

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-pushbutton", "id": "btn", "top": -100, "left": 200, "attrs": { "color": "green" } },
    { "type": "wokwi-led", "id": "led", "top": 100, "left": 200, "attrs": { "color": "red" } },
    { "type": "wokwi-resistor", "id": "r1", "top": 130, "left": 120, "attrs": { "value": "220" } }
  ],
  "connections": [
    [ "uno:2", "btn:1.l", "green", [] ],
    [ "btn:2.l", "uno:GND.1", "black", [] ],
    [ "uno:8", "r1:1", "blue", [] ],
    [ "r1:2", "led:A", "blue", [] ],
    [ "led: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/02-entradas-digitales/wokwi/ej01/. Con la extensión Wokwi instalada y la licencia activada (lo cuenta el onboarding del curso):

make sim EJ=02-entradas-digitales/ej01

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