Changes between Version 2 and Version 3 of SysCom19
- Timestamp:
- Oct 9, 2019, 6:06:40 AM (6 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
SysCom19
v2 v3 18 18 - La photorésistance 19 19 20 = Démarrage (rappel)20 = Test du matériel 21 21 22 22 Pour s'assurer que le module Arduino et la chaîne de compilation sont fonctionnels, vous pouvez reprendre l'exemple `blink`` … … 33 33 - La led doit clignoter sur le module 34 34 35 = Exécution ''multi-tâches'' 36 37 == Principe 38 39 Il est possible de programmer des applications multi-tâches coopératives dans l'environnement Arduino sans pour autant disposer des services d'un OS. Le principe a été volontairement simplifié à l'extrême. Ici, toute l'application sera dans un seul fichier. 35 = Principe d'exécution multi-tâches 36 37 Il est possible de programmer des applications multi-tâches coopératives dans l'environnement Arduino sans pour autant disposer des services d'un OS. Le principe est volontairement simplifié à l'extrême. Ici, toute l'application sera dans un seul fichier. 40 38 Nous n'allons pas utiliser la programmation objet pour ne pas complexifier, mais ce serait possible pour une application plus ambitieuse pour une meilleure maintenance. 41 39 … … 45 43 Les ISR (Interrupt Service Routine) qui sont des fonctions exécutées lors de la survenue d'interruption sont considérée comme des tâches. 46 44 47 == Tâches 48 49 Chaque tâche est représentée par 50 * une fonction `loop_Tache()` qui code son comportement qui sera appelée dans la fonction `loop()`. 45 Chaque tâche est représentée deux fonctions `loop_Tache()` et `setup_Tache()` 46 * La fonction `loop_Tache()` code le comportement de la tâche. Elle es appelée dans la fonction `loop()`. 51 47 Dans cet exemple l'application a trois tâches : la tâche 1 est répliquée 2 fois et la tâche 2 n'a 52 48 {{{#!c 53 49 loop() { 54 loop_ tache1(args...); // 1er réplica de la tâche 155 loop_ tache1(args...); // 2nd réplica de la tache 156 loop_ tache2(args...); // unique réplica de la tâche 250 loop_Tache1(args...); // 1er réplica de la tâche 1 51 loop_Tache1(args...); // 2nd réplica de la tache 1 52 loop_Tache2(args...); // unique réplica de la tâche 2 57 53 } 58 54 }}} … … 60 56 Les tâches n'ont pas le droit de conserver le processeur sinon cela crée un blocage du système. 61 57 Cela signifie qu'il est interdit de faire des boucles d'attente d'un événement. 62 63 58 La fonction loop() est en fait un ordonnanceur de tâche suivant un algorithme FIFO statique. 64 59 65 60 La fonction loop() ignore si la tâche est en mesure d'avancer. Les tâches sont toujours "prêtes". 66 C'est chaque tâche qui doit vérifier si elle peut avancer , par exemple si les données61 C'est chaque tâche qui doit vérifier si elle peut avancer ou pas, par exemple si les données 67 62 attendues sont disponible ou si assez de temps c'est écoulé depuis la dernière instance d'exécution. 68 63 Si oui elle avance, sinon elle sort immédiatement et la tâche suivante dans la liste est exécutée. 69 64 70 * une seconde fonction `setup_Tache()` quiinitialise les ressources matérielles assignées de la tâche (périphériques) et l'état interne (voir plus loin).65 * La seconde fonction `setup_Tache()` initialise les ressources matérielles assignées de la tâche (périphériques) et l'état interne (voir plus loin). 71 66 {{{#!c 72 67 setup() { 73 setup_ tache1(args...); // setup du 1er réplica de la tâche 174 setup_ tache1(args...); // setup du 2nd réplica de la tache 175 setup_ tache2(args...); // setup de l'unique réplica de la tâche 268 setup_Tache1(args...); // setup du 1er réplica de la tâche 1 69 setup_Tache1(args...); // setup du 2nd réplica de la tache 1 70 setup_Tache2(args...); // setup de l'unique réplica de la tâche 2 76 71 } 77 72 }}} … … 84 79 - Elles peuvent aussi avoir des variables `static`. Ces variables ont une valeur 85 80 unique pour toutes les réplicas d'une tâche. 81 - Ces variables définissent donc un état interne partagé par tous les réplicas. 86 82 * Variables de contexte d'exécution : 87 - Enfin chaque réplica de tâche dispose d'une structure contenant son état interne ,88 lequel est conservé entre deux instance d'exécution d e latâche.83 - Enfin chaque réplica de tâche dispose d'une structure contenant son état interne propre, 84 lequel est conservé entre deux instance d'exécution du réplica de tâche. 89 85 Le contexte d'exécution représenté par une variable globale du programme sous forme d'une structure. 90 86 Une structure différente est passée en argument de chaque réplica de tâche dans les arguments … … 99 95 }}} 100 96 101 C'est la fonction `setup_Tache()` qui va devoir initialiser le contexte avec des arguments97 C'est la fonction `setup_Tache()` qui initialise l'état interne des tâches 102 98 {{{#!c 103 99 void setup_Tache(struct Tache_st *ctx, args...) { 100 stat type etat_tache; 101 // Initialisation de l'état interne commun a tous les réplica 102 etat_tache = etat_initial; // reçu dans les args 104 103 // Initialisation du contexte} 105 ctx->etat = etat_initial; // reçu dans les paramètres104 ctx->etat = etat_initial; // reçu dans les args 106 105 ... 107 106 } 108 107 }}} 109 108 110 = = Communication entretâches111 112 L es tâches communiquent entre elles par des variables globales de l'application.113 Chaque tâche reçoit en argument les pointeurs vers les variables qu'elle utilise pour communiquer.114 Ces pointeurs sont nommés connecteurs (ou ports).109 = Communications inter-tâches 110 111 Lorsqu'on écrit un programme multi-tâches, les tâches communiquent entre elles. Pour ce faire, nous allons simplement créer variables globales et les donner en arguments aux tâches. 112 Chaque tâche reçoit donc en argument les pointeurs vers les variables qu'elle utilise pour communiquer. 113 Ces pointeurs sont nommés des ports. 115 114 116 115 La structure forme de la fonction loop d'une tâche est donc : 117 116 {{{#!c 118 void loop_Tache(struct Tache_st *ctx, connectors....) {117 void loop_Tache(struct Tache_st *ctx, ports....) { 119 118 // test de la condition d'exécution, si absent on SORT 120 119 if (evement_attendu_absent) return; … … 124 123 }}} 125 124 125 Supposons que nous voulions que la tâche T1 envoie un message à la tâche T2. Nous allons utiliser une boite à lettre. Le code suivant explique le principe qui est basé sur une variable d'état à 2 valeur indiquant l'état de la boîte. La boîte peut être vide ou pleine. 126 l'écrivain T1 ne peut écrire que lorsque la boîte est vide. Lorsqu'elle est vide, il y écrit et il change l'état. Inversement, le lecteur attend qu'elle soit pleine. Lorsqu'elle est pleine, il la lit et change l'état. 127 128 Il s'agit d'une communication sans perte. Si T1 ne testait pas l'état de la boîte, on pourrait avoir des pertes, c'est parfois nécessaire, si T2 n'a pas eu le temps d'utiliser la boîte mais que T1 a une nouvelle valeur, il peut écraser la valeur présente. 129 130 {{{#!c 131 struct mailbox { 132 enum {EMPTY, FULL} state; // Création d'une boite vide 133 int val; 134 } mb0 = {.state = EMPTY}; 135 136 struct T1_st {...} T1; // Création de 2 contextes d'exécution 137 struct T2_st {...} T2; 138 139 void setup_T1(struct T1_st *T1, args...) {...} // Déclaration des fonctions setup de tâche 140 void setup_T2(struct T2_st *T2, args...) {...} 141 142 void loop_T1(struct T1_st *T1, struct mailbox *mb) { 143 if (mb->state != EMPTY) return; // attend que la mailbox soit vide 144 mb->val = 42; 145 mb->state = FULL; 146 } 147 148 void loop_T2(struct T1_st *T1, struct mailbox *mb) { 149 if (mb->state != FULL) return; // attend que la mailbox soit pleine 150 // usage de mb->val 151 mb->state = EMPTY; 152 } 153 setup() { 154 setup_T1(&T1, args...); 155 setup_T2(&T2, args...); 156 } 157 158 loop() { 159 loop_T1(&T1, &mb0); 160 loop_T2(&T2, &mb0); 161 } 162 }}} 163 126 164 == Gestion des tâches standard périodiques 127 165 128 Pour les tâches périodiques (elles sont fréquentes), nous pouvons écrire une fonction qui exploite un timer interne du processeur qui s'incrémente chaque microseconde. Cette fonction nommée `waitFor(int timer, unsigned long period)` prend deux paramètres `timer` et `period`. Le premier un numéro de timer (il en faudra autant que de tâches périodiques). Le second est une période en microsecondes. 166 Pour les tâches périodiques (elles sont fréquentes), nous pouvons écrire une fonction qui exploite un timer interne du processeur qui s'incrémente chaque microseconde. Cette fonction nommée : 167 {{{#!c 168 waitFor(int timer, unsigned long period) 169 }}} 170 Elle prend deux paramètres `timer` et `period`. Le premier un numéro de timer (il en faudra autant que de tâches périodiques). Le second est une période en microsecondes. 129 171 130 172 `wairFor()` peut être appelée aussi souvent que nécessaire, elle rend la valeur 1 une seule fois par période (second paramètre). … … 252 294 253 295 254 = Communications inter-tâches255 256 Lorsqu'on écrit un programme multi-tâches, il est intéressant de les faire communiquer. Pour ce faire, nous allons simplement créer variables globales et les donner en arguments aux taches communicantes.257 258 Supposons que nous voulions que la tâche T1 envoie un message à la tâche T2. Nous allons utiliser une boite à lettre. Le code suivant explique le principe qui est basé sur une variable d'état à 2 valeur indiquant l'état de la boite. La boite peut être vide ou pleine.259 l'écrivain T1 ne peut écrire que lorsque la boite est vide. Lorsqu'elle est vide, il y écrit et il change l'état. Inversement, le lecteur attend qu'elle soit pleine. Lorsqu'elle est pleine, il la lit et change l'état.260 261 Il s'agit d'une communication sans perte. Si T1 ne testait pas l'état de la boite, on pourrait avoir des pertes, c'est parfois nécessaire, si T2 n'a pas eu le temps d'utiliser la boite mais que T1 a une nouvelle valeur, il peut écraser la valeur présente.262 {{{#!c263 struct mailbox {264 enum {EMPTY, FULL} state;265 int val;266 } mb0 = {.state = EMPTY};267 268 void loop_T1(&mb) {269 if (mb->state != EMPTY) return; // attend que la mailbox soit vide270 mb->val = 42;271 mb->state = FULL;272 }273 274 void loop_T2(&mb) {275 if (mb->state != FULL) return; // attend que la mailbox soit pleine276 // usage de mb->val277 mb->state = EMPTY;278 }279 }}}280 281 296 **Questions** 282 297