les vencimos · offline
L27. Estados y funciones
Maestro
Cuando el programa crece, loop se vuelve una bolsa de if. La salida es poner nombre a cada modo y nombre a cada gesto. Un estado es una variable: apagado, encendido, aviso. Una función es un trozo con nombre: encender, apagar, medir. loop solo pregunta en qué estado estás y llama. No hace el trabajo menudo.
Sin estados, cada sensor añade condiciones cruzadas y un día el LED enciende por dos razones a la vez. Con estados, solo hay un modo vigente. Pasas de apagado a encendido cuando llega el botón. Pasas a aviso cuando el sensor cruza el umbral. Cada modo sabe qué pinta en los pines. Los otros modos no se cuelan.
Una función void encender() agrupa los digitalWrite. Se llama desde donde haga falta y no se copia. Si mañana el LED cambia de pin, lo cambias en un sitio. El nombre tiene que decir el gesto, no un número suelto.
El sketch de abajo es mínimo: estado 0 apagado, estado 1 encendido. El pin 2 cambia de uno a otro, con una espera corta de rebote. La función aplicar escribe el LED. loop no sabe de pines. Eso es el orden que vas a necesitar en el semáforo y en la alarma.
Montaje
Pines de esta lección
Por qué
Un estado es un recuerdo con nombre. Aquí vale 0 o 1. El dedo no pone el LED: el dedo pide un cambio, y la función aplicar traduce el recuerdo a HIGH o LOW. Si mañana el estado 1 también enciende un zumbador, lo añades en aplicar, no repartes digitalWrite por todo el loop.
Hace falta el flanco y luego esperar a que suelten. Si cambias de estado mientras el pin sigue LOW, la siguiente vuelta del loop lo cambia otra vez, y el LED parpadea a toda velocidad con el dedo quieto. El while que espera la suelta es una forma simple. Bloquea, sí, pero solo durante el dedo, que es corto.
Los nombres 0 y 1 son pobres y bastan. Cuando haya tres situaciones, rojo, ámbar y verde, el estado será 0, 1 y 2 y aplicar pondrá tres pines. La idea no cambia: una variable, un sitio que la aplica, un sitio que la cambia.
Inicializar importa. estado = 0 y aplicar dentro de setup dejan el LED apagado al cargar, no en un recuerdo de la vez anterior. El chip no guarda la variable al quitar el USB. Al volver, setup manda.
Práctica
- Un pulsador en el 2, LED en el 13.
- Carga el sketch del estado.
- Al arrancar, LED apagado.
- Un golpe. LED encendido, y se queda al soltar.
- Otro golpe. LED apagado. Diez golpes: acaba apagado, porque empezó apagado y diez es par.
- Mantén el dedo. No debe oscilar. Si oscila, el while de la suelta no está.
- Pulsa RESET. Tiene que volver a apagado, el estado inicial, no al último.
Anota el montaje
Escribe qué cable va a qué pin, o qué has entendido del paso. Se guarda en este aparato.
Ejemplos resueltos
Oscila mientras aprietas
Se cambia el estado en cada vuelta en la que el pin está LOW. Un dedo de medio segundo son cientos de cambios. Al soltar, el LED queda al azar.
Después de cambiar, se espera a que digitalRead vuelva a HIGH. Un gesto, un cambio. El delay de 30 ms sigue ahí para el rebote del golpe.
Aplicar está copiado en dos sitios y no coincide
En un sitio el estado 1 enciende el LED. En otro, un arreglo rápido lo deja apagado. Según por dónde entres, el recuerdo y la luz mienten.
Una sola función aplicar. Quien cambie el estado no toca el pin. Quien toca el pin no decide el estado.
En la mesa
Golpea y suelta, diez veces, contando solo clics. El LED debe quedar como empezó si empezó apagado y diez es par. Si queda al azar, estás cambiando de estado durante todo el tiempo que el dedo está abajo. Mira el while de la suelta. Sin él, esta lección es la del rebote otra vez, no la de la memoria.
Pulsa RESET. Tiene que volver a apagado, el estado inicial, no acordarse del último golpe. El chip no tiene diario. Si se acuerda, no has reiniciado: has pulsado otra cosa. Usa el botón de RESET de la placa y míralo.
Di la función aplicar en una frase: aquí se entera el LED, y en ningún otro sitio. Si encuentras otro digitalWrite del 13 suelto, bórralo o mételo dentro. Dos sitios, dos verdades, un LED mentiroso.
Sketch
int estado = 0;
void aplicar() {
digitalWrite(13, estado == 1 ? HIGH : LOW);
}
void setup() {
pinMode(13, OUTPUT);
pinMode(2, INPUT_PULLUP);
aplicar();
}
void loop() {
if (digitalRead(2) == LOW) {
delay(30);
if (estado == 0) estado = 1;
else estado = 0;
aplicar();
while (digitalRead(2) == LOW) {
delay(10);
}
}
}
Ejercicio
Añade un estado 2, aviso, que parpadee usando millis, no un delay largo. Entras con el pin 3. Si te lías, vuelve a dejar solo dos estados: mejor pocos y claros.
Autoevaluación
1. ¿Qué problema tiene un loop lleno de if cruzados?
Que varias razones mandan a la vez y dejas de saber quién enciende el LED.
2. ¿Para qué sirve una función con nombre?
Para agrupar un gesto y no copiarlo. Si cambia el pin, cambias un sitio.
3. ¿Cuántos estados mandan a la vez?
Uno. El programa está en un modo y cambia de modo con un motivo claro.