Multitasking
1. Por qué no usar delay()? #
La función delay(ms) bloquea todo el código, es decir, mientras espera, no se ejecuta nada más. Esto es un problema cuando queremos, por ejemplo:
- Leer un sensor cada segundo,
- Parpadear un LED cada medio segundo,
- Y al mismo tiempo revisar un botón.
Solución: usar millis() como temporizador. #
2. Qué es millis()? #
La función millis() devuelve el número de milisegundos transcurridos desde que se encendió la placa. Al usarla, podemos medir el tiempo sin detener el programa.
3. Objetivo #
Simular tareas simultáneas como:
- Parpadear varios LEDs a distinto ritmo.
- Leer sensores de forma periódica.
- Mostrar datos cada cierto tiempo.
- Controlar botones o eventos sin interferencias.
4. Estructura básica para múltiples tareas #
1unsigned long tAnteriorTarea1 = 0; 2const unsigned long intervaloTarea1 = 1000; 3 4void loop() { 5 unsigned long ahora = millis(); 6 7 if (ahora - tAnteriorTarea1 >= intervaloTarea1) { 8 tAnteriorTarea1 = ahora; 9 // ejecutar tarea 1 10 } 11 12 // otras tareas... 13}
5. Ejemplo 1: Dos LEDs con tiempos distintos #
1const int led1 = 8; 2const int led2 = 9; 3 4unsigned long tLed1 = 0, tLed2 = 0; 5const long intervalo1 = 500; // LED1 cada 0.5s 6const long intervalo2 = 1000; // LED2 cada 1s 7 8bool estadoLed1 = false; 9bool estadoLed2 = false; 10 11void setup() { 12 pinMode(led1, OUTPUT); 13 pinMode(led2, OUTPUT); 14} 15 16void loop() { 17 unsigned long ahora = millis(); 18 19 // Tarea LED1 20 if (ahora - tLed1 >= intervalo1) { 21 tLed1 = ahora; 22 estadoLed1 = !estadoLed1; 23 digitalWrite(led1, estadoLed1); 24 } 25 26 // Tarea LED2 27 if (ahora - tLed2 >= intervalo2) { 28 tLed2 = ahora; 29 estadoLed2 = !estadoLed2; 30 digitalWrite(led2, estadoLed2); 31 } 32}
6. Ejemplo 2: LED + sensor + botón #
Simula:
- Parpadeo de un LED cada 500ms.
- Lectura de un potenciómetro cada 100ms.
- Lectura de un botón continuamente.
1const int led = 13; 2const int pot = A0; 3const int boton = 2; 4 5unsigned long tLED = 0, tSensor = 0; 6bool estadoLED = false; 7 8void setup() { 9 Serial.begin(9600); 10 pinMode(led, OUTPUT); 11 pinMode(boton, INPUT_PULLUP); 12} 13 14void loop() { 15 unsigned long ahora = millis(); 16 17 // LED intermitente 18 if (ahora - tLED >= 500) { 19 tLED = ahora; 20 estadoLED = !estadoLED; 21 digitalWrite(led, estadoLED); 22 } 23 24 // Leer potenciómetro 25 if (ahora - tSensor >= 100) { 26 tSensor = ahora; 27 int valor = analogRead(pot); 28 Serial.print("Potenciómetro: "); 29 Serial.println(valor); 30 } 31 32 // Leer botón (en tiempo real) 33 if (digitalRead(boton) == LOW) { 34 Serial.println("¡Botón presionado!"); 35 delay(200); // anti-rebote rápido 36 } 37}
7. Recomendaciones para múltiples tareas #
- Crea una variable por tarea para controlar su tiempo (
tAnterior). - Usa
unsigned longsiempre conmillis()para evitar desbordamientos. - Nunca uses
delay()si estás manejando más de una tarea. - Si el código crece, organiza cada tarea en una función separada.
8. Proyecto sugerido #
Estación ambiental multitarea:
- LED parpadeante como latido del sistema.
- Sensor de temperatura/humedad que se lee cada 2 segundos.
- Muestra datos en monitor serial cada 5 segundos.
- Botón que guarda el umbral actual en EEPROM.
Resumen del tema
Conceptos clave #
- Multitarea Cooperativa: ejecución concurrente simulada de múltiples tareas mediante temporización no bloqueante con
millis(). - Variables Temporales Individuales: cada tarea independiente gestiona su propia variable
unsigned long tAnteriory su constanteintervalo. - Eliminación de Bloqueos: exclusión total de
delay()para garantizar que la comprobación de botones, lecturas de sensores y actualización de salidas se procesen en tiempo real. - Estructura Escalable: modularización de cada tarea periódica en una función dedicada llamada condicionalmente desde
loop().
Qué debes recordar #
La multitarea en microcontroladores de un solo núcleo se logra verificando periódicamente el tiempo transcurrido con millis() para cada tarea de forma independiente.