This is an old revision of the document!


Registres

Une des choses les moins évidentes à comprendre dans le fonctionnement d'un microcontrôleur est typiquement un registre. Il est impossible d'utiliser les micro-contrôleurs sans savoir ce qu'ils sont. Ce livre n'est nullement différent, on cherche alors à ce que le lecteur familiarise lui/elle même avec le concept du registre et donc le texte suivant essayera de l'expliquer en termes assez simples, pour que même un débutant puisse saisir l'idée d'un registre.

Essentiel

Les boutons d'un lecteur de cassettes

Un registre ressemble à un panneau de boutons de n'importe quel appareil domestique. On trouve des interrupteurs, qui peuvent être allumés ou éteints. Le meilleur exemple est un lecteur de cassette simple. Pour ceux qui ne se souviennent pas, le lecteur de cassette a 6 boutons, de gauche à droite :

  • Enregistrement
  • Rembobinage
  • Play
  • Avance rapide
  • Arrêt
  • Pause

Chaque bouton à une fonction, mais seulement quand il est utilisé correctement. Par exemple, le bouton d'arrêt n'a pas de fonction à moins que la cassette fonctionne - only then will it do something apparent et arrête la lecture. Les boutons avance rapide et rembobinage, d'autre part, peuvent être utilisés à tout moment, parce que la bande peut être orientée dans les deux directions, peu importe si elle fonctionne ou s'est arrêtée. L'enregistrement commence seulement quand les boutons play et enregistrement sont appuyés simultanément. Certains peuvent avoir essayé d'appuyer sur plusieurs ou tous les boutons à la fois - dans ce cas, le lecteur de cassette pourrait faire quelque chose d'inattendu ou mettre tout en pause.

Les registres du micro-contrôleur se comportent comme des boutons d'un lecteur de cassette - chaque bouton à une fonction, lorsqu'il est utilisé correctement. En appuyant les mauvais boutons, un micro-contrôleur ne se détériorera pas, mais il ne fonctionnera pas non plus. En réalité, il n'y a aucun bouton dans les registres, au lieu de cela il y a une série de transistors, qui s'allument et s'éteignent. Des micro-contrôleurs plus simples ont 8 interrupteurs basés sur des transistors dans un registre simple. Un registre peut être imaginé comme un nombre de 8 bits, où chaque bit marque l'état d'un de ces interrupteur. Par exemple, la valeur 1 signifie que l'interrupteur est branché et 0 que l'interrupteur est débranché.

Les “boutons” du registre et la valeur des bits

Puisque l'état des interrupteurs du registre peut facilement être traité comme un nombre et vice versa, un registre peut être comparé à une mémoire, qui peut contenir des données de la taille d'un nombre. Par cette comparaison, nous voyons que les registres sont en réalité des créneaux de mémoire. La différence entre un registre et un créneau de mémoire est qu'une créneau de mémoire stocke seulement les informations, alors que dans un registre ces informations contrôlent en réalité quelque chose. Par exemple, si une valeur binaire de 01100001 est écrite à un registre, cela signifie que trois boutons imaginaires sont appuyés et quelque chose arrive.

Avec un lecteur de cassette il est possible d'appuyer sur chaque bouton séparément, mais dans un registre il est plus difficile de changer la valeur d'un “interrupteur” ou le bit. Concrètement il est nécessaire de changer le contenu entier du registre. Avant le changement de la valeur d'un bit, il faut savoir qu'il y a beaucoup de registres dans un micro-contrôleur. Certaines parties du micro-contrôleur utilisent des dizaines de registres pour les contrôler. La variété des registres signifie qu'il y doit avoir une façon de distinguer les différents des registres ce que l'on réalise en les nommant. Un registre, par exemple, est appelé PORTB. En réalité, ces noms doivent juste rendre les choses plus faciles pour le développeur et chaque nom correspond à une adresse numérique.

Usage

Pour écrire sur un registre ou en lire une valeur, il doit être adressé comme une variable dans C. L'exemple suivant montre l'écriture d'une valeur binaire sur un registre imaginaire REG et ensuite sa lecture dans la variable Reg . Des valeurs binaires sont distinguées par 0b (zéro), pour que le compilateur comprenne le système numérique.

  REG = 0b01100001;
  unsigned char reg = REG;

Il n'y a rien de difficile à écrire et lire les valeurs d'un registre, mais il devient un peu délicat si on doit modifier seulement un bit. Pour modifier des bits, on a besoin d'avoir des connaissances en mathématiques binaires et utiliser des systèmes numériques différents. Il ne serait pas impossible de ne traiter que des nombres binaires, mais ils peuvent être un peu ennuyeux, parce que des nombres binaires sont assez long et c'est pourquoi la plupart des personnes utilisent des nombres hexadécimaux plus courts.

