- ¿Cómo funciona RTOS?
- Términos de uso frecuente en RTOS
- Instalación de la biblioteca Arduino FreeRTOS
- Diagrama de circuito
- Ejemplo de Arduino FreeRTOS: creación de tareas FreeRTOS en Arduino IDE
- Implementación de tareas FreeRTOS en Arduino IDE
El sistema operativo presente dentro de los dispositivos integrados se denomina RTOS (sistema operativo en tiempo real). En los dispositivos integrados, las tareas en tiempo real son críticas donde la sincronización juega un papel muy importante. Las tareas en tiempo real son deterministas en el tiempo, lo que significa que el tiempo de respuesta a cualquier evento es siempre constante, por lo que se puede garantizar que cualquier evento en particular ocurrirá en un momento fijo. RTOS está diseñado para ejecutar aplicaciones con una sincronización muy precisa y un alto grado de confiabilidad. RTOS también ayuda en la multitarea con un solo núcleo.
Ya cubrimos un tutorial sobre cómo usar RTOS en sistemas embebidos donde puede saber más sobre RTOS, la diferencia entre SO de propósito general y RTOS, diferentes tipos de RTOS, etc.
En este tutorial, comenzaremos con FreeRTOS. FreeRTOS es una clase de RTOS para dispositivos integrados que es lo suficientemente pequeño como para ejecutarse en microcontroladores de 8/16 bits, aunque su uso no se limita a estos microcontroladores. Es un código completamente abierto y su código está disponible en github. Si conocemos algunos conceptos básicos de RTOS, entonces es muy fácil usar FreeRTOS porque tiene API bien documentadas que se pueden usar directamente en el código sin conocer la parte de backend de la codificación. Puede encontrar la documentación completa de FreeRTOS aquí.
Como FreeRTOS puede ejecutarse en MCU de 8 bits, también se puede ejecutar en la placa Arduino Uno. Tenemos que descargar la biblioteca FreeRTOS y luego comenzar a implementar el código usando API. Este tutorial está destinado a un principiante completo, a continuación se muestran los temas que cubriremos en este tutorial de Arduino FreeRTOS:
- Cómo funciona RTOS
- Algunos términos de uso frecuente en RTOS
- Instalación de FreeRTOS en Arduino IDE
- Cómo crear tareas de FreeRTOS con ejemplo
¿Cómo funciona RTOS?
Antes de comenzar a trabajar con RTOS, veamos qué es una Tarea. La tarea es un fragmento de código que se puede programar en la CPU para ejecutarse. Entonces, si desea realizar alguna tarea, entonces debe programarse usando el retraso del kernel o usando interrupciones. Este trabajo lo realiza el Programador presente en el kernel. En un procesador de un solo núcleo, el programador ayuda a que las tareas se ejecuten en un intervalo de tiempo particular, pero parece que diferentes tareas se ejecutan simultáneamente. Cada tarea se ejecuta de acuerdo con la prioridad que se le asigna.
Ahora, veamos qué sucede en el kernel RTOS si queremos crear una tarea para que el LED parpadee con un intervalo de un segundo y poner esta tarea en la prioridad más alta.
Aparte de la tarea LED, habrá una tarea más que es creada por el kernel, se conoce como una tarea inactiva. La tarea inactiva se crea cuando no hay ninguna tarea disponible para su ejecución. Esta tarea siempre se ejecuta en la prioridad más baja, es decir, la prioridad 0. Si analizamos el gráfico de tiempo dado anteriormente, se puede ver que la ejecución comienza con una tarea LED y se ejecuta durante un tiempo específico, luego, durante el tiempo restante, la tarea inactiva se ejecuta hasta que se produce una interrupción del tic. Luego, el kernel decide qué tarea debe ejecutarse de acuerdo con la prioridad de la tarea y el tiempo total transcurrido de la tarea LED. Cuando se completa 1 segundo, el kernel elige nuevamente la tarea led para ejecutar porque tiene una prioridad más alta que la tarea inactiva, también podemos decir que la tarea LED se adelanta a la tarea inactiva. Si hay más de dos tareas con la misma prioridad, se ejecutarán por turnos durante un tiempo específico.
Debajo del diagrama de estado, ya que muestra el cambio de la tarea no en ejecución al estado de ejecución.
Cada tarea recién creada pasa al estado Listo (parte del estado sin ejecución). Si la tarea creada (Task1) tiene la prioridad más alta que otras tareas, pasará al estado de ejecución. Si esta tarea en ejecución se adelanta a la otra tarea, volverá al estado listo nuevamente. De lo contrario, si la tarea1 está bloqueada mediante el bloqueo de la API, la CPU no participará en esta tarea hasta el tiempo de espera definido por el usuario.
Si Task1 se suspende en estado de ejecución utilizando Suspend API, entonces Task1 pasará al estado Suspendido y no estará disponible para el programador nuevamente. Si reanuda Task1 en el estado suspendido, volverá al estado listo, como puede ver en el diagrama de bloques.
Esta es la idea básica de cómo se ejecutan las tareas y cómo cambian sus estados. En este tutorial, implementaremos dos tareas en Arduino Uno usando FreeRTOS API.
Términos de uso frecuente en RTOS
1. Tarea: Es un fragmento de código que se puede programar en la CPU para ejecutarse.
2. Programador: es responsable de seleccionar una tarea de la lista de estado listo al estado en ejecución. Los programadores a menudo se implementan para mantener ocupados todos los recursos de la computadora (como en el equilibrio de carga).
3. Prevención: Es el acto de interrumpir temporalmente una tarea que ya se está ejecutando con la intención de sacarla del estado en ejecución sin su cooperación.
4. Cambio de contexto: en la preferencia basada en prioridad, el programador compara la prioridad de las tareas en ejecución con una prioridad de la lista de tareas preparadas en cada interrupción de systick . Si hay alguna tarea en la lista cuya prioridad es mayor que la tarea en ejecución, se produce un cambio de contexto. Básicamente, en este proceso, el contenido de las diferentes tareas se guarda en su respectiva memoria de pila.
5. Tipos de políticas de programación:
- Programación preventiva: en este tipo de programación, las tareas se ejecutan con el mismo intervalo de tiempo sin tener en cuenta las prioridades.
- Prevención basada en prioridades : la tarea de alta prioridad se ejecutará primero.
- Programación cooperativa: el cambio de contexto ocurrirá solo con la cooperación de las tareas en ejecución. La tarea se ejecutará continuamente hasta que se llame al rendimiento de la tarea.
6. Objetos del Kernel: Para indicar a la tarea que realice algún trabajo, se utiliza el proceso de sincronización. Para realizar este proceso se utilizan objetos de Kernel. Algunos objetos del Kernel son Eventos, Semáforos, Colas, Mutex, Buzones de correo, etc. Veremos cómo usar estos objetos en los próximos tutoriales.
De la discusión anterior, tenemos algunas ideas básicas sobre el concepto RTOS y ahora podemos implementar el proyecto FreeRTOS en Arduino. Entonces, comencemos instalando bibliotecas FreeRTOS en Arduino IDE.
Instalación de la biblioteca Arduino FreeRTOS
1. Abra Arduino IDE y vaya a Sketch -> Incluir biblioteca -> Administrar bibliotecas . Busque FreeRTOS e instale la biblioteca como se muestra a continuación.
Puede descargar la biblioteca de github y agregar el archivo.zip en Sketch-> Incluir biblioteca -> Agregar archivo .zip .
Ahora, reinicie el IDE de Arduino. Esta biblioteca proporciona un código de ejemplo, que también se puede encontrar en Archivo -> Ejemplos -> FreeRTOS como se muestra a continuación.
Aquí escribiremos el código desde cero para entender el funcionamiento, luego puedes revisar los códigos de ejemplo y usarlos.
Diagrama de circuito
A continuación se muestra el diagrama de circuito para crear una tarea de LED parpadeante usando FreeRTOS en Arduino:
Ejemplo de Arduino FreeRTOS: creación de tareas FreeRTOS en Arduino IDE
Veamos una estructura básica para escribir un proyecto FreeRTOS.
1. Primero, incluya el archivo de encabezado Arduino FreeRTOS como
#incluir
2. Proporcione el prototipo de función de todas las funciones que está escribiendo para su ejecución, que se escribe como
void Task1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Ahora, en la función void setup () , cree tareas e inicie el programador de tareas.
Para crear tareas, se llama a la API xTaskCreate () en la función de configuración con ciertos parámetros / argumentos.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Hay 6 argumentos que deben pasarse al crear cualquier tarea. Veamos cuáles son estos argumentos
- pvTaskCode: Es simplemente un puntero a la función que implementa la tarea (en efecto, solo el nombre de la función).
- pcName: un nombre descriptivo para la tarea. FreeRTOS no lo utiliza. Se incluye únicamente con fines de depuración.
- usStackDepth: cada tarea tiene su propia pila única que el kernel asigna a la tarea cuando se crea la tarea. El valor especifica el número de palabras que puede contener la pila, no el número de bytes. Por ejemplo, si la pila tiene 32 bits de ancho y usStackDepth se pasa como 100, entonces se asignarán 400 bytes de espacio de pila (100 * 4 bytes) en RAM. Use esto sabiamente porque Arduino Uno tiene solo 2 Kbytes de RAM.
- pvParameters: parámetro de entrada de la tarea (puede ser NULL).
- uxPriority: Prioridad de la tarea (0 es la prioridad más baja).
- pxCreatedTask: se puede usar para pasar un identificador a la tarea que se está creando. Este identificador se puede usar para hacer referencia a la tarea en llamadas API que, por ejemplo, cambian la prioridad de la tarea o eliminan la tarea (puede ser NULL).
Ejemplo de creación de tareas
xTaskCreate (tarea1, "tarea1", 128, NULL, 1, NULL); xTaskCreate (tarea2, "tarea2", 128, NULL, 2, NULL);
Aquí, Task2 tiene mayor prioridad y, por lo tanto, se ejecuta primero.
4. Después de crear la tarea, inicie el programador en una configuración vacía usando vTaskStartScheduler (); API.
5. La función Void loop () permanecerá vacía ya que no queremos ejecutar ninguna tarea de forma manual e infinita. Porque la ejecución de la tarea ahora la maneja el Programador.
6. Ahora, tenemos que implementar funciones de tarea y escribir la lógica que desea ejecutar dentro de estas funciones. El nombre de la función debe ser el mismo que el primer argumento de la API xTaskCreate () .
void task1 (void * pvParameters) { while (1) { .. ..//your logic } }
7. La mayor parte del código necesita la función de retardo para detener la tarea en ejecución, pero en RTOS no se sugiere usar la función Delay () ya que detiene la CPU y, por lo tanto, RTOS también deja de funcionar. Entonces, FreeRTOS tiene una API de kernel para bloquear la tarea durante un tiempo específico.
vTaskDelay (const TickType_t xTicksToDelay);
Esta API se puede utilizar con fines de retraso. Esta API retrasa una tarea durante un número determinado de tics. El tiempo real durante el cual la tarea permanece bloqueada depende de la tasa de ticks. La constante portTICK_PERIOD_MS se puede utilizar para calcular en tiempo real a partir de la tasa de ticks.
Esto significa que si desea un retraso de 200 ms, simplemente escriba esta línea
vTaskDelay (200 / portTICK_PERIOD_MS);
Entonces, para este tutorial, usaremos estas API de FreeRTOS para implementar tres tareas.
API que se utilizarán:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Tarea que se creará para este tutorial:
- El LED parpadea en el pin digital 8 con una frecuencia de 200 ms
- El LED parpadea en el pin digital 7 con una frecuencia de 300 ms
- Imprime números en el monitor serial con una frecuencia de 500ms.
Implementación de tareas FreeRTOS en Arduino IDE
1. De la explicación de la estructura básica anterior, incluya el archivo de encabezado Arduino FreeRTOS. Luego haga prototipos de funciones. Como tenemos tres tareas, haga tres funciones y sus prototipos.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); Void Taskprint (void * pvParameters);
2. En la función void setup () , inicialice la comunicación en serie a 9600 bits por segundo y cree las tres tareas utilizando la API xTaskCreate () . Inicialmente, establezca las prioridades de todas las tareas como '1' e inicie el programador.
configuración vacía () { Serial.begin (9600); xTaskCreate (TaskBlink1, "Task1", 128, NULL, 1, NULL); xTaskCreate (TaskBlink2, "Task2", 128, NULL, 1, NULL); xTaskCreate (Taskprint, "Task3", 128, NULL, 1, NULL); vTaskStartScheduler (); }
3. Ahora, implemente las tres funciones como se muestra a continuación para el parpadeo del LED de la tarea 1.
Void TaskBlink1 (void * pvParameters) { pinMode (8, SALIDA); while (1) { digitalWrite (8, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, BAJO); vTaskDelay (200 / portTICK_PERIOD_MS); } }
Del mismo modo, implemente la función TaskBlink2. La función Task3 se escribirá como
Void Taskprint (void * pvParameters) { int contador = 0; while (1) { contador ++; Serial.println (contador); vTaskDelay (500 / portTICK_PERIOD_MS); } }
Eso es. Hemos completado con éxito un proyecto Arduino FreeRTOS para Arduino Uno. Puede encontrar el código completo junto con un video al final de este tutorial.
Finalmente, conecte dos LED en el pin digital 7 y 8 y cargue el código en su placa Arduino y abra el monitor serial. Verá que un contador se está ejecutando una vez en 500 ms con el nombre de la tarea como se muestra a continuación.
Además, observe los LED, están parpadeando en diferentes intervalos de tiempo. Intente jugar con el argumento de prioridad en la función xTaskCreate . Cambie el número y observe el comportamiento en el monitor serie y los LED.
Ahora, puede comprender los dos primeros códigos de ejemplo en los que se crean tareas de lectura analógica y lectura digital. De esta manera, puede realizar proyectos más avanzados utilizando solo las API de Arduino Uno y FreeRTOS.