Arduino Usando La Función Millis en Lugar de Delay

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 8

Arduino: Usando la función millis() en lugar de

delay()

El código que sigue es un típico ejemplo de escritura a través de la comunicación serie de Arduino. Escribe
“Hola” a través del puerto COM serie (visible con el Monitor Serie de Arduino, en la pestaña Herramientas), y
espera durante 1000 milisegundos (1 segundo) al final de cada iteración del bucle.

Programa de saludo 'Hola'


Arduino
void setup() {
Serial.begin(9600);
}

1 void setup() {
2 Serial.begin(9600);
3}
4
5 void loop() {
6 Serial.println("Hola");
7 delay(1000);
8}

La función delay() es muy fácil de usar para crear esperas, pero tiene un inconveniente: deja al
microcontrolador «atrapado» dentro de la ejecución de esta función durante el tiempo que se ha indicado. Si
hubiese un cambio en un pin que debería detectar, o si llegase información a través de cualquiera de las
comunicaciones posibles (serie, I2C o SPI) el microcontrolador sólo se enteraría luego de completarse el
retardo.

Una solución es crear un retardo que no deje insensible al sistema durante un tiempo tan extenso.
La función millis()

millis() devuelve el número de milisegundos desde que la placa Arduino empezó a ejecutar, luego de un reinicio
o el encendido. Este número se desbordará (volverá a cero), después de aproximadamente 50 días.

Retorna la cantidad de milisegundos en un valor long sin signo (unsigned long).

Ejemplo
Arduino
unsigned long tiempo;
void setup(){
Serial.begin(9600);
}

1 unsigned long tiempo;


2 void setup(){
3 Serial.begin(9600);
4 }
5 void loop(){
6 Serial.print("Tiempo: ");
7 tiempo = millis();
8 // imprime el tiempo transcurrido desde el inicio del programa
9 Serial.println(time);
10 // esperar un segundo para no enviar cantidades masivas de datos
11 delay(1000);
12 }

Nota: Tenga en cuenta que como el valor de retorno para millis() es un long sin signo (unsigned long), pueden
producirse errores lógicos si un programador intenta hacer operaciones aritméticas con tipos de datos más
pequeños, como de tipo int. Incluso con los long con signo se pueden producir errores ya que su valor máximo
es la mitad que la de su contraparte sin signo.

Ejemplo de texto «Hola» utilizando la función millis()

Retardo con función millis()


Arduino
int periodo = 1000;
unsigned long TiempoAhora = 0

