- Comment fonctionne RTOS?
- Termes fréquemment utilisés dans RTOS
- Installation de la bibliothèque Arduino FreeRTOS
- Schéma
- Exemple Arduino FreeRTOS - Création de tâches FreeRTOS dans Arduino IDE
- Implémentation de tâches FreeRTOS dans l'IDE Arduino
Le système d'exploitation présent à l'intérieur des périphériques embarqués est appelé un RTOS (Real-Time Operating System). Dans les appareils embarqués, les tâches en temps réel sont essentielles où la synchronisation joue un rôle très important. Les tâches en temps réel sont déterministes dans le temps, ce qui signifie que le temps de réponse à tout événement est toujours constant afin qu'il puisse être garanti qu'un événement particulier se produira à un moment donné. RTOS est conçu pour exécuter des applications avec un timing très précis et un haut degré de fiabilité. RTOS aide également au multitâche avec un seul cœur.
Nous avons déjà couvert un tutoriel sur la façon d'utiliser RTOS dans les systèmes embarqués où vous pouvez en savoir plus sur RTOS, la différence entre OS général et RTOS, différents types de RTOS, etc.
Dans ce tutoriel, nous allons commencer avec FreeRTOS. FreeRTOS est une classe de RTOS pour les périphériques embarqués qui est suffisamment petite pour être exécutée sur des microcontrôleurs 8/16 bits, bien que son utilisation ne se limite pas à ces microcontrôleurs. C'est un logiciel complètement open-source et son code est disponible sur github. Si nous connaissons certains concepts de base de RTOS, alors il est très facile d'utiliser FreeRTOS car il possède des API bien documentées qui peuvent être directement utilisées dans le code sans connaître la partie backend du codage. La documentation complète de FreeRTOS peut être trouvée ici.
Comme FreeRTOS peut fonctionner sur un MCU 8 bits, il peut également être exécuté sur la carte Arduino Uno. Nous devons simplement télécharger la bibliothèque FreeRTOS, puis commencer à implémenter le code à l'aide d'API. Ce tutoriel est destiné à un débutant complet, voici les sujets que nous aborderons dans ce tutoriel Arduino FreeRTOS:
- Comment fonctionne RTOS
- Quelques termes fréquemment utilisés dans RTOS
- Installation de FreeRTOS dans Arduino IDE
- Comment créer des tâches FreeRTOS avec un exemple
Comment fonctionne RTOS?
Avant de commencer à travailler avec RTOS, voyons ce qu'est une tâche. La tâche est un morceau de code qui peut être programmé sur le processeur pour être exécuté. Donc, si vous souhaitez effectuer une tâche, elle doit être planifiée en utilisant le délai du noyau ou en utilisant des interruptions. Ce travail est effectué par Scheduler présent dans le noyau. Dans un processeur monocœur, le planificateur aide les tâches à s'exécuter dans une tranche de temps particulière, mais il semble que différentes tâches s'exécutent simultanément. Chaque tâche s'exécute selon la priorité qui lui est donnée.
Maintenant, voyons ce qui se passe dans le noyau RTOS si nous voulons créer une tâche pour le clignotement des LED avec un intervalle d'une seconde et mettre cette tâche sur la priorité la plus élevée.
En dehors de la tâche LED, il y aura une autre tâche qui est créée par le noyau, elle est connue comme une tâche inactive. La tâche inactive est créée lorsqu'aucune tâche n'est disponible pour exécution. Cette tâche s'exécute toujours sur la priorité la plus basse, c'est-à-dire 0 priorité. Si nous analysons le graphique de synchronisation donné ci-dessus, on peut voir que l'exécution commence par une tâche LED et qu'elle s'exécute pendant un temps spécifié, puis pendant le temps restant, la tâche inactive s'exécute jusqu'à ce qu'une interruption de tick se produise. Ensuite, le noyau décide quelle tâche doit être exécutée en fonction de la priorité de la tâche et du temps total écoulé de la tâche LED. Quand 1 seconde est terminée, le noyau choisit à nouveau la tâche led à exécuter car elle a une priorité plus élevée que la tâche inactive, nous pouvons également dire que la tâche LED précède la tâche inactive. S'il y a plus de deux tâches avec la même priorité, elles s'exécuteront en mode round-robin pendant une durée spécifiée.
Sous le diagramme d'état, il montre le passage de la tâche non en cours à l'état en cours d'exécution.
Chaque tâche nouvellement créée passe à l'état Prêt (partie de l'état non en cours d'exécution). Si la tâche créée (Task1) a la priorité la plus élevée que les autres tâches, elle passera à l'état d'exécution. Si cette tâche en cours prévaut sur l'autre tâche, elle reviendra à l'état prêt. Sinon, si la tâche 1 est bloquée à l'aide de l'API de blocage, le processeur ne s'engagera pas dans cette tâche avant le délai défini par l'utilisateur.
Si Task1 est suspendu à l'état d'exécution à l'aide des API Suspend, Task1 passe à l'état Suspendu et n'est plus disponible pour le planificateur. Si vous reprenez Task1 à l'état suspendu, il reviendra à l'état prêt comme vous pouvez le voir dans le diagramme.
C'est l' idée de base de la manière dont les tâches s'exécutent et modifient leurs états. Dans ce tutoriel, nous allons implémenter deux tâches dans Arduino Uno à l'aide de l'API FreeRTOS.
Termes fréquemment utilisés dans RTOS
1. Tâche: C'est un morceau de code qui peut être programmé sur le CPU à exécuter.
2. Planificateur: il est chargé de sélectionner une tâche de la liste d'état prêt à l'état en cours d'exécution. Les planificateurs sont souvent mis en œuvre afin de maintenir toutes les ressources informatiques occupées (comme dans l'équilibrage de charge).
3. Préemption: c'est l'acte d'interrompre temporairement une tâche déjà en cours d'exécution avec l'intention de la retirer de l'état en cours sans sa coopération.
4. Changement de contexte: dans la préemption basée sur la priorité, le planificateur compare la priorité des tâches en cours d'exécution avec une priorité de la liste des tâches prêtes à chaque interruption systick . S'il y a une tâche dans la liste dont la priorité est supérieure à la tâche en cours d'exécution, un changement de contexte se produit. Fondamentalement, dans ce processus, le contenu des différentes tâches est enregistré dans leur mémoire de pile respective.
5. Types de politiques de planification:
- Planification préventive: dans ce type de planification, les tâches s'exécutent avec une tranche de temps égale sans tenir compte des priorités.
- Préemption basée sur la priorité: la tâche à haute priorité s'exécutera en premier.
- Planification coopérative: le changement de contexte ne se produira qu'avec la coopération des tâches en cours d'exécution. La tâche fonctionnera en continu jusqu'à ce que le rendement de la tâche soit appelé.
6. Objets du noyau: pour signaler à la tâche d'effectuer un certain travail, le processus de synchronisation est utilisé. Pour effectuer ce processus, des objets noyau sont utilisés. Certains objets du noyau sont des événements, des sémaphores, des files d'attente, des mutex, des boîtes aux lettres, etc. Nous verrons comment utiliser ces objets dans les prochains tutoriels.
De la discussion ci-dessus, nous avons quelques idées de base sur le concept RTOS et maintenant nous pouvons implémenter le projet FreeRTOS dans Arduino. Alors, commençons par installer les bibliothèques FreeRTOS dans Arduino IDE.
Installation de la bibliothèque Arduino FreeRTOS
1. Ouvrez l'IDE Arduino et allez dans Sketch -> Inclure la bibliothèque -> Gérer les bibliothèques . Recherchez FreeRTOS et installez la bibliothèque comme indiqué ci-dessous.
Vous pouvez télécharger la bibliothèque depuis github et ajouter le fichier.zip dans Sketch-> Inclure la bibliothèque -> Ajouter un fichier .zip .
Maintenant, redémarrez l'IDE Arduino. Cette bibliothèque fournit des exemples de code, également disponibles dans Fichier -> Exemples -> FreeRTOS comme indiqué ci-dessous.
Ici, nous écrirons le code à partir de zéro pour comprendre le fonctionnement, plus tard, vous pourrez vérifier les exemples de codes et les utiliser.
Schéma
Vous trouverez ci-dessous le schéma de circuit pour créer une tâche LED clignotante à l'aide de FreeRTOS sur Arduino:
Exemple Arduino FreeRTOS - Création de tâches FreeRTOS dans Arduino IDE
Voyons une structure de base pour écrire un projet FreeRTOS.
1. Tout d'abord, incluez le fichier d'en-tête Arduino FreeRTOS comme
#comprendre
2. Donnez le prototype de fonction de toutes les fonctions que vous écrivez pour exécution, qui s'écrit
void Task1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Maintenant, dans la fonction void setup () , créez des tâches et démarrez le planificateur de tâches.
Pour créer une tâche, l' API xTaskCreate () est appelée dans la fonction de configuration avec certains paramètres / arguments.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Il y a 6 arguments qui doivent être passés lors de la création d'une tâche. Voyons quels sont ces arguments
- pvTaskCode: C'est simplement un pointeur vers la fonction qui implémente la tâche (en fait, juste le nom de la fonction).
- pcName: nom descriptif de la tâche. Ceci n'est pas utilisé par FreeRTOS. Il est inclus uniquement à des fins de débogage.
- usStackDepth: chaque tâche a sa propre pile unique qui est allouée par le noyau à la tâche lorsque la tâche est créée. La valeur spécifie le nombre de mots que la pile peut contenir, et non le nombre d'octets. Par exemple, si la pile a une largeur de 32 bits et que usStackDepth est passé en tant que 100, alors 400 octets d'espace de pile seront alloués (100 * 4 octets) dans la RAM. Utilisez-le à bon escient car Arduino Uno ne dispose que de 2 Ko de RAM.
- pvParameters: paramètre d'entrée de la tâche (peut être NULL).
- uxPriority: Priorité de la tâche (0 est la priorité la plus basse).
- pxCreatedTask: Il peut être utilisé pour transmettre un handle à la tâche en cours de création. Ce handle peut ensuite être utilisé pour référencer la tâche dans les appels d'API qui, par exemple, modifient la priorité de la tâche ou suppriment la tâche (peut être NULL).
Exemple de création de tâches
xTaskCreate (tâche1, "tâche1", 128, NULL, 1, NULL); xTaskCreate (tâche2, "tâche2", 128, NULL, 2, NULL);
Ici, Task2 a une priorité plus élevée et s'exécute donc en premier.
4. Après avoir créé la tâche, démarrez le planificateur dans une configuration vide à l'aide de vTaskStartScheduler (); API.
5. La fonction Void loop () restera vide car nous ne voulons exécuter aucune tâche manuellement et indéfiniment. Parce que l'exécution des tâches est désormais gérée par Scheduler.
6. Maintenant, nous devons implémenter des fonctions de tâche et écrire la logique que vous voulez exécuter à l'intérieur de ces fonctions. Le nom de la fonction doit être le même que le premier argument de l' API xTaskCreate () .
void task1 (void * pvParameters) { while (1) { .. ..//your logic } }
7. La plupart du code nécessite une fonction de retard pour arrêter la tâche en cours, mais dans RTOS, il n'est pas suggéré d'utiliser la fonction Delay () car elle arrête le CPU et donc RTOS cesse également de fonctionner. FreeRTOS a donc une API noyau pour bloquer la tâche pendant un temps spécifique.
vTaskDelay (const TickType_t xTicksToDelay);
Cette API peut être utilisée à des fins de retard. Cette API retarde une tâche pour un nombre donné de ticks. Le temps réel pendant lequel la tâche reste bloquée dépend du taux de ticks. La constante portTICK_PERIOD_MS peut être utilisée pour calculer en temps réel à partir du taux de ticks .
Cela signifie que si vous voulez un délai de 200 ms, écrivez simplement cette ligne
vTaskDelay (200 / portTICK_PERIOD_MS);
Donc, pour ce tutoriel, nous utiliserons ces API FreeRTOS pour implémenter trois tâches.
API à utiliser:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Tâche à créer pour ce tutoriel:
- La LED clignote sur la broche numérique 8 avec une fréquence de 200 ms
- La LED clignote à la broche numérique 7 avec une fréquence de 300 ms
- Imprimez les numéros sur le moniteur série avec une fréquence de 500 ms.
Implémentation de tâches FreeRTOS dans l'IDE Arduino
1. À partir de l'explication de la structure de base ci-dessus, incluez le fichier d'en-tête Arduino FreeRTOS. Créez ensuite des prototypes de fonctions. Comme nous avons trois tâches, faites donc trois fonctions et ses prototypes.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); void Taskprint (void * pvParameters);
2. Dans la fonction void setup () , initialisez la communication série à 9600 bits par seconde et créez les trois tâches à l'aide de l' API xTaskCreate () . Initialement, définissez les priorités de toutes les tâches sur «1» et démarrez le planificateur.
void setup () { 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. Maintenant, implémentez les trois fonctions comme indiqué ci-dessous pour le clignotement du voyant de la tâche 1.
void TaskBlink1 (void * pvParameters) { pinMode (8, OUTPUT); while (1) { digitalWrite (8, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, FAIBLE); vTaskDelay (200 / portTICK_PERIOD_MS); } }
De même, implémentez la fonction TaskBlink2. La fonction Task3 sera écrite comme
void Taskprint (void * pvParameters) { compteur int = 0; while (1) { compteur ++; Serial.println (compteur); vTaskDelay (500 / portTICK_PERIOD_MS); } }
C'est ça. Nous avons terminé avec succès un projet FreeRTOS Arduino pour Arduino Uno. Vous pouvez trouver le code complet avec une vidéo à la fin de ce didacticiel.
Enfin, connectez deux LED aux broches numériques 7 et 8 et téléchargez le code sur votre carte Arduino et ouvrez le moniteur série. Vous verrez qu'un compteur s'exécute une fois toutes les 500 ms avec le nom de la tâche comme indiqué ci-dessous.
Observez également les voyants, ils clignotent à des intervalles de temps différents. Essayez de jouer avec l'argument de priorité dans la fonction xTaskCreate . Modifiez le numéro et observez le comportement sur le moniteur série et les voyants.
Vous pouvez maintenant comprendre les deux premiers exemples de codes dans lesquels des tâches de lecture analogique et de lecture numérique sont créées. De cette manière, vous pouvez réaliser des projets plus avancés en utilisant uniquement les API Arduino Uno et FreeRTOS.