Bonjour, nous continuons le cours "Comprendre les microcontrôleurs". Et aujourd'hui, nous allons parler de manipulation de champs de bits. Oh, ne soyez pas effrayés de ce nom un petit peu compliqué. Il va s'agir tout simplement d'être capable de jouer avec des bits individuels à l'intérieur de registres. On va donc, au cours de cette leçon, chercher à manipuler d'une manière indépendante les bits pour les mettre mettre à 1, il s'agira du "set bit", les mettre à 0, le "clear bit", et en tester la valeur. Donc je rappelle la problématique : le microcontrôleur voit des ensembles de bits, des registres, par exemple 8 bits, c'est-à -dire un octet, un byte, ou encore 16 bits, ou encore 32 bits. Par contre l'application, qu'on est en train d'écrire, souhaite généralement voir des bits indépendants. Par exemple, j'ai un port, il y a deux diodes lumineuses connectées, il y a un bouton poussoir connecté, Je m'intéresse à chacune des diodes lumineuses, je m'intéresse au bouton poussoir, je n'ai pas envie de réfléchir au niveau d'un mot de 8 bits, j'ai bien envie de réfléchir plutôt à mes bits séparés. Comment utiliser le langage C pour faire ces manipulations de bits? Est-ce que cela engage qu'il, je vous le rappelle, a bien quelques dizaines d'années, avait été prévu pour faire ces opérations. Et bien oui, il a effectivement été prévu pour le faire. Je vous propose de commencer par un exemple, la mise à 1 d'un bit à l'intérieur d'un champs de bits, il s'agira donc de l'opération "set bit". Le mot "set" voulant dire aussi, en anglais, "mise à 1", "activer", "mettre à 1". Le problème se pose de la manière suivante. J'ai un registre, par exemple un registre de sortie, les valeurs qui sont dans X0 à X7 je ne les connais pas, je les ai notées de cette manière-là . Et je souhaite qu'après une opération bien faite, je me retrouve à avoir un 1 sur cette sortie. Mais que toutes les autres valeurs aient conservé leur valeur initiale. Je souhaite uniquement faire la mise à 1 de ce bit. Il me faut chercher une opération, donc ici une opération qui permet, avec un certain opérant, de faire le travail souhaité. Visiblement, une opération arithmétique ne va pas convenir pour ce type de travail. On va donc se tourner vers une opération logique. Et pour cela, il va falloir revenir à l'algèbre de Boole, dont on a un tout petit peu parlé au début de ce cours. Et je vais profiter de tester vos connaissances en vous posant la question : Quelle est la réponse à ces quatre formules, dont deux utilisent le "et" logique, deux autres utilisant le "ou" logique? Je vous laisse quelques secondes pour y réfléchir. La réponse est la suivante : X et 0 me donnent 0, On ne peut jamais avoir une sortie de type "et" à 1 lorsqu'il y a un 0. Par contre, X et 1 me donnent tantôt 1, tantôt 0 selon la valeur de X. Donc la réponse est X. De la même manière avec le "ou", lorsque j'ai un 0, je maintiens la valeur. Par contre lorsque j'ai un 1, c'est un 1 que j'aurai à la sortie. On dit parfois, en mathématique, que le 1 est l'élément neutre du "et" et que le 0 est l'élément neutre du "ou". Je reviens au problème qui se posait tout à l'heure. Je souhaite tantôt conserver la valeur, tantôt avoir un 1. Il faut donc que je cherche l'opération qui convient. On voit bien que c'est l'opération "ou" qui tantôt est capable de donner comme résultat la valeur X, tantôt la valeur 1. Il est donc facile de voir l'opérande que je dois utiliser. Le 0 étant l'élément neutre du "ou", je le place partout où je veux conserver la valeur et je place, ici, le 1 là où je souhaite obtenir un 1 après mon opération. J'ai donc la formule, il suffit de l'écrire en C. C'est l'occasion d'introduire un nouvel opérateur en C, que nous n'avons pas encore vu, il s'agit du "ou" logique qui est représenté par cette barre verticale. P1OUT, c'est ce qui correspond au "après" est affecté, c'est le signe égal, par la combinaison avec le "ou" logique de deux opérandes, P1OUT, c'est ce que j'avais avant, et cette valeur, que j'ai pour le moment écrite en binaire. En regardant cette formule, j'avoue que je ne suis pas du tout satisfait. Elle n'est pas très lisible. Nous allons essayer de trouver une manière plus simple d'écrire rigoureusement la même chose. Première étape, je vais commencer par essayer d'utiliser le "ou égal", qui est une syntaxe proposée par le C, qui permet de ne pas avoir à répéter le même opérande mais qui le sous-entend comme étant un des deux opérandes. C'est déjà plus compacte, un petit peu plus lisible. Par contre, cette valeur binaire n'est pas du tout lisible. Voyons ici, c'est le bit numéro 0, 1, 2, 3, 4, 5, 6, oui, c'est le bit numéro 6. C'est pas du tout évident à la première lecture. Je souhaite voir le chiffre 6 apparaître dans ma formule. Comme ça, immédiatement, je saurai qu'il s'agit du bit numéro 6. Pour cela, je vais devoir être un petit peu rusé. Je prends ici la valeur 1, que j'ai exprimée en binaire dans un registre. Si je la décale vers la gauche de six positions, j'obtiens ce résultat-là . Il se trouve que l'opération existe. Cet opérateur, qui se dessine par plus petit que, plus petit que, est le, l'opérateur de décalage à gauche. Il existe bien entendu aussi l'opérateur de décalage à droite. Donc, ici, la valeur 1 a été décalée de 6. Le résultat que j'obtiens, c'est évidemment un résultat sur 8 bits. C'est bits-là sont perdus et c'est bits-là ont été remplacés, conventionnellement, par des 0. Donc, cette expression peut s'écrire de la manière suivante : Je l'intègre directement à ma formule. 1 décalé à gauche de 6. Donc finalement, mon "set bit" peut s'écrire P1OUT "ou égal" 1 décalé de 6. Alors certains de mes étudiants m'ont dit : "mais, c'est quand même très ennuyeux, parce que, ici, nous avions une opération logique à faire, ici, nous avons une première puis une deuxième opération logique à faire. Ce qui va prendre du temps, prendre de la place dans la mémoire." Alors, ça n'est pas tout à fait juste. Ce calcul-là doit être fait par le microcontrôleur. Par contre, ce calcul-là , étant donné qu'il touche une constante et une deuxième constante, il ne va jamais changer. Ce résultat lui-même est une constante. Et alors, si c'est une constante, ça n'est pas le microcontrôleur qui devra la calculer, mais bel et bien le compilateur lui-même. Alors le compilateur, s'il a un tout petit peu plus de travail par cette ligne que par cette ligne, ça n'a aucune importance, le résultat de la compilation est identique. Ces deux lignes, je pourrais même dire ces trois lignes, donnent exactement le même résultat après la compilation. Donc je vais pouvoir maintenant me souvenir, mémoriser que le "set bit" peut se réaliser par cette combinaison "ou egal". Il reste à faire la même chose pour le "clear bit". La problématique est presque la même sauf qu'il faut mettre un 0. On a de nouveau les lois de l'algèbre de Boole et cette fois c'est le "et" logique qui va nous intéresser. Et alors, l'opérande aura cette allure-là . Les éléments neutres, les 1 comme éléments neutres du "et" losqu'on veut conserver la valeur, et le 0 pour imposer le 0 à la sortie. Donc je peux l'écrire de cette manière-là . De nouveau, on va chercher à utiliser une syntaxe plus simple, plus lisible. On regroupe avec le "ou égal". Reste le problème de cette valeur. Ici, c'est le bit numéro 6 qui m'intéresse et c'est le seul qui est à 0. Alors j'ai parfois un étudiant distrait qui me dit : "mais monsieur, pourquoi ne peut-on pas écrire 0 décalé à gauche de 6 ?" Et bien la réponse est évidente, si je prends 0, que je le décale à gauche de 6 cases, j'obtiens toujours un 0. Or, dans ce cas, c'est bien ces 1 qui m'intéressent, et le 0 naturellement. La syntaxe qu'on va utiliser est la suivante. Elle utilise un opérateur qui nous est encore inconnu, qui s'appelle l'opérateur d'inversion bit à bit, et qui utilise ce symbole Tilde, c'est comme ça qu'on l'appelle. Je vous signale juste que c'est, en espagnol, un accent. Donc que quand on le tape sous certains éditeurs, il ne vient pas, il se présente comme un accent flottant et qu'il faut taper un espace pour qu'il apparaisse en tant que caractère. Et alors finalement, on va pouvoir se souvenir du fait que l'opération "clear bit", mise à 0 d'un bit, se fait avec cet ensemble "et égal tilde". Et j'aimerais bien qu'on apprenne à reconnaître le "ou égal" d'une part, le "et égal tilde" comme étant la manière d'écrire le "set bit" et le "clear bit". Les opérations "set bit" et "clear bit", que nous venons de voir, sont évidemment principalement utilisées pour les sorties. Comment maintenant gérer une entrée? Alors, on cherche, généralement, à tester une entrée. Par exemple "if" et on souhaite mettre la condition qui permet de savoir si le bouton start a été pressé. Pour pouvoir avancer, il faut que je vous rappelle une chose, le langage C n'a pas de type booléen et pour lui, une valeur nulle correspond à faux et une valeur non nulle correspond à vrai. Parfois les gens disent la valeur 1 correspond à vrai. C'est juste, mais la valeur 33 aussi correspond à vrai. Une valeur non nulle est considérée comme vraie et nous allons utiliser cette astuce pour tester notre entrée. Voilà le problème : j'ai 8 valeurs, s'il s'agit d'un registre 8 bits, je m'intéresse à savoir si j'ai un 0 ici en position 3, ici, au contraire, j'ai un 1. Et j'aimerais pouvoir dire : dans ce cas-là , c'est faux, dans ce cas-là , c'est vrai. L'unique présence de ce 1 va pouvoir me faire comprendre que c'est vrai. Et la même chose, ce 0 entraîne que la condition est fausse. Je rappelle que faux, c'est une valeur nulle, que vrai c'est une valeur non nulle. Quelle opération dois-je utiliser maintenant pour faire disparaître tous ces bits qui ne m'intéressent pas? Et bien, il s'agit évidemment de l'opération logique "et". Je mets une valeur 1 à cet endroit. J'obtiens, si j'avais un 0, un 0, si j'avais un 1, j'obtiens un 1. Partout ailleurs, ces 0 que j'ai mis là me donnent des valeurs nulles. Et si je regarde maintenant globalement cette valeur, elle est complètement nulle, c'est donc une condition fausse. Cette valeur-là n'est pas nulle, à cause de ce 1. Elle rend donc la condition "vraie". Il ne reste plus qu'à l'écrire en C. Ma condition, ici, s'écrit de la manière suivante : par exemple, P1IN "et" 1 décalé de 3. Je vous propose que nous écrivions un petit exemple qui utilise ces trois notions que nous venons de voir. Ici, nous avons sur une entrée, un bouton qui s'appelle "on", sur une autre entrée, un bouton qui s'appelle "off", sur une sortie, nous avons une diode lumineuse. Pour marquer que ce schéma n'est pas complet, je n'ai pas pris la peine d'indiquer l'alimentation, de mentionner le condensateur de découplage, qu'il est juste de mettre entre le plus et le moins, je n'ai pas parlé non plus du reset, de la patte test. C'est un schéma simplifié étant donné que j'ai l'habitude d'utiliser mon microcontrôleur, souvent pour donner des explications, je ne répète pas tous ces détails. Alors j'ai écrit ici le programme. Certes, volontairement, il n'utilise pas les simplifications que nous avons appris à utiliser pour rendre les programmes plus lisibles. L'objectif, ici, est vraiment de montrer quelles sont les opérations qu'on utilise. Je dois mettre à 1 le bit numéro 6 de direction pour avoir ma LED en sortie. Je fais un "ou égal". Je dois mettre à 1 les deux bits 2 puissance 2 et 2 puissance 3 de mon registre P1OUT pour enclencher les résistances en pull up. Nous n'avons pas encore vu cette partie-là , on la verra plus tard, mais comprenez bien ici que c'est des "ou égal", donc que c'est des "set bit". Au niveau de ma boucle principale, qui s'exécute de manière infinie, je vais tester le bit 2 dans P1IN, pour savoir si le bouton "on" est allumé. Vous ferez la même chose un peu plus tard avec le 2 puissance 3, qui correspond au bouton "off". Si le bouton "on" est actif, je vais allumer la diode lumineuse. Si, au contraire, le bouton "off" est actif, je vais éteindre la diode lumineuse. Pourquoi ai-je dû rajouter, ici, ce point d'exclamation? Je vous signale juste que c'est lié au fait que nous avons cablé les boutons "on" et "off" à la masse. Dans un prochain cours, nous aurons des explications très précises sur l'usage de ce point d'exclamation qui signifie l'inversion d'une condition logique. Nous avons donc appris que le langage C permet de manipuler des bits à l'intérieur de champs de bits, à l'intérieur de registres. On peut réaliser la fonction de mise à 1 d'un bit avec le "ou égal". On peut réaliser la fonction de mise à 0 d'un bit avec le "et égal tilde". Et qu'on peut tester un bit en masquant, en faisant le "et" logique avec la valeur lue.