les vencimos · offline
L26. millis en vez de delay
Maestro
millis devuelve cuántos milisegundos lleva despierta la placa. No espera. Tú miras el reloj, decides si ya toca, y el loop sigue. Así el parpadeo no se come el botón. La variable del reloj tiene que ser unsigned long. Con un int se desborda enseguida y el tiempo hace cosas raras.
El patrón es siempre el mismo. Guardas el último momento en que cambiaste. Cada vuelta de loop restas: millis() menos ese recuerdo. Si la resta ya es mayor que el periodo, toca cambiar y vuelves a guardar el reloj. Entre medias el programa puede leer un pin, escribir Serial o mirar un sensor.
La resta entre dos unsigned long aguanta la vuelta del contador, que ocurre pasados unos 49 días. No la cambies por un long con signo porque parezca más claro: el tipo que toca es el largo sin signo.
El sketch parpadea el 13 cada medio segundo sin delay. Al lado lee el pin 2. Si está apretado, manda una línea por Serial. Prueba a pulsar durante el parpadeo: el clic se ve, porque nadie ha dormido el chip. Eso era imposible en la lección 8.
No mezcles este estilo con delay largos en el mismo loop. Un delay de un segundo tira por tierra el beneficio. Las esperas cortas de rebote, de 30 ms, aún se pueden quedar un tiempo. Lo que no vuelve es la pausa de un segundo.
Montaje
Pines de esta lección
Por qué
millis devuelve cuántos milisegundos lleva el chip encendido, en un número que da la vuelta al cabo de muchos días. Restar ahora menos anterior aguanta esa vuelta si los dos son unsigned long. Un int se queda corto y el ritmo se rompe a los pocos segundos. Por eso el tipo importa aquí, no por manía.
El patrón es: si ya pasó el plazo, guarda el ahora como anterior y haz la cosa. El loop sigue dando vueltas rapidísimo el resto del tiempo. Un delay(500) haría lo mismo con el LED y dejaría el botón sordo durante medio segundo. Con millis, el if del botón se ejecuta miles de veces entre dos cambios del LED.
El botón de esta lección aún imprime mientras está LOW, no solo en el flanco, y lleva un delay(30) corto. Verás varias líneas apretado si mantienes el dedo. No es el contador limpio. Es la prueba de que el dedo se oye sin apagar el parpadeo. El flanco fino ya lo conoces.
No mezcles este parpadeo con otro delay largo en el mismo loop. Un delay(2000) escondido en una rama mata la ventaja. Si algo espera, que sea una resta de millis con su propia variable anterior.
Práctica
- LED en el 13, pulsador en el 2 a GND, pines 0 y 1 vacíos.
- Carga el sketch de millis.
- Sin pulsar, el LED cambia cada medio segundo.
- Mantén el botón. En el monitor, a 9600, tienen que salir líneas, y el LED no se congela.
- Mete a propósito un delay(2000) al final del loop, carga, y mira cómo el LED y el botón se vuelven torpes. Quítalo.
- Comprueba que anterior y ahora son unsigned long, no int.
- Deja el ritmo en 500 antes de salir.
Anota el montaje
Escribe qué cable va a qué pin, o qué has entendido del paso. Se guarda en este aparato.
Ejemplos resueltos
El LED se para al pulsar
Dentro del if del botón hay un delay de un segundo, además del print. Mientras el dedo está, el plazo del LED no se revisa a tiempo y parece que millis no funciona.
Se acorta esa espera a los 30 ms del rebote, o se quita. El bloqueo largo no puede vivir en el mismo loop que un reloj.
El ritmo se acelera solo
anterior se actualiza en todas las vueltas, no solo cuando el plazo se cumple. La resta nunca llega a 500 porque anterior acaba de copiarse.
anterior = ahora va dentro del if, cuando de verdad toca cambiar el LED. Fuera, anterior se queda quieto.
En la mesa
Mira el LED y el monitor a la vez. Mantén el botón. Las letras tienen que seguir naciendo y el LED tiene que seguir cambiando. Si las letras salen y el LED se congela, hay un delay dentro del botón. Si el LED vive y no hay letras, el monitor no está a 9600 o el if del botón no se cumple: pulsa de verdad a GND, no al aire.
Suelta y cuenta los cambios del LED en diez segundos. Tienen que ser unos veinte, porque cambia cada medio segundo. Si son muchos menos, la resta no se cumple a tiempo: anterior se actualiza siempre, o hay un delay largo. No corrijas el 500 hasta haber contado.
Esta lección está bien cuando te aburre mirar las dos cosas y las dos siguen. El aburrimiento estable es la prueba de que el loop no se atasca. Un efecto bonito que se salta golpes no sirve.
Sketch
unsigned long anterior = 0;
bool encendido = false;
void setup() {
pinMode(13, OUTPUT);
pinMode(2, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
unsigned long ahora = millis();
if (ahora - anterior >= 500) {
anterior = ahora;
encendido = !encendido;
digitalWrite(13, encendido ? HIGH : LOW);
}
if (digitalRead(2) == LOW) {
Serial.println("apretado");
delay(30);
}
}
Ejercicio
Sustituye el parpadeo con delay por el de millis. Mantén pulsado el pin 2 un segundo entero. En el monitor debe salir más de una línea. Si no sale ninguna, queda un delay escondido.
Autoevaluación
1. ¿millis espera?
No. Solo dice cuánto tiempo lleva la placa despierta.
2. ¿Qué tipo usa la variable del último cambio?
unsigned long. No un int.
3. ¿Por qué ahora el botón sí se lee durante el parpadeo?
Porque loop no se duerme dentro de delay.