Dans la programmation AVR, les bits de registre sont invariablement définis en déplaçant a 1
vers la gauche à la position de bit appropriée - et ils sont effacés par un complément à un du même.
Exemple: pour un ATtiny85, je pourrais définir PORTB, b 4 comme ceci:
PORTB |= (1<<PB4);
ou effacez-le comme ceci:
PORTB &= ~(1<<PB4);
Ma question est: pourquoi est-ce fait de cette façon? Le code le plus simple finit par être un gâchis de décalages de bits. Pourquoi les bits sont-ils définis comme des positions de bits au lieu de masques.
Par exemple, l'en-tête IO pour l'ATtiny85 inclut ceci:
#define PORTB _SFR_IO8(0x18)
#define PB5 5
#define PB4 4
#define PB3 3
#define PB2 2
#define PB1 1
#define PB0 0
Pour moi, il serait beaucoup plus logique de définir les bits comme masques à la place (comme ceci):
#define PORTB _SFR_IO8(0x18)
#define PB5 0x20
#define PB4 0x10
#define PB3 0x08
#define PB2 0x04
#define PB1 0x02
#define PB0 0x01
Nous pourrions donc faire quelque chose comme ceci:
// as bitmasks
PORTB |= PB5 | PB3 | PB0;
PORTB &= ~PB5 & ~PB3 & ~PB0;
pour activer et désactiver les bits b 5 , b 3 et b 0 , respectivement. Par opposition à:
// as bit-fields
PORTB |= (1<<PB5) | (1<<PB3) | (1<<PB0);
PORTB &= ~(1<<PB5) & ~(1<<PB3) & ~(1<<PB0);
Le code bitmask lit beaucoup plus clairement: les bits set PB5
, PB3
et PB0
. De plus, il semblerait que les opérations soient sauvegardées car les bits n'ont plus besoin d'être décalés.
J'ai pensé que cela avait peut-être été fait de cette façon pour préserver la généralité afin de permettre le portage du code d'un AVR à n bits vers un m bits (par exemple 8 bits à 32 bits). Mais cela ne semble pas être le cas, car se #include <avr/io.h>
résout en fichiers de définition spécifiques au microcontrôleur cible. Même le changement de cibles d'un ATtiny 8 bits en un Atmega 8 bits (où les définitions de bits changent syntaxiquement de PBx
à PORTBx
, par exemple), nécessite des changements de code.
_BV(b)
au lieu de(1<<b)
rend les choses inutilement désordonnées. Je définis généralement les mnémoniques de bits avec_BV()
, par exemple#define ACK _BV(1)
.