Nombres hexadécimaux

En hexadécimal, les nombres ne sont pas seulement des 0 et des 1 comme dans le fichier binaire ou de 0 à 9 en décimale, mais au lieu de cela de 0 à F. Un nombre hexadécimal est composé de quatre bits. La table à droite montre les nombres binaires et leurs équivalents hexadécimaux. Des nombres binaires sont convertis en hexadécimal en lisant des bits quatre à la fois, en commençant par le rang le plus bas. Les rangs sont lus de droite à gauche en commençant par 0. Par exemple, le bit le plus bas classé (au rang 0) est 0 et le plus haut (au rang 3) est 1. Dans l'exemple précédent, la valeur binaire du registre est 01100001, qui correspond au 61 en hexadécimal et est écrit 0x61 (zéro) en langage C.

Pour changer un bit seul dans un nombre (le registre, la variable ou n'importe où autrement à cet égard) il est nécessaire d'utiliser des opérations binaires. L'opération binaire est une opération entre deux nombres binaires, où chaque bit des nombres sont soumis à leur propre opération logique. Typiquement un micro-contrôleur supporte quatre opérations binaires, chacune ayant plusieurs noms. La section suivante décrit l'opération logique derrière chacune de ces quatre opérations binaires avec un bit seul ou des bits multiples.

Négation, multiplication logique, addition logique et séparation exclusive

 

  • Négation / Inversion
    Le négation inverse la valeur du bit, un 0 devient 1 et vice et versa. En C, la négation correspond au symbole “~”.
  • Multiplication logique/ Conjonction
    Lorsqu'on multiplie deux bits, le résultat est 1 lorsque les deux valeurs sont à 1. En C, la multiplication logique correspond au symbole “&”.
  • Addition logique / Disjonction
    Lorsqu'on additionne deux bits, le résultat est 1 lorsqu'au moins une des deux valeurs est à 1, quelle que soit la valeur de l'autre. La valeur est 0 quand les deux bits sont à 0. En C, l'addition logique correspond au symbole “|”.
  • Disjonction exclusive / OU Exclusif / XOR
    L'opération du OU Exclusif renvoi 1 lorsque les deux bits on des valeurs différentes (le premier est à 1, le second à 0), sinon l'opération renvoi 0. En C, le OU Exclusif correspond au symbole “^”.

C'est tout ce qu'il y a à savoir pour modifier les bits seuls. La théorie seule n'est probablement pas suffisante, c'est pourquoi il y a quelques exemples typiques avec des registres dans les paragraphes suivants.

Mettre un simple bit en valeur haute

Mettre un bit en haut

Pour mettre un ou plusieurs bits dans un registre en valeur haute (1) une opération d'addition logique est nécessaire. Un des opérandes de l'opération doit être le registre et l'autre un nombre binaire, où seul le bit haut est celui qui doit être mis haut dans le registre. Ce nombre binaire est appelé un bitmask. Ci-dessous le code de C correspondant à l'opération montrée à droite :

  // Let's suppose REG = 0x0F
  REG = REG | 0x11; // First method
  REG |= 0x11;      // Second method
  // Now REG = 0x1F

Mettre un simple bit en valeur basse

Mettre un bit en bas

Pour mettre un ou plusieurs bits dans un registre en valeur basse (0) une opération de multiplication logique est nécessaire. Un des opérandes de l'opération doit être le registre et l'autre un bitmask, où seul le bit bas est celui qui doit être mis bas dans le registre. Ci-dessous le code de C correspondant à l'opération montrée à droite :

  // Let's suppose REG = 0x0F
  REG = REG & 0xFE; // First method
  REG &= 0xFE;      // Second method
  // Now REG = 0x0E

 

Inverser la valeur d'un bit

Inverser la valeur d'un bit

Pour inverser un ou plusieurs bits dans un registre une opération de disjonction exclusive est nécessaire. Un des opérandes de l'opération doit être le registre et l'autre un bitmask, où seul le bit bas est celui qui doit être inversé dans le registre. Ci-dessous le code de C correspondant à l'opération montrée à droite :

  // Let's suppose REG = 0x0F
  REG = REG ^ 0x11; // First method
  REG ^= 0x11;      // Second method (use only one per inversion)
  // Now REG = 0x1E

Inverser tout le registre

Inverser tous les bits

Pour inverser tous les bits d'un registre on utilise l'opération de négation. Cette opération est unaire, ce qui signifie qu'elle ne nécessite qu'un seul opérande. Ci-dessous le code de C correspondant à l'opération montrée à droite :

  // Let's suppose REG = 0x0F
  REG = ~REG;
  // Now REG = 0xF0

Reading the value of a single bit

Reading the value of a bit

To read one or more bits from a register the same operation is required as was used for setting a bit low - logical multiplication. One of the operands of the operation must be the register and the other a bitmask, where the only high bit is the one that needs to be read from the register. Below is the C code for the operation shown on the right:

  // Let's suppose REG = 0x0F
  unsigned char x = REG & 0x01;
  // Now x = 0x01

 

Shifting a bit

Many programming languages actually have a few additional bitwise operations, which make it easier for the programmers. These are bit shifting operations that shift bits left or right in a binary number. The main value of shift operations in dealing with registers is their ability to convert bit ranks to bitmasks and vice versa.

Shift left

The image on the right shows a shift left operation. Although bit shifting is not a logical operation and has no corresponding symbol, in C it is marked as “«”. Shift left is used to transform a bit rank to a bitmask. For example, to get the mask for the 6th bit (NB! rank 5), number 1 has to be shifted left 5 times. The example operation looks like this in C:

REG = 0x01 << 5;
// Now REG = 0x20
Shift right

Shift right operation works similarly to shift left operation. It is marked as “»” in C. Right shift is used to get the logical value of a bit from a bitmask. A leading example showed how to read the value of a single bit. Let's suppose the bit to read is not of the lowest rank, but for example of rank 5. In this case, the result would be either 0x20 or 0x00, but sometimes a result of 1 or 0 is needed and that is when the right shift comes to the rescue. The example operation on the right looks like this in C:

// Let's suppose REG = 0x20
unsigned char x = REG >> 5;
// Now x = 0x01 (or simply 1)

If a bit is shifted right from the lowest rank or left from the highest rank by the bit shifting operation, it disappears. Some programming languages also have rotating bit shift operations, where the bit doesn't disappear, but moves from the lowest rank to the highest or vice versa. C doesn't have that kind of bit shift operations, but they can be written by the programmer if needed.

All bit operations work with not only registers, but with variables and constants as well. The latter can of course only be used as operands and not the result.

AVR registers

To do anything actual with the microcontroller's registers, one needs to know how to use that particular microcontroller. Each microcontroller comes with one or several datasheets, which describe the whole structure and functionality or the microcontroller. The datasheet also describes the registers. The following will help understand the register descriptions in AVR datasheets.

One of AVRs registers from its datasheet

The image shows ATmega128 microcontroller's UCSRnA register, which stands for “USART Control and Status Register A”. This register is used to configure AVR's USART module and read its states. All AVR register names are written in capital letters, but as the reader might notice, the register name contains also a lower case n. A lower n is used to mark some module's index. Since ATmega128 has 2 almost identical USART modules, they are not described twice, but only once and the n must be read as 0 or 1 by the user. Therefore ATmega128 has registers UCSR0A and UCSR1A.

The content of the register is marked by an 8-slot box with a bold line around it. Each slot marks one bit. Bit ranks are marked above the box - increasing from right to left. Since AVR is an 8-bit microcontroller, most of the registers are 8-bit as well. There are some exceptions, a few registers are 16-bit, but they actually consist of two 8-bit registers. Like each register has a name, each bit in the register has also a name - just like the buttons on a tape player. Each bit is described in the datasheet. Bit names are abbreviations as well and the lower n must be substituted with the module's index, just like with register names. Some registers don't use all 8 bits, in this case the bit's slot is marked with a hyphen.

Below the register's bits are two lines, which state whether the bit is readable (R), writable (W) or both (R/W). For example, the status bits can't be overwritten and even if it's attempted in the program, the bit will remain unchanged. If the bit is marked as writable, reading it will always result in one specific value stated in the datasheet. The second line specifies the default value of the bit, which it has after the reset of the microcontroller.

While AVR register names point to an actual memory slot address, the bit names hold the rank number of the corresponding bit. Therefore it is necessary to transform the names to bitmasks using a shift operation, in order to manipulate with bits in a register. The following code contains a few example lines for using the USART 0 module's register.

  // Set TXC0 bit high
  UCSR0A |= (1 << TXC0);
 
  // Set U2X0 bit low
  UCSR0A &= ~(1 << U2X0);
 
  // Read the value of UDRE0 bit(mask)
  unsigned char u = (UCSR0A & (1 << UDRE0));
 
  // At this point u value is either 0 or 32,
  // which enables using it in a logical operation
  if (u)
  {
     // Invert MPCM0 bit
     UCSR0A ^= (1 << MPCM0);
  }
 
  // Sometimes it is necessary to acquire a specific 0 or 1 value,
  // so the read bit needs to be shifted right
  u >>= UDRE0;
 
  // Now the value of u is either 0 or 1
fr/avr/registers.1268908040.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0