- ¿Qué es la multitarea?
- ¿Por qué omitir delay () en Arduino?
- ¿Por qué utilizar millis ()?
- Componentes requeridos
- Diagrama de circuito
- Programación de Arduino UNO para multitarea
La multitarea ha llevado a las computadoras a una revolución donde uno o más programas pueden ejecutarse simultáneamente, lo que aumenta la eficiencia, flexibilidad, adaptabilidad y productividad. En los sistemas integrados, los microcontroladores también pueden manejar multitarea y realizar dos o más tareas simultáneamente sin detener las instrucciones actuales.
Aquí, en este tutorial, aprenderemos cómo Arduino realiza la multitarea con la función Arduino millis. Generalmente, una función delay () se usa en Arduino para una tarea periódica como LED parpadeando, pero esta función delay () detiene el programa durante un tiempo definitivo y no permite que se realicen otras operaciones. Entonces, este artículo explica cómo podemos evitar el uso de la función delay () y reemplazarla con millis () para realizar más de una tarea simultáneamente y hacer del Arduino un controlador multitarea. Antes de entrar en detalles, comencemos por subestimar la multitarea.
¿Qué es la multitarea?
La multitarea simplemente significa ejecutar más de una tarea o programa simultáneamente al mismo tiempo. Casi todos los sistemas operativos cuentan con multitarea. Este tipo de sistemas operativos se conocen como MOS (sistema operativo multitarea). El MOS puede ser un sistema operativo de PC móvil o de escritorio. El buen ejemplo de multitarea en computadoras es cuando los usuarios ejecutan la aplicación de correo electrónico, el navegador de Internet, el reproductor multimedia, los juegos, al mismo tiempo y si los usuarios no quieren usar la aplicación, se ejecuta en segundo plano si no está cerrada. El usuario final usa todas estas aplicaciones al mismo tiempo, pero el sistema operativo toma este concepto un poco diferente. Analicemos cómo el sistema operativo gestiona la multitarea.
Como se ve en la imagen, la CPU divide el tiempo en tres partes iguales y asigna cada parte a cada tarea / aplicación. Así es como se realiza la multitarea en la mayoría de los sistemas. El concepto será casi el mismo para Arduino Multitasking, excepto que la distribución del tiempo será un poco diferente. Dado que Arduino se ejecuta en baja frecuencia y la RAM se compara con la computadora portátil / móvil / PC, el tiempo asignado a cada tarea también será diferente. Arduino también tiene una función delay () que se usa ampliamente. Pero antes de comenzar, analicemos por qué no deberíamos usar la función delay () en ningún proyecto.
¿Por qué omitir delay () en Arduino?
Si se considera la documentación de referencia de Arduino, entonces hay dos tipos de funciones de retardo, la primera es delay () y la segunda es delayMicroseconds (). Ambas funciones son idénticas en términos de generar retardo. La única diferencia es que, en la función delay (), el parámetro entero pasado está en milisegundos, es decir, si escribimos delay (1000), el retardo será de 1000 milisegundos, es decir, 1 segundo. De manera similar, en la función delayMicroseconds (), el parámetro pasado está en microsegundos, es decir, si escribimos delayMicroseconds (1000), entonces el retardo será de 1000 microsegundos, es decir, 1 milisegundos.
Aquí viene el punto, ambas funciones pausan el programa durante el tiempo transcurrido en la función de retardo. Entonces, si damos un retraso de 1 segundo, el procesador no puede pasar a la siguiente instrucción hasta que haya pasado 1 segundo. De manera similar, si la demora es de 10 segundos, el programa se detendrá durante 10 segundos y el procesador no permitirá continuar con las siguientes instrucciones hasta que pasen los 10 segundos. Esto dificulta el rendimiento del microcontrolador en términos de velocidad y ejecución de las instrucciones.
El mejor ejemplo para explicar el inconveniente de la función de retardo es el uso de dos botones. Considere que queremos alternar dos LED usando dos botones. Entonces, si se presiona un botón, el LED correspondiente debe brillar durante 2 segundos, de manera similar, si se presiona el segundo, el LED debe brillar durante 4 segundos. Pero cuando usamos delay (), si el usuario está presionando el primer botón, entonces el programa se detendrá por 2 segundos y si el usuario presiona el segundo botón antes de 2 segundos de retraso, entonces el microcontrolador no aceptará la entrada como el programa está en etapa de parada.
La documentación oficial de Arduino lo menciona claramente en la descripción de la función Notas y advertencias de delay (). Puede revisar y verificar esto para que quede más claro.
¿Por qué utilizar millis ()?
Para superar el problema causado por el uso de la demora, un desarrollador debe usar la función millis () que es fácil de usar una vez que se vuelve habitual y utilizará el rendimiento de la CPU al 100% sin generar ninguna demora en la ejecución de las instrucciones. millis () es una función que simplemente devuelve la cantidad de milisegundos que han transcurrido desde que la placa Arduino comenzó a ejecutar el programa actual sin congelar el programa. Este número de tiempo se desbordará (es decir, volverá a cero) después de aproximadamente 50 días.
Al igual que Arduino tiene delayMicroseconds (), también tiene la versión micro de millis () como micros (). La diferencia entre micros y milis es que, los micros () se desbordarán después de aproximadamente 70 minutos, en comparación con milis () que son 50 días. Entonces, dependiendo de la aplicación, puede usar millis () o micros ().
Usando millis () en lugar de delay ():
Para usar millis () para la sincronización y el retraso, debe registrar y almacenar la hora a la que tuvo lugar la acción para iniciar la hora y luego verificar a intervalos si ha pasado la hora definida. Entonces, como se indicó, almacene la hora actual en una variable.
currentMillis largo sin firmar = millis ();
Necesitamos dos variables más para saber si ha pasado el tiempo requerido. Hemos almacenado la hora actual en la variable currentMillis , pero también necesitamos saber cuándo comenzó el período de tiempo y cuánto dura. Entonces se declaran Interval y previousMillis . El intervalo nos dirá el tiempo de retraso y previosMillis almacenará la última vez que ocurrió el evento.
unsigned long previousMillis; período largo sin firmar = 1000;
Para entender esto, tomemos un ejemplo de un LED parpadeante simple. El período = 1000 nos dirá que el LED parpadeará durante 1 segundo o 1000ms.
const int ledPin = 4; // el número de pin del LED conectado int ledState = LOW; // se usa para establecer el estado del LED unsigned long previousMillis = 0; // se almacenará la última vez que el LED estuvo parpadeando const long period = 1000; // período en el que parpadear en ms void setup () { pinMode (ledPin, OUTPUT); // establece ledpin como salida } void loop () { unsigned long currentMillis = millis (); // almacena la hora actual if (currentMillis - previousMillis> = period) {// verifica si pasaron 1000ms previousMillis = currentMillis; // guarde la última vez que parpadeó el LED if (ledState == LOW) {// si el LED está apagado, enciéndalo y viceversa ledState = HIGH; } else { ledState = LOW; } digitalWrite (ledPin, ledState); // establece el LED con ledState para que vuelva a parpadear } }
Aquí, la declaración
Las interrupciones en Arduino funcionan igual que en otros microcontroladores. La placa Arduino UNO tiene dos pines separados para conectar interrupciones en los pines GPIO 2 y 3. Lo hemos cubierto en detalle en el Tutorial de interrupciones de Arduino, donde puede obtener más información sobre las interrupciones y cómo usarlas.
Aquí mostraremos Arduino Multitasking manejando dos tareas al mismo tiempo. Las tareas incluirán el parpadeo de dos LED en diferentes tiempos de retardo junto con un botón que se utilizará para controlar el estado de encendido / apagado del LED. Entonces se realizarán tres tareas simultáneamente.
Componentes requeridos
- Arduino UNO
- Tres LED (cualquier color)
- Resistencias (470, 10k)
- Jerséis
- Tablero de circuitos
Diagrama de circuito
El diagrama de circuito para demostrar el uso de la función Arduino Millis () es muy fácil y no tiene muchos componentes para conectar como se muestra a continuación.
Programación de Arduino UNO para multitarea
Programar Arduino UNO para multitarea solo requerirá la lógica detrás de cómo funciona millis () que se explica anteriormente. Se recomienda practicar el parpadeo del LED usando milis una y otra vez para aclarar la lógica y sentirse cómodo con milis () antes de comenzar a programar Arduino UNO para multitarea. En este tutorial, la interrupción también se usa con millis () simultáneamente para realizar múltiples tareas. El botón será una interrupción. Por lo tanto, siempre que se genere una interrupción, es decir, se presione un botón, el LED cambiará al estado ENCENDIDO o APAGADO.La programación comienza con la declaración de los números de pin donde se conectan los LED y el botón pulsador.
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2;
A continuación, escribimos una variable para almacenar el estado de los LED para uso futuro.
int ledState1 = LOW; int ledState2 = LOW;
Tal como se explicó anteriormente en el ejemplo de parpadeo, se declaran las variables de período y milis anterior para comparar y generar retardo para los LED. El primer LED parpadea después de cada segundo y otro LED parpadea después de 200 ms.
unsigned long previousMillis1 = 0; const long period1 = 1000; unsigned long previousMillis2 = 0; const long period2 = 200;
Se utilizará otra función de milis para generar el retardo antirrebote para evitar las pulsaciones múltiples del botón pulsador. Habrá un enfoque similar al anterior.
int debouncePeriod = 20; int debounceMillis = 0;
Las tres variables se utilizarán para almacenar el estado del botón pulsador como interrupción, LED de alternancia y estado del botón pulsador.
bool buttonPushed = falso; int ledChange = LOW; int lastState = HIGH;
Defina la acción del pin que funcionará como INPUT o OUTPUT.
pinMode (led1, SALIDA); pinMode (led2, SALIDA); pinMode (toggleLed, OUTPUT); pinMode (pulsador, ENTRADA);
Ahora defina el pin de interrupción adjuntando interrupción con la definición de ISR y modo de interrupción. Tenga en cuenta que se recomienda utilizar digitalPinToInterrupt (pin_number) al declarar la función attachInterrupt () para traducir el pin digital real al número de interrupción específico.
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
La subrutina de interrupción está escrita y solo cambiará el indicador buttonPushed. Tenga en cuenta que la subrutina de interrupción debe ser lo más corta posible, así que intente escribirla y minimizar las instrucciones adicionales.
void pushButton_ISR () { buttonPushed = true; }
El ciclo comienza con el almacenamiento del valor de milis en una variable currentMillis que almacenará el valor del tiempo transcurrido cada vez que el ciclo se repita.
currentMillis largo sin firmar = millis ();
Hay un total de tres funciones en la multitarea, abrir y cerrar un LED en 1 segundo, Blink segundo LED en 200 ms y Si no se pulsa botón pulsador luego cambiar OFF / ON LED. Entonces escribiremos tres partes para hacer esta tarea.
La primera es alternar el estado del LED cada 1 segundo comparando los milis transcurridos.
if (currentMillis - previousMillis1> = period1) { previousMillis1 = currentMillis; if (ledState1 == LOW) { ledState1 = HIGH; } else { ledState1 = LOW; } digitalWrite (led1, ledState1); }
De manera similar, en segundo lugar, alterna el LED cada 200 ms comparando los milis transcurridos. La explicación ya se explicó anteriormente en este artículo.
if (currentMillis - previousMillis2> = period2) { previousMillis2 = currentMillis; if (ledState2 == LOW) { ledState2 = HIGH; } else { ledState2 = LOW; } digitalWrite (led2, ledState2); }
Por último, se monitorea el indicador buttonPushed y, después de generar un retardo antirrebote de 20ms, simplemente cambia el estado del LED correspondiente al botón pulsador adjunto como interrupción.
if (buttonPushed = true) // verifica si se llama a ISR { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // genera un retardo de rebote de 20ms para evitar múltiples pulsaciones { debounceMillis = currentMillis; // guarda el último tiempo de retardo antirrebote if (digitalRead (pushButton) == LOW && lastState == HIGH) // cambia el led después de presionar el botón { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = LOW; } else if (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = falso; } }
Esto finaliza el tutorial de Arduino millis (). Tenga en cuenta que para acostumbrarse a millis (), simplemente practique para implementar esta lógica en algunas otras aplicaciones. También puede expandirlo para usar motores, servomotores, sensores y otros periféricos. En caso de duda, escriba a nuestro foro o comente a continuación.
El código completo y el video para demostrar el uso de la función millis en Arduino se proporcionan a continuación.