Quand on a plusieurs tâches qui s’exécutent dans une application, il y a forcément un moment où on a besoin de les synchroniser.
Cet article illustre l’utilisation des sémaphores simples (mutex) proposés par AvrX pour ce faire.
L’application
On reprend nos LEDs de l’article précédent, et on ajoute un bouton poussoir relié entre la masse et l’entrée PA0 de notre micro-contrôleur. Pour se simplifier la vie et éviter l’ajout de composants supplémentaires, on utilisera les résistances de pull-up interne du micro.
L’application consiste à faire changer l’état de la LED1 à chaque appui sur le poussoir. On allumera également la LED2 tant que le poussoir reste enfoncé, pour servir de témoin.
Petit rappel sur les sémaphores
Dans leur version la plus simple, les sémaphores peuvent avoir deux états : baissé et levé. Trois fonctions de base sont fournies par toute gestion de sémaphore :
– SetSemaphore qui lève le sémaphore
– ResetSemaphore qui le baisse
– WaitSemaphore qui bloque la tâche appelante tant que le sémaphore est baissé
Mise en oeuvre avec AvrX
La déclaration d’un sémaphore se fait grâce à la macro AVRX_MUTEX()
.
Les fonctions de manipulation et d’utilisation sont :
AvrXWaitSemaphore()
Attend qu’un sémaphore soit levé. S’il l’est déjà au moment de l’appel, il n’y a aucune attente. A noter également que le sémaphore est baissé au sortir de l’attente. Très important : cette fonction ne peut pas être appelée dans un handler d’interruption. D’ailleurs, qui voudrait bloquer l’exécution d’un gestionnaire d’interruption ?
AvrXSetSemaphore()
Lève le sémaphore. La version AvrXIntSetSemaphore()
permet de faire la même chose, mais depuis un gestionnaire d’interruption et sans redispatcher en fin d’appel
AvrXResetSemaphore()
Baisse le sémaphore. Comme pour sa copine, il existe aussi AvrXIntResetSemaphore
Il est également possible de tester un sémaphore sans bloquer au moyen de AvrXTestSemaphore()
et AvrXIntTestSemaphore()
.
Petite restriction par contre : AvrX ne permet qu’à une seule tâche d’être en attente sur un sémaphore donné. Je n’ai pas essayé de voir ce que ça pouvait donner. Je vous en laisse le soin 😉
Le source
Le voici, le voilà :
La tâche de gestion de la LED se contente de boucler, en attendant à chaque itération que le sémaphore soit levé pour basculer l’état de la LED.
La tâche de gestion du poussoir scrute l’entrée toute les 100 ms environ, en lorsqu’un changement d’état relâché/appuyé est détecté, elle lève le sémaphore. Afin de visualiser la prise en compte de l’action, on allume également une autre LED tant que le bouton est maintenu appuyé.
Au niveau du programme principal, il n’y a rien de plus que précédemment, si ce n’est la configuration du port A en entrée, avec les résistances de pull-up activées.
hardware.h
a été modifié pour ajouter les définitions relatives à la lecture du poussoir :
<docxxx|center>
Le makefile
Il a été modifié afin de regrouper tous les tutoriaux dans un seul makefile. Voici donc la nouvelle version :
Le nouveau mode opératoire est le suivant :