Ir al contenido principal

Cómo crear un temporizador (reloj) no bloqueante en Arduino con millis()

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:

  1. Almacenamos el tiempo de la última acción en una variable: previousMillis.
  2. En cada iteración del bucle, leemos el tiempo presente: currentMillis = millis();.
  3. Calculamos la diferencia: currentMillis - previousMillis.
  4. 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:

millis_multitarea.ino
// Variables para el temporizador no bloqueante
unsigned long previousMillis = 0; // Guarda el último instante en que se conmutó el LED
const unsigned long interval = 1000; // Intervalo de temporización en ms (1 segundo)

void setup() {
  // Configurar el pin del LED integrado como salida
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // Capturar el tiempo actual del sistema
  unsigned long currentMillis = millis();

  // Evaluar si ha transcurrido el intervalo programado
  if (currentMillis - previousMillis >= interval) {
    // Actualizar la marca de tiempo anterior
    previousMillis = currentMillis;

    // Conmutar el estado del LED digital
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }

  // --- ZONA MULTITAREA ---
  // Aquí se pueden incluir lecturas de sensores o pulsadores.
  // El bucle loop() continuará ejecutándose miles de veces por segundo.
}

Análisis Detallado del Sketch

  • Uso de unsigned long: Es indispensable definir tanto previousMillis como currentMillis con 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 de loop() 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

Entradas populares de este blog

Cómo evitar que Windows apague la pantalla o el disco duro (con gpedit)

Introducción Uno de los problemas más frecuentes en Windows es la suspensión automática del sistema, el apagado de la pantalla o la desactivación del disco duro tras unos minutos de inactividad. Aunque esto busca ahorrar energía, puede resultar frustrante si utilizas tu PC como servidor doméstico, servidor Plex, máquina de descargas o para tareas de larga duración . Si bien es posible cambiar estos ajustes desde la configuración tradicional de energía, muchas veces Windows ignora nuestras preferencias debido a directivas internas. La solución definitiva para evitar que tu ordenador se apague o suspenda es utilizar el Editor de Directivas de Grupo Local (gpedit.msc) . ⚠️ Advertencia sobre la versión de Windows El comando gpedit.msc solo está disponible de forma nativa en las ediciones Windows Pro, Enterprise y Education . Si utilizas Windows Home , esta herramienta no estará presente por defecto y deberás recurrir a la configuración convencional del Panel de Control. Paso 1...

Alarma con Arduino y Sensor Ultrasónico HC-SR04 (Tutorial paso a paso)

Introducción Crear un sistema de seguridad o detección de movimiento no tiene que ser complicado ni caro. En este tutorial vamos a construir una alarma con Arduino y un sensor de ultrasonidos (el famoso HC-SR04). Este proyecto es ideal para principiantes porque aprendes a leer sensores externos y a generar una respuesta física (encender un LED y hacer sonar un buzzer) cuando alguien se acerca demasiado. A continuación, te explico cómo funciona el sensor, qué materiales necesitas, cómo montar el circuito y te desgloso el código línea por línea para que realmente entiendas lo que estás programando. ¿Cómo funciona el Sensor Ultrasónico HC-SR04? Este sensor funciona igual que un sonar o los delfines: emite un sonido imperceptible para el humano (ultrasonido) y espera a que ese sonido choque contra un objeto y regrese (eco). Pin Trig (Trigger - Disparo): Le dice al sensor que debe "gritar" y emitir el pulso de ultrasonido. Pin Echo (Eco - Recepción): Se queda escuchando...

Instalar el driver USB a TTL PL2303HX en Windows 10 (Solución al Error Code 10)

Introducción: ¿Para qué sirve el convertidor USB a TTL? Los adaptadores USB a TTL (equipados con chips como el PL2303HX , FTDI o CP2102) son herramientas indispensables en el taller de cualquier maker, técnico o entusiasta de la electrónica. Nos permiten establecer comunicación serie UART entre un ordenador y dispositivos como Arduino, ESP32-CAM, routers, receptores de satélite o tablets . Sin embargo, conectar este tipo de cables en Windows 10 o Windows 11 suele transformarse en un dolor de cabeza. Al conectar el dispositivo, el sistema instala automáticamente el controlador más reciente y muestra un aviso de fallo con el icono amarillo de advertencia: "Este dispositivo no puede iniciar (Código 10)" . A continuación te explicamos por qué sucede y cómo solucionarlo en pocos minutos. ⚠️ Causa del fallo: Bloqueo de chips no oficiales por Prolific La inmensa mayoría de los módulos USB-TTL económicos integran una revisión o clon del chip Pr...