[AUDIO_VIDE] Bonjour, pour utiliser au mieux les micro contrôleurs pour commander des enseignes et afficheurs à LED il faut bien connaître comment fonctionnent les broches d'entrée et sortie. C'est ce que nous allons voir, en regardant tout d'abord, exactement, les différents rôles possibles des broches d'entrée et sortie, en regardant ensuite comment s'organisent, en interne, les registres, et nous prendrons le cas de l'AVR et du MSP430. Nous apprendrons aussi à tirer partie des opérations logiques en C pour agir sur un bit à la fois. Et finalement, nous regarderons comment écrire proprement les constantes, pour rendre nos programmes aussi lisibles que possible. Les micro contrôleurs ont donc des broches, utilisées en entrée et en sortie, on les appelle parfois des GPIO, General Purpose Input Output, donc des entrées et sorties à usage général. Avec la librairie Arduino, le choix du mode de fonctionnement d'une broche se fait par pinMode, la lecture se fait par digitalRead, et l'écriture se fait par digitalWrite. Cette librairie a justement pour rôle de cacher ce qui se passe à l'intérieur du micro contrôleur, et c'est ce que nous voulons découvrir aujourd'hui. Ces procédures Arduino ont l'avantage d'être simples, mais ne sont pas toujours optimales. Par exemple, l'accès ne se fait qu'une seule broche à la fois, le temps d'exécution est souvent important, et la taille mémoire est peu optimale. On va chercher à faire mieux pour nos enseignes et afficheurs à LED. Regardons en détail les différents rôles possibles des broches. Une broche peut être une entrée. Elle est naturellement à haute impédance, à cause de l'utilisation de la technologie CMOS. Dans beaucoup de cas, il est nécessaire d'avoir une résistance de tirage. Par exemple un tirage vers le haut, appelé, pull-up, en anglais. Prenons l'exemple d'un interrupteur, connecté à la broche d'un micro contrôleur. Lorsque l'interrupteur est fermé, avec ce schéma, ici, nous avons, d'une manière fiable, un zéro, sur la broche du micro contrôleur. Et lorsque l'interrupteur est ouvert, on a en fait un état à haute impédance, on ne sait pas quelle valeur se trouve sur l'entrée. Les micro contrôleurs étant réalisés en technologie CMOS, cette haute impédance de l'entrée a pour conséquence que on ne sait pas la valeur, zéro ou 1, qu'on va lire à un instant donné, dans le cas où l'interrupteur est ouvert. Alors, on a l'habitude d'ajouter une résistance, qui tire vers le haut, de telle manière que, lorsque l'interrupteur est ouvert, on ait un état, 1, qui arrive sur l'entrée. À noter que la plupart des micro contrôleurs modernes peuvent intégrer cette résistance, il est possible de l'enclencher par programmation, pour ne pas avoir besoin de l'implémenter à l'extérieur. Certains micro contrôleurs offrent ce même mécanisme, mais à tirage vers le bas, Pull-down Resister. Maintenant, lorsqu'une broche est une sortie, eh bien elle peut prendre l'état logique, zéro, ou l'état logique 1. À zéro, un transistor de type NMOS va tirer la broche vers le zéro. À 1, c'est un transistor PMOS qui va tirer la broche vers le 1. À l'intérieur des micro contrôleurs, les broches ne sont pas indépendantes. Elles sont regroupées par ports, et ces ports ont généralement huit bits, parfois 16 ou même 32 bits. Un port peut éventuellement être incomplet, sur un modèle donné de micro contrôleur, en fonction du nombre de broches à disposition. Les noms des ports dépendent des familles de micro contrôleurs. On accède aux broches et à leur rôle, à leur fonction, par des registres internes aux micro contrôleurs. Par exemple, sur le micro contrôleur PIC, il y a un registre qui s'appelle PORT A, un registre qui s'appelle TRIS ; sur les AVR, les registres correspondants s'appellent PORT A, DDR A, plus PIN A ; encore des noms différents pour les MSP 430, P1DIR, P1OUT, P1IN, P1REN. On a souvent les mêmes concepts qui s'appliquent à des noms différents. Essayons d'y voir un petit peu plus clair. Prenons l'exemple du micro contrôleur AVR, les ports s'appellent, PORT A, PORT B, etc. Je noterai dans mes exemples ce qui correspond au PORT A. Les huit broches du PORT A s'appellent PA0, PA1, etc. jusqu'à PA7. Trois registres sont utilisés pour piloter chaque port. Le premier s'appelle DDR A, ça signifie, Data Direction Register, c'est donc le registre qui permet de fixer la direction de la broche, c'est-à -dire de dire si c'est une entrée ou une sortie. Le deuxième registre s'appelle PORT A, c'est le registre de sortie, lorsqu'une broche est utilisée en sortie. C'est ce registre qui sera utilisé pour donner la valeur. PIN A, lui, n'est pas à proprement parler un registre. C'est une adresse dans laquelle on peut lire l'état de chaque broche. Regardons plus en détail comment utiliser les deux registres, DDR A et PORT A, pour utiliser une entrée ou une sortie. Il faut donc bien comprendre que nous avons un registre huit bits, DDR A, un registre huit bits, PORT A ; ces deux bits correspondent à la broche PA0, ces deux à PA1, PA2. Par exemple, ici, c'est le bit numéro six, PA6. On a une valeur dans DDR, une valeur dans PORT, voilà les combinaisons qu'on peut avoir. Lorsque DDR est à zéro, on a une entrée, lorsque DDR est à 1, on a une sortie. Maintenant, dans le cas d'une entrée, si PORT est à zéro, c'est une entrée normale, à haute impédance, mais si PORT prend la valeur 1, alors un pull-up est rajouté. Dans le cas de l'utilisation d'une broche comment une sortie, eh bien, tout naturellement, la valeur du PORT va se transmettre sur la sortie, un 1 donnera une sortie à 1. Ces deux registres sont bel et bien des registres, qui mémorisent les valeurs ; on peut les écrire, depuis un programme, on peut également les lire, pour contrôler la valeur. Pour ce qui est de PIN A, on ne peut que lire, et lorsqu'on lit, les valeurs sur PA0, PA1 etc. jusqu'à PA7, viennent se placer dans PIN A. Sur les MSP430, les ports s'appellent P1, P2 etc. Je prendrai l'exemple avec P1. Les broches de P1 s'appellent P1.0, P1.1 etc. jusqu'à P1.7. Quatre registres sont utilisés pour piloter chaque port. Le registre P1DIR, c'est le registre de direction, il est tout à fait équivalent au, DDR, des AVR. Le registre, P1OUT, c'est le registre de sortie. Il est équivalent au PORT A des AVR. P1IN a également la même fonctionnalité que PIN A des AVR, il donne l'état de chaque broche. Par contre, il y a un registre supplémentaire, qui s'appelle P1REN, comme Resister Enable, enclenchement d'une résistance de tirage. Voilà les fonctions possibles des broches, en fonction de ces entrées, lorsque DIR est à 1, on a une sortie, qui peut prendre la valeur zéro, ou la valeur 1 ; lorsque DIR est à zéro, on a tous les cas possibles des entrées, et c'est Resister Enable qui détermine si on a une entrée normale à haute impédance, lorsque c'est un zéro, ou si l'on a une résistance de tirage, lorsque REN est à 1. Et alors le tirage peut être vers le haut, ou vers le bas, selon la valeur de registre P1OUT. À noter que cette table est incomplète, que les autres combinaisons ne doivent, en principe, pas être utilisées. Donc, pratiquement, pour lire et écrire sur un port, il faut initialiser le registre de direction, ici, on aura une sortie sur le bit zéro et sur le bit 6, des entrées sur les autres bits, on pourra éventuellement enclencher les résistances de tirage, et ensuite on pourra, en permanence, lire, dans une variable ce qu'il y a sur les broches, que ce soit d'ailleurs utilisé en entrée ou en sortie, on On peut toujours lire la valeur, mais c'est généralement lorsque c'est une entrée qui nous intéresse. Pour une écriture, eh bien on prend une valeur, une valeur de 8 bits qu'on va placer dans P1OUT. On a compris que les broches des microcontrôleurs sont regroupées par ports. Mais alors comment les utiliser individuellement, un bit à la fois? Eh bien nous allons utiliser les opérations logiques du langage C. Nous avons à disposition le ET logique, le OU logique et l'inversion logique. Le OU logique est représenté par la barre verticale, ce symbole & correspond au ET logique et le tilde ici correspond à l'inversion logique. Regardons comment un bit peut être mis à 1 à l'intérieur d'un port. Il suffit d'exécuter cette instruction. Comment est-ce que cela fonctionne? Au départ, nous avons des valeurs que nous ne connaissons pas à l'intérieur de P1OUT. Nous souhaitons qu'après l'opération se trouve la valeur logique 1. Eh bien en réalisant le OU logique entre cette opérande et cette opérande, on obtient bien ici un 1 et ici une conservation de chaque valeur. Il est également possible de mettre plusieurs bits à 1 en une seule instruction. Ici le bit 6 et le bit 1 sont mis à 1 par l'opération logique OU. C'est similaire pour la mise à 0. C'est la fonction logique ET qui sera utilisée, mais cette fois avec un 0 lorsqu'on veut faire passer le 0 et un 1 lorsqu'on veut maintenir l'ancienne valeur. C'est lié aux propriétés de l'algèbre de Boole. Et de nouveau, c'est possible d'agir sur plusieurs bits à la fois. À noter que ce type d'écriture est assez peu lisible. Cherchons une meilleure solution pour écrire ces opérations. Les opérations setbit et clearbit s'utilisent généralement avec des sorties, mais il ne faut pas aussi oublier les entrées. Nous devons tester un bit. La situation se présente de la manière suivante : on a 8 bits. Le bit qui nous intéresse peut être à 0 ou à 1. Comment faire pour cacher les autres bits? Eh bien on va utiliser l'opération logique ET que nous voyons ici. Ces valeurs-là vont disparaître grâce au ET logique. Cette valeur va être conservée grâce à la présence du 1, tout comme celle-ci va être conservée. Le résultat final sera une valeur complètement nulle dans le cas du 0, une valeur non nulle dans le cas du 1 ; et ça correspond parfaitement à ce qu'on veut en C puisqu'une valeur nulle est considérée comme une condition fausse alors qu'une valeur non nulle est considérée comme une valeur vraie. Donc par exemple, nous pourrons utiliser dans un if : if P1IN & cette valeur, et nous testons le bit en question. Pour mettre à 1 le bit 6, on peut écrire l'instruction de cette manière-là . Aux décimales, c'est particulièrement peu lisible. Pour ceux qui connaissent bien l'hexadécimal, c'est un peu plus lisible avec cette notation, 0x signifiant hexadécimal. Certains compilateurs permettent d'écrire la valeur en binaire, mais attention, c'est pas toujours le cas. Mais il y a une notation beaucoup plus intéressante qui consiste à utiliser l'opérateur de décalage. Ici on prend la valeur 1 qui se trouve donc normalement ici et on la décale de 6 pour la mettre à cette place. Et le gros avantage c'est que cette notation fait apparaître le chiffre 6 qui est le rond du bit concerné. À noter que ces quatre instructions sont compilées exactement de la même manière par le compilateur. Cette valeur-là étant une constante, elle est évidemment calculée par le compilateur et non pas calculée au moment de l'exécution par le microcontrôleur. On peut même d'ailleurs ajouter que les compilateurs modernes réalisent que ces instructions sont en fait la mise à 1 d'un bit dans un champ de bit et elles utilisent les instructions assembleurs spécifiques qui existent sur tous les processeurs modernes. Pour la mise à 0, on va utiliser la même notation qu'ici, mais en utilisant l'opérateur d'inversion. Et c'est ainsi qu'on va pouvoir se souvenir que pour faire un bit set, on fait le OU égal ; lorsqu'on veut un bit clear, on utilise ET égal tilde. Je profite de l'occasion pour parler du dernier opérateur disponible en C qui est le OU exclusif sur un champ de bits. On pourra par exemple l'utiliser pour inverser la valeur binaire dans un registre P1OUT ^= (1<<6). Pour rendre plus lisibles nos programmes, nous utiliserons volontiers le dièse define du C. Il s'agit donc d'un ordre de remplacement qui est donné au préprocesseur, qui s'exécute avant la compilation elle-même. De cette manière, lorsqu'on écrira dans un programme ClockSet, qui montre que j'ai l'intention de passer le signal d'horloge Clock à la valeur 1, cette expression remplacera le ClockSet. Idem pour le ClockClear, ici un clear bit. On pourra par exemple aussi l'utiliser pour gérer une Led. Allumer, éteindre ou changer l'état d'une Led avec un set bit, un clear bit et un toggle bit. Nous avons vu le rôle exact des broches d'entrée sortie et comment elles sont regroupées en ports à l'intérieur des microcontrôleurs. Nous avons vu les registres qui permettent de les manipuler sur un AVR ou sur un MSP430. Nous avons vu les opérations logiques qu'il est possible d'utiliser. Nous pourrons donc maintenant utiliser au mieux nos ports d'entrée sortie pour nos enseignes et afficheurs à Led.