les vencimos · offline

L26. millis en vez de delay

Pensar en el tiempo (70–84%)

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

LED 500 msLED otra vezbotón cuando seadelay pararía el botón; millis no
El LED del 13 cambia cada 500 ms por resta de tiempos. El botón del 2 se lee en el mismo loop, y el monitor puede decir apretado sin esperar al LED.

Pines de esta lección

Uno R3 · 5 V · mira la serigrafía, no la memoria13sigue el ritmo2se lee igualmillisel reloj500sin parar el loop
0 y 1 siguen libres. El 2 es el botón. El 13 es la luz. A0 no hace falta en el dibujo 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

  1. LED en el 13, pulsador en el 2 a GND, pines 0 y 1 vacíos.
  2. Carga el sketch de millis.
  3. Sin pulsar, el LED cambia cada medio segundo.
  4. Mantén el botón. En el monitor, a 9600, tienen que salir líneas, y el LED no se congela.
  5. 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.
  6. Comprueba que anterior y ahora son unsigned long, no int.
  7. 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?

2. ¿Qué tipo usa la variable del último cambio?

3. ¿Por qué ahora el botón sí se lee durante el parpadeo?