En la programación de AVR, los bits de registro se establecen invariablemente desplazando a la izquierda a 1
a la posición apropiada del bit, y se borran con el complemento de uno de los mismos.
Ejemplo: para un ATtiny85, podría establecer PORTB, b 4 de esta manera:
PORTB |= (1<<PB4);
o bórralo así:
PORTB &= ~(1<<PB4);
Mi pregunta es: ¿Por qué se hace de esta manera? El código más simple termina siendo un caos de cambios de bits. ¿Por qué los bits se definen como posiciones de bits en lugar de máscaras?
Por ejemplo, el encabezado IO para el ATtiny85 incluye esto:
#define PORTB _SFR_IO8(0x18)
#define PB5 5
#define PB4 4
#define PB3 3
#define PB2 2
#define PB1 1
#define PB0 0
Para mí, sería mucho más lógico definir los bits como máscaras (como esto):
#define PORTB _SFR_IO8(0x18)
#define PB5 0x20
#define PB4 0x10
#define PB3 0x08
#define PB2 0x04
#define PB1 0x02
#define PB0 0x01
Entonces podríamos hacer algo como esto:
// as bitmasks
PORTB |= PB5 | PB3 | PB0;
PORTB &= ~PB5 & ~PB3 & ~PB0;
para activar y desactivar los bits b 5 , b 3 y b 0 , respectivamente. A diferencia de:
// as bit-fields
PORTB |= (1<<PB5) | (1<<PB3) | (1<<PB0);
PORTB &= ~(1<<PB5) & ~(1<<PB3) & ~(1<<PB0);
El código de máscara de bits se lee mucho más claramente: establece los bits PB5
, PB3
y PB0
. Además, parece que guarda operaciones ya que los bits ya no necesitan ser desplazados.
Pensé que tal vez se hizo de esta manera para preservar la generalidad a fin de permitir el código de portabilidad de un n -bit AVR a un m -bit (ejemplo de 8 bits a 32 bits). Pero este no parece ser el caso, ya que #include <avr/io.h>
se resuelve en archivos de definición específicos para el microcontrolador de destino. Incluso el cambio de objetivos de un ATtiny de 8 bits a un Atmega de 8 bits (donde las definiciones de bits cambian sintácticamente de PBx
a PORTBx
, por ejemplo), requiere cambios de código.