delay() Función Arduino: Bucles estrechos y código de bloqueo
¿Alguna vez has hecho un proyecto Arudino y quieres que algo ocurra en un intervalo de tiempo? Tal vez cada 3 segundos quieres que un servo se mueva, o tal vez cada 1 minuto quieres enviar una actualización de estado a un servidor web.
¿Cómo lo haces? Hay alguna función que sea simple y sencilla que nos ayude con esto? Sí que la hay. Hablaremos de la función delay, así como de la función millis(), en el siguiente vídeo:
Esta es la parte 2 de nuestra miniserie sobre la función millis(). La parte 1 nos ayuda a entender lo que hace la función millis(), la parte 2 analiza los bucles cerrados y el código de bloqueo, y la parte 3 analiza cuándo la función millis() supera a la función delay().
Temas de esta lección
- Bucles estrechos
- Código de bloqueo
- Recetas antiguas para inspirar la música
Millis() frente a Delay()
Así que quieres que algo ocurra en un intervalo determinado y estás buscando una solución. Si tu respuesta es usar la función de retardo, pues más o menos tienes razón. Pero hay otra manera.
La opción más fresca y elegante es la función millis() de Arduino. Y cuanto más familiarizado estés con el uso de la función millis, para ayudarte a cronometrar eventos en tu código Arduino, más fácil será incorporar otras partes en tu programa más adelante.
Una vez que empieces a usar la función millis(), serás más feliz, más alegre, y caramba, le gustarás a la gente.
![Función Millis() de Arduino](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/people_like_you.png)
Bucles cerrados
Primero vamos a discutir el concepto de bucle cerrado. Y cuando decimos un bucle cerrado, ¿qué significa?
Vamos a echar un vistazo a un boceto de Arduino para una demostración de un bucle cerrado. Comenzando con el boceto más básico, sólo tenemos dos funciones: void setup, y void loop. Y como ya sabrás, void setup sólo se ejecuta una vez, y luego pasa la función a void loop.
![Arduino void setup loop](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/void_setup_loop_2.png)
Void loop entonces pasa por cada línea de código que podría estar dentro del bucle (dentro de estas llaves).
Ejecuta la primera línea, luego ejecuta la segunda, y luego la tercera, y así sucesivamente, hasta llegar al final. Y luego vuelve al principio.
¿Cómo de rápido ejecuta el bucle? Depende de la placa Arduino que utilices, pero un Arduino Uno tiene una velocidad de reloj de 16 megahercios. Así que eso significa que 16 millones de instrucciones están sucediendo cada segundo en el Arduino!
![Velocidad de reloj del Arduino](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/16-Mhz.png)
Cada línea de código no es necesariamente una instrucción. De hecho, lo más probable es que sean múltiples instrucciones. Pero aún así, eso es relativamente rápido (el procesador de tu ordenador probablemente esté funcionando a velocidades de Gigahercios… eso son miles de millones).
¿Entonces considerarías ese sketch vacío un bucle cerrado? Definitivamente, eso es lo más rápido y apretado que se puede hacer un bucle. Como no hay nada dentro del bucle que ejecutar, el tiempo que se tarda en recorrer el sketch es prácticamente nulo. Dicho de otra manera, el intervalo desde el inicio del bucle hasta el final es corto (por lo tanto es rápido, o «apretado»).
Agreguemos algunas líneas de código. Iniciaremos la comunicación en serie, y luego imprimiremos algo en la ventana del monitor de serie.
![Comunicación en serie de bucle cerrado de Arduino](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/tight_loop.png)
¿Es esto un bucle cerrado? Es decir, desde el inicio del bucle hasta el final del mismo, ¿toma mucho tiempo? Lleva muy poco tiempo, así que es un bucle rápido y ajustado.
Sin embargo, cabe destacar que este bucle no es tan ajustado como el ejemplo anterior. En el ejemplo anterior, no teníamos ningún código. Así que sólo estaba corriendo a través del bucle. Ahora que tenemos una función aquí, serial print, tomará un poco de tiempo para imprimir «Ice Ice Baby» en el monitor serial.
Pero esto sigue siendo un bucle bastante rápido. Así que vamos a añadir un poco más de código. Haremos que el programa compruebe si se ha pulsado un botón, y si es así, haremos que se envíe algo nuevo al monitor serie
![Monitor serie de bucle cerrado de Arduino con pulsación de botón](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/tight_loop_2.png)
Así que hemos declarado un botón y hemos utilizado una sentencia if para comprobar y ver si se ha pulsado el botón. Es el voltaje en el pin cinco alto? Si es así, entonces imprimimos algo más en la ventana del monitor serie.
¿Es esto un bucle cerrado? Así que, desde el inicio del bucle, hasta el final del bucle, ¿es bastante rápido?
Sí, sigue siendo bastante rápido. Este es un bucle bastante apretado. Tenemos cuatro líneas de código. Estamos imprimiendo en el monitor de serie, y luego estamos haciendo una comprobación rápida para ver si un botón está siendo presionado. Y si lo es, imprimimos algo. Todavía apretado, todavía rápido.
A continuación vamos a añadir un retraso a este programa utilizando la función Arduino delay(). Puedes ver a continuación que hemos añadido un retardo de mil milisegundos (1 segundo) al bucle.
![Bucle cerrado Arduino con retardo](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/tight_loop_3.png)
¿Sigue siendo un bucle cerrado? Es el tiempo, desde el inicio del bucle hasta el final del bucle, mucho tiempo? No, definitivamente no es un bucle cerrado. El código comienza rápido, hacemos la impresión en serie, pero luego nos detenemos justo ahí en la función de retardo.
Todo el programa se detiene mientras esperamos que este código de retardo termine.
Cuando el Arduino llega a esta línea de código, es como ir a la tienda de comestibles. Llegas a la línea de 12 artículos o menos, pero entonces el tipo delante de ti saca su chequera, y comienza a escribir un cheque. Sabes que vas a estar ahí un minuto. Es lo mismo aquí.
![Cuando alguien saca un cheque en la línea exprés](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/checkout.png)
Así que esto no es un bucle cerrado. El tiempo desde el inicio del bucle hasta el final del bucle es bastante significativo. Especialmente comparado con los últimos programas. El orden de magnitud del tiempo es enorme.
Ahora lo que hemos tratado de demostrar aquí es que toda esta idea sobre los bucles apretados es relativa. Todo depende de tu aplicación. Si necesitas comprobar el estado de un sensor cada 10 millonésimas de segundo, entonces un programa que tenga tres líneas de código puede no ser lo suficientemente ajustado, simplemente depende.
Otro punto a destacar es que no todas las líneas de código tardan lo mismo en ejecutarse. Si estás llamando a una función que hace un montón de cosas, como la impresión en serie, por ejemplo, entonces esa línea de código puede tardar mucho más que otras 10 líneas de código.
Así que la estrechez de un bucle es una idea relativa.
![La estanqueidad de un bucle de Arduino es relativa - Einstein](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/The-tightness-of-a-loop-is-relative.png)
Código de bloqueo
Cuando un programa se detiene en algún punto, y tarda algún tiempo en ejecutar algún código, ese código puede llamarse código de bloqueo. Este es un término general.
En nuestro programa tenemos la función delay actuando como código de bloqueo. Ningún código después del retardo puede ejecutarse hasta que el retardo termine, así que se está bloqueando.
El código de bloqueo no es, sin embargo, sólo cuando usamos la función delay().
Tomemos nuestro programa y eliminemos el retardo, pero añadiremos un bucle for. Nuestro bucle for imprimirá números y texto al puerto serie.
![Bucle for apretado de Arduino](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/tight_loop_4.png)
¿Pues cuánto tiempo se ejecuta este bucle? Se ejecutará durante un tiempo porque tiene que pasar por 100 iteraciones antes de detenerse.
¿Y qué pasa con el código después de este bucle for? ¿Puede ejecutarse? No, tiene que esperar porque está siendo bloqueado por el bucle for.
Este bucle for está anidado dentro del bucle principal. ¿Es el bucle for un bucle «apretado»? Antes de que respondas, volvamos a insistir en cómo debes pensar en él: ¿toma mucho tiempo recorrer este bucle for, desde el principio hasta el final?
Bueno, en realidad no. Sólo tiene dos líneas de código. Así que es un bucle bastante apretado.
Pero es un bucle apretado que tiene que pasar por muchas iteraciones antes de que el programa pueda llegar al código de abajo. Así que, incluso un bucle apretado, si se ve obligado a pasar por varias iteraciones, puede bloquear nuestro código.
Más sobre la función delay()
Hablemos un poco más sobre esta función delay. ¿Qué hemos establecido hasta ahora?
Primero hemos dicho que la función delay disminuye la rigidez de un bucle. Si tienes un bucle apretado y añades la función de retardo, va a tomar más tiempo y lo hará menos apretado. Es decir, la cantidad de tiempo que se necesita para llegar desde el inicio del bucle hasta el final, aumentará con la función de retardo.
También sabemos que la función de retardo bloquea el código. Esto va de la mano con lo que acabamos de decir. Cuando la función de retardo se está ejecutando, está bloqueando la ejecución de otro código mientras se está retrasando.
¡Podrías pensar que esta función de retardo es una flojera total! Nunca va a llegar a nada en nuestros proyectos. Pero para muchos programas sencillos que escribimos, la función de retardo funciona fantásticamente. Es simple de usar, es realmente fácil de deletrear, y hace justo lo que dice.
![Función de retardo de Arduino siendo una patata de sofá](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/Is-the-delay-function-a-total-slacker__.png)
Así que no debemos necesariamente condenar al ostracismo la función delay() de nuestra caja de herramientas de programación. Sólo debemos reconocer que es una función de programación sencilla que puede funcionar en muchos casos.
Sin embargo, hay un momento en el que empiezas a tener problemas. Eso tiene que ver con el efecto de bloqueo que la función de retardo tiene en nuestro programa.
En la próxima lección de la serie, la parte 3, vamos a identificar donde esto realmente se convierte en un problema. Aprenderás cuándo tiene sentido usar la función delay() en un programa, y cuándo es el momento de cambiar a usar la función millis().
Revisión
Primero, hablamos de la estrechez de un bucle. Dijimos que la estanqueidad de un bucle es relativa. Depende de cuál sea tu aplicación.
Segundo, hablamos de código bloqueante, o código que se bloquea. Esencialmente, es un término genérico que podemos dar al código que va a tardar algún tiempo en ejecutarse, y que va a detener la ejecución de otras partes de nuestro programa mientras se ejecuta.
¡Esperamos haber disfrutado de esta lección! En la siguiente parte de esta serie, vamos a continuar nuestro viaje aprendiendo cómo utilizar la función millis para crear eventos repetitivos cronometrados en nuestro código Arduino. Nos vemos la próxima vez!
![Recetas antiguas de Arduino para inspirar música](https://programmingelectronics.com/wp-content/uploads/2019/04/ancient-recipe-gif.gif)