void setup() {

1 int periodo = 1000;


2 unsigned long TiempoAhora = 0;
3 void setup() {
4 Serial.begin(9600);
5 }
6 void loop() {
7 TiempoAhora = millis();
8 Serial.println("Hola");
9 while(millis() < TiempoAhora+periodo){
10 // espere [periodo] milisegundos
11 }
12 }
13
14

Hacerlo de esta manera solo tiene sentido como ejemplo, ya que es evidente que en este caso directamente se
puede usar una función delay(1000). Pero de todos modos la diferencia entre este ejemplo y el código que usa
la función delay(1000) es que el ciclo del código que usa la función millis() se ejecutará una vez por segundo
con la máxima precisión posible. El bucle en un código con delay(1000) se ejecutará en algo más de tiempo, ya
que se produce un retardo al ejecutar Serial.println(«Hola»). Ocurrirá igual con cualquier otra serie de
instrucciones que se incluyan dentro del bucle.

¿Por qué usar millis() en lugar de delay()?

Presentaré dos ventajas al utilizar millis() para crear retardos, en comparación con el uso habitual de delay().

1. Cronometraje preciso

La primera ventaja que discutiremos es la exactitud en el tiempo.

Con millis() podemos garantizar que el bucle se ejecute tantas veces como queramos dentro del retardo sin
afectar su extensión, independientemente del tiempo de ejecución (obviamente, siempre que el tiempo de
ejecución de todas las instrucciones sea menor al retardo deseado).

Con delay() esto no es posible, ya que no sabemos cuánto tiempo durará el tiempo de ejecución de todas las
instrucciones de programa que están dentro del ciclo.

Una sincronización precisa como esta es muy útil cuando se muestrea a una cierta frecuencia, o cuando se
utilizan filtros, entre otras cosas.

2. Sin bloqueo

La ventaja principal de la función millis() es que no nos impide ejecutar otro código mientras estamos
«esperando».

Ejemplo: digamos que queremos imprimir «Hola» en el puerto serie una vez por segundo mientras hacemos
otras cosas. Esto no es posible con delay(), ya que entrar a la función delay() pausa todo el código.

Aquí hay una manera de hacer esto:

Ciclo con instrucciones dentro y con tiempo de retardo preciso


Arduino
int periodo = 1000;
unsigned long TiempoAhora = 0

void setup() {

1 int periodo = 1000;


2 unsigned long TiempoAhora = 0;
3
4 void setup() {
5 Serial.begin(9600);
6 }
7
8 void loop() {
9
10 if(millis() > TiempoAhora + periodo){
11 TiempoAhora = millis();
12 Serial.println("Hola");
13 }
14
15 // AQUI CORRE OTRO CODIGO
16 // AQUI CORRE OTRO CODIGO
17 // AQUI CORRE OTRO CODIGO
18 // AQUI CORRE OTRO CODIGO
19 // AQUI CORRE OTRO CODIGO
20 }

Este fragmento de código es bastante similar al primer ejemplo que mostramos, excepto que este no bloquea el
resto del programa mientras no se está imprimiendo hacia la línea serie.

3. Un simple secuenciador

Vamos a escribir un ejemplo simple en el que creamos un planificador que imprime ciertos trozos de texto a
través de la línea serie a diferentes intervalos.

Planificador de mensajes
Arduino
#define INTERVALO_MENSAJE1
#define INTERVALO_MENSAJE2
#define INTERVALO_MENSAJE3
#define INTERVALO_MENSAJE4

1 #define INTERVALO_MENSAJE1 5000


2 #define INTERVALO_MENSAJE2 7000
3 #define INTERVALO_MENSAJE3 11000
4 #define INTERVALO_MENSAJE4 13000
5 unsigned long tiempo_1 = 0;
6 unsigned long tiempo_2 = 0;
7 unsigned long tiempo_3 = 0;
8 unsigned long tiempo_4 = 0;
9 void print_tiempo(unsigned long tiempo_millis);
10 void setup() {
11 Serial.begin(9600);
12 }
13 void loop() {
14 if(millis() > tiempo_1 + INTERVALO_MENSAJE1){
15 tiempo_1 = millis();
16 print_tiempo(tiempo_1);
17 Serial.println("Soy el mensaje 1");
18 }
19
20 if(millis() > tiempo_2 + INTERVALO_MENSAJE2){
21 tiempo_2 = millis();
22 print_tiempo(tiempo_2);
23 Serial.println("Soy el mensaje 2");
24 }
25
26 if(millis() > tiempo_3 + INTERVALO_MENSAJE3){
27 tiempo_3 = millis();
28 print_tiempo(tiempo_3);
29 Serial.println("Soy el mensaje 3");
30 }
31
32 if(millis() > tiempo_4 + INTERVALO_MENSAJE4){
33 tiempo_4 = millis();
34 print_tiempo(tiempo_4);
35 Serial.println("Soy el mensaje 4");
36 }
37 }
38 void print_tiempo(unsigned long tiempo_millis){
39 Serial.print("Tiempo: ");
40 Serial.print(tiempo_millis/1000);
41 Serial.print("s - ");
42 }
43
44
45
46
47

Así es como se ven los primeros 60 segundos en el Monitor Serie:


Esta es una manera agradable y fácil de sincronizar las ejecuciones en su código. También se puede ejecutar
otras partes de código simultáneamente.

4. Una nueva función delay()

La función delay() estándar podemos reemplazarla por una implementada con la función millis(). Si bien parece
que es lo mismo, ya veremos a continuación qué ventaja nos puede ofrecer su estructura de programa:

Función Espera()
Arduino
unsigned long Contador = 0;
void Espera(int valor)
{
Contador = millis() + valor;

1 unsigned long Contador = 0;


2 void Espera(int valor)
3{
4 Contador = millis() + valor;
5 do {
6
7 } while (Contador<=millis() && digitalRead(12)==HIGH);
8}

Además de esperar el tiempo indicado, esta función monitorea un pin de entrada del Arduino que haya sido
cableado para detectar que ha sucedido algún evento externo. Si esa señal va a nivel BAJO (LOW), se
interrumpe el retardo.

Para conectar varias entradas capaces de interrumpir el ciclo de retardo, se pueden agregar más elementos en la
comparación de cierre del while, por ejemplo

while (Contador<=millis() && digitalRead(12)==HIGH) && digitalRead(11)==HIGH);

O se puede conectar a la entrada por el pin 12 (u otro pin elegido) un circuito como el que sigue, un AND
realizado con lógica de diodos de señal (1N914 o 1N4148), que tiene la ventaja de que se puede ampliar
indefinidamente. También se puede implementar con un circuito integrado compuerta AND.
Nota: quede claro que el circuito se representa con pulsadores, pero cada una de estas entradas puede ser un
microswith, los contactos de un relé, o cualquier otro sensor que cierre circuito hacia GND (tierra o común).

Función micros() y desbordamiento

Al igual que delay() tiene una versión en microsegundos llamada delayMicroseconds(), la función millis()
tiene como compañera para tiempos breves la función micros(). Si necesitamos una mejor resolución, micros()
puede ser el camino a seguir. Sin embargo, tenga en cuenta que el valor devuelto por micros() se desbordará
(volverá a cero) después de aproximadamente 70 minutos, en comparación con los 50 días de millis().
“Desbordamiento” significa que el conteo llega a su máximo, y entonces los valores de retorno de la función
recomienzan desde cero.

Resumen

millis() y micros() son funciones realmente útiles para usar en tareas relacionadas con el tiempo. La opción
inicial y típica de un programador de Arduino es usar delay(), que no siempre funcionará tan bien,
principalmente cuando se programan muchas funciones que tienen que ver con el tiempo y existen eventos que
no se pueden perder.

También podría gustarte