Atmega328 registers
Introduction
Lorsque l'on commence à écrire des programmes qui sortent de l'ordinaire ou que l'on veut pousser un microcontrôleur à la limite de ces capacité, il est obligatoire de descendre au niveau des registres. Seulement voila, la manipulation de registre ne s'improvise pas, nécessite de connaître le hardware que l'on utilise et, de par sa nature, est spécifique à un type de microcontrôleur !
Manipuler les registre implique donc de sacrifier la portabilité du code, offerte par l'utilisation des fonctions haut niveau comme digitalWrite(), au profit de la vitesse d'exécution et de la compacité du code.
Les fonctions comme digitalWrite(), digitalRead(), pinMode() permettent au développeur d'accomplir une action sans avoir à se soucier du type de microcontrôleur utilisé mais, in finé, elle vont elle même manipuler les registres pour accomplir ces tâches !
Le cas de l'ATmega328
Comment manipuler un registre ?
Maintenant que l'on à identifié le groupe et la position du bit des broches dans les registres, nous pouvons passer à la manipulation !
Reprenons l'exemple de la broche D13. Pour modifier sont état, il suffit de modifier la valeur de PORTB:
PORTB = B00100000; // pour mettre D13 à HIGH
PORTB = B00000000; // pour mettre D13 à LOW
Seulement voila, on sait que sa position dans les registres correspond au bit numéro 6 mais on a absolument aucune idée de la valeur de PORTB au moment de la modification ! La manipulation précédente va certainement modifier l'état de D13 mais va aussi modifier l'état des autre broches du groupe B. On ne peut donc pas agir de la sorte, il faut utiliser un opérateur logique pour modifier les registres et on va distinguer deux cas de figures: le passage à 1 et celui à 0.
Passage à 1
Pour modifier l'état d'un registre à 1 sans modifier l'état des autres registres nous allons utiliser l'opérateur OU. Si on reprend l'exemple précédent, nous allons plutôt faire cela: PORTB |= B00100000; // pour mettre seulement D13 à HIGH
Imaginons que PORTB est la valeur suivante B00010101, PORTB |= B00100000 revient à faire:
On a donc réussi à modifier la valeur de D13 sans modifier l'état des autres broches ! |
Table de vérité de OU
|
On peut également effectuer cette manipulation par décalage de bit. Dans l'exemple précédent nous avons utilisé B00100000 pour faire le OU mais on aurait pu utiliser l'écriture (1<<5) ou même la constante prévue à cet effet (1<<PB5). Le chiffre 1 est un entier qui s'écrit en binaire comme cela:
Il nous suffit donc de le décaler de 5 position vers la gauche pour obtenir B00100000:
Les trois écritures suivantes sont donc équivalentes: PORTB |= B00100000;
PORTB |= (1<<5);
PORTB |= (1<<PB5);
|
Passage à 0
Pour modifier l'état d'un registre à 1 sans modifier l'état des autres registres nous allons utiliser l'opérateur ET. Si on reprend l'exemple précédent, nous allons plutôt faire cela: PORTB &= ~B00100000; // pour mettre seulement D13 à LOW
L'opérateur ~ permet d'obtenir le complément A1 d'un nombre binaire: B00100000 devient alors B11011111. Imaginons que PORTB est la valeur suivante B00010101, PORTB &= ~B00100000 revient à faire:
On a donc réussi à modifier la valeur de D13 sans modifier l'état des autres broches ! |
Table de vérité de ET
|
On peut également effectuer cette manipulation par décalage de bit. Dans l'exemple précédent nous avons utilisé ~B00100000 pour faire le OU mais on aurait pu utiliser l'écriture ~(1<<5) ou même la constante prévue à cet effet ~(1<<PB5).. Les trois écritures suivantes sont donc équivalentes: PORTB &= ~B00100000;
PORTB &= ~(1<<5);
PORTB &= ~(1<<PB5);
|
Cas concret
Dans l'exemple suivant nous allons modifier l'état de la broche D13 pour la faire clignoter.
Modification de sens
Dans un premier temps il faut la placer en sortie et pour cela nous allons manipuler le registre DDRB:
- la valeur 1 positionne la broche en sortie (OUTPUT);
- la valeur 0 positionne la broche en entrée (INPUT), si la l'état est positionné à 1 cela active la résistance de pullup (INPUT_PULLUP).
Nous allons donc modifier le registre DDRB comme suit, les trois notations sont équivalentes:
DDRB |= B00100000; // Positionnement de D13 en OUTPUT
DDRB |= (1<<5);
DDRB |= (1<<PB5);
Modification d'état
On peut maintenant modifier son état grâce au registre PORTB:
PORTB |= B00100000; // Positionnement de D13 à HIGH
PORTB |= (1<<5);
PORTB |= (1<<PB5);
Lecture d'état
Il est possible de lire l'état de la broche D13 grâce au registre PINB.