Introducción
Cuando nos iniciamos en la programación con Arduino, la forma más sencilla e intuitiva de introducir pausas en el código es recurrir a la función delay(). Por ejemplo, ejecutar delay(1000); detiene el flujo del programa durante un segundo. Sin embargo, en proyectos más avanzados, delay() presenta un inconveniente crítico: bloquea por completo el procesador.
Mientras se ejecuta un delay(), el microcontrolador queda congelado. No puede leer sensores, atender pulsadores ni procesar comunicaciones serie. Para solucionar esta limitación existe la función millis(), que permite implementar temporizadores no bloqueantes y lograr una multitarea real.
⚠️ El Problema del Bloqueo por delay()
La función delay() detiene la ejecución del bucle principal loop(). Si estás diseñando un sistema de seguridad o un robot que requiera respuesta inmediata ante un obstáculo, el uso de delay() provocará retardos inaceptables (lag) en las lecturas de los sensores.
Materiales Recomendados para la Práctica
Para poner en práctica la lógica no bloqueante y realizar pruebas de multitarea con lecturas simultáneas, se recomiendan los siguientes componentes:
| Componente | Descripción | Enlace |
|---|---|---|
| Placa Arduino UNO R3 / R4 | Placa microcontroladora ideal para aprender la gestión de tiempos y multitarea. | Ver en Amazon |
| Kit de LEDs de 5mm | Para crear múltiples temporizadores visuales independientes en el mismo sketch. | Ver en Amazon |
| Sensor de Ultrasonidos HC-SR04 | Sensor de medición de distancia ideal para combinar con temporizadores no bloqueantes. | Ver en Amazon |
| Protoboard y Cables Dupont | Base de prototipado y cables jumper para la interconexión rápida de periféricos. | Ver en Amazon |
¿Qué es millis() y cómo funciona?
La función millis() devuelve el número de milisegundos transcurridos desde que la placa Arduino comenzó a ejecutar el programa actual. Este contador se gestiona mediante un temporizador interno por interrupción (Timer 0 en arquitecturas ATmega) y opera de forma ininterrumpida de fondo.
Puesto que el cronómetro de millis() se incrementa continuamente, la clave para crear un temporizador no bloqueante reside en responder a la siguiente pregunta en cada ciclo del loop(): "¿Ha transcurrido el intervalo deseado desde la última actualización?".
La Lógica Matemática: Resta y Desbordamiento (Overflow)
La estructura estándar para verificar el tiempo transcurrido utiliza la siguiente secuencia lógica:
- Almacenamos el tiempo de la última acción en una variable:
previousMillis. - En cada iteración del bucle, leemos el tiempo presente:
currentMillis = millis();. - Calculamos la diferencia:
currentMillis - previousMillis. - Si la diferencia es mayor o igual al intervalo programado, ejecutamos la acción y actualizamos
previousMillis = currentMillis;.
💡 Prevención del Desbordamiento (Overflow)
El contador de millis() se almacena en una variable de 32 bits sin signo (unsigned long), alcanzando su valor máximo a los 49,7 días aproximadamente (4.294.967.295 ms), momento en el cual vuelve a cero. Al utilizar la resta (currentMillis - previousMillis), el álgebra binaria de complementos maneja correctamente la transición de vuelta a cero, evitando que el temporizador se bloquee.
Código de Ejemplo: Parpadeo de LED No Bloqueante
A continuación se presenta el código optimizado para hacer parpadear el LED integrado en la placa (o un LED externo conectado al pin 13) sin pausar la ejecución del resto de tareas:
Análisis Detallado del Sketch
- Uso de
unsigned long: Es indispensable definir tantopreviousMilliscomocurrentMilliscon este tipo de dato. Utilizar enteros estándar (int) provocará errores de desbordamiento en pocos segundos. - Evaluación Condicional: La expresión
if (currentMillis - previousMillis >= interval)solo resultará verdadera al alcanzar el tiempo límite, permitiendo que las demás líneas dentro deloop()se sigan ejecutando a máxima velocidad. - Actualización de
previousMillis: Asignar el valor actual es vital para reiniciar el contador relativo. De lo contrario, la condición continuará siendo verdadera indefinidamente.
Aplicaciones Prácticas y Multitarea
Al erradicar el uso de delay(), es posible crear múltiples rutinas independientes duplicando la estructura con distintas variables:
🚀 Pon a prueba la multitarea en proyectos reales
Aplica esta técnica sustituyendo retardos bloqueantes en proyectos como nuestra Alarma con Arduino y Sensor Ultrasónico HC-SR04. También puedes realizar simulaciones virtuales en tiempo real accediendo a nuestro Simulador de Arduino Online.
Conclusión
Sustituir delay() por la lógica basada en millis() representa la transición de programas secuenciales básicos a proyectos de ingeniería electrónica profesionales y eficientes. Dominar la resta no bloqueante te permitirá desarrollar sistemas embebidos complejos capaces de gestionar múltiples periféricos en paralelo.
Comentarios
Publicar un comentario