[TUTORIEL] Les opérations bit à bit

[TUTORIEL] Les opérations bit à bit

Message non lude Laetitia » Mar 11 Aoû 2015 18:30

Bonjour,

Aujourd'hui nous allons nous intéresser aux opérations bit à bit !
Pas de blagues graveleuses en vue (ne faites pas les innocents :roll:), on va parler ici de logique et de programmation.

À quoi ça sert ?

Pourquoi chercher à manipuler les bits séparément les uns des autres alors que l'on crée des variables pour les gérer sans se prendre la tête ?

  • C'est un moyen rapide de changer un paramètre sans passer par les fonctions d'une librairie.
  • Manipuler les données au niveau le plus bas possible équivaut à limiter le nombre d'instructions qui vont être effectuées, et donc à réduire leur temps d'exécution.
  • Ou, tout simplement, vous trouvez plus intéressant de comprendre ce qui se passe au cœur de votre microcontrôleur ;)
Pré-requis : Algèbre de Boole

Le calcul binaire se base sur l'algèbre de Boole. Elle traite des données qui ne peuvent avoir que deux valeurs : 0 ou 1 (FAUX/VRAI, LOW ou HIGH : on peut utiliser des variables de type boolean pour fixer la valeur d'une sortie numérique).
Je vous invite à aller (re)lire le tutoriel d'OpenClassrooms si vous avez envie d'approfondir un peu, je me concentrerai ici sur les applications dans la programmation de micro-contrôleurs...

La théorie

Nous avons à notre disposition six opérateurs binaires. Quatre d'entre eux sont directement issus de l'algèbre booléenne : NOT ~, AND &, OR |, XOR ^ ; les deux autres sont les opérateurs de décalage à gauche << et à droite >> (en anglais bitshift).
Note : le décalage à droite ou à gauche permet respectivement de diviser ou multiplier par 2.

Nous allons ici "utiliser des masques" pour agir sur la donnée initiale : cela se fait en trois temps. D'abord il nous faut choisir l'opérateur adéquat, en fonction de son action sur les bits. Ensuite construire le masque, de même taille que la donnée à manipuler (par exemple 8 bits s'il s'agit d'un byte), avec des 0 et des 1 pour chaque bit respectif, en fonction de l'opération affectée. Enfin, on pose l'équation mathématique permettant d'appliquer le masque sur la donnée.

Puisqu'un exemple vaut mieux qu'un long discours, prenons une simple opération : 0101 & 0011 = 0001
Si l'on considère que la première opérande 0101 est notre variable, la seconde 0011 le masque, notre opérateur AND sert à mettre à 0 les bits masqués par un 0 et à ne pas toucher ceux qui sont masqués par un 1... pas mal, non ?

Petit récapitulatif de l'effet des opérateurs booléens sur un bit quelconque X :

  • AND
    X & 0 = 0
    X & 1 = X
  • OR
    X | 0 = X
    X | 1 = 1
  • XOR
    X ^ 0 = X
    X ^ 1 = ~X
Il ne reste plus qu'à déterminer les masques et à les appliquer ! On peut en déduire des opérations bien utiles, voyons les plus courantes...

Application

    Fabriquer un masque - Astuce
Comme vu précédemment, le masque doit faire la même taille que la donnée à manipuler, et sa valeur dépendra du but de l'opération. Vous pouvez le faire "à la main" en écrivant les bits individuellement en fonction du résultat attendu, ou utiliser un des opérateurs vus plus tôt pour le construire plus rapidement :

Code: Tout sélectionner
byte A = 0b00010000;
byte B = 1 << 4;

Ici les masques A et B sont identiques. En effet, en décalant 4 fois 1 (= 0b00000001) vers la gauche, c'est-à-dire en le multipliant par 2 quatre fois, on obtient bien 16 (= 0b00010000).

Passons maintenant à quelques opérations bit à bit courantes.

    Lire la valeur d'un bit
Pour lire la valeur d'un bit particulier, il faut appliquer un masque qui mette à 0 tous ceux qui ne nous intéressent pas :

Code: Tout sélectionner
byte A = 0b00010001;
byte S = A & 0b00010000;
// S = 0b00010000

Si l'on veut aller plus vite dans la rédaction du masque, on peut aussi écrire :

Code: Tout sélectionner
byte A = 0b00010001;
byte S = A & (1 << 4);
// S = 0b00010000

Avec cette méthode, S est nul, donc a pour valeur logique FAUX, lorsque le bit lu est à 0, et a pour valeur logique VRAI lorsque le bit est à 1. Si l'on cherche à extraire la valeur du bit pour traitement ultérieur, il nous faut nous débarrasser des 0 inutiles :

Code: Tout sélectionner
byte A = 0b00010001;
byte S = (A & (1 << 4)) >> 4 // même méthode mais on redécale pour ne garder que le bit lu
// S = 1

    Modifier l'état d'un bit sans toucher aux autres
En regardant le récapitulatif ci-dessus, vous vous apercevrez que l'on peut forcer l'état d'un bit à 0 avec l'opérateur AND, ou à 1 avec l'opérateur OR. Il ne reste plus qu'à construire le masque approprié !

Code: Tout sélectionner
// Mettre un bit à 1
byte A = 0b00000001;
byte S = A | (1 << 4);
// S = 0b00010001

// Mettre un bit à 0
byte A = 0b00010001;
byte S = A & ~(1 << 4);
// S = 0b00000001

Note : il existe des opérateurs composés permettant d'écrire différemment ces opérations :

Code: Tout sélectionner
// Opérateur composé OR
byte A = 0b00000001;
A |= 1 << 4;
// A = 0b00010001

// Opérateur composé AND
byte A = 0b00010001;
A &= ~(1 << 4);
// A = 0b00000001

    Modifier l'état de plusieurs bits sans toucher aux autres
Opération un peu plus délicate ici, nous avons besoin de deux masques successifs. D'abord un masque AND pour mettre à 0 les bits que nous avons besoin de modifier, puis un masque OR pour fixer la nouvelle valeur des bits.

Code: Tout sélectionner
byte A = 0b01010101;
byte S = (A & 0b11111000) | 0b00000010;
// S = 0b01010010

C'est tout pour cette fois ! J'espère que ce tutoriel vous aura plu, et bonne bidouille en attendant le prochain !
"If it's itchy, scratch it !" - "DIY or die"

RTFM (À lire avant de poster) - ANDb (Arduino Noob Database)
Avatar de l’utilisateur
Laetitia
 
Messages: 296
Inscription: Mar 7 Aoû 2012 15:07
Localisation: Toulouse

Retourner vers Logiciel Arduino

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité