在AVR编程中,通过将a左1
移到合适的位位置来始终设置寄存器位-并用相同的补码清除它们。
例如:对于一个ATtiny85,我可以这样设置PORTB,b 4:
PORTB |= (1<<PB4);
或像这样清除它:
PORTB &= ~(1<<PB4);
我的问题是:为什么要这样做?最简单的代码最终是一团乱码。为什么将位定义为位位置而不是掩码。
例如,ATtiny85的IO标头包括以下内容:
#define PORTB _SFR_IO8(0x18)
#define PB5 5
#define PB4 4
#define PB3 3
#define PB2 2
#define PB1 1
#define PB0 0
对我来说,将这些位定义为掩码(这样)会更加合乎逻辑:
#define PORTB _SFR_IO8(0x18)
#define PB5 0x20
#define PB4 0x10
#define PB3 0x08
#define PB2 0x04
#define PB1 0x02
#define PB0 0x01
所以我们可以做这样的事情:
// as bitmasks
PORTB |= PB5 | PB3 | PB0;
PORTB &= ~PB5 & ~PB3 & ~PB0;
分别打开和关闭位b 5,b 3和b 0。相对于:
// as bit-fields
PORTB |= (1<<PB5) | (1<<PB3) | (1<<PB0);
PORTB &= ~(1<<PB5) & ~(1<<PB3) & ~(1<<PB0);
该位掩码代码读取更清晰:设置位PB5
,PB3
和PB0
。此外,由于不再需要移位位,因此似乎可以节省操作。
我认为可能是为了保留通用性而这样做的,以便允许将代码从n位AVR 移植到m位(例如8位到32位)。但这不是事实,因为#include <avr/io.h>
解析为特定于目标微控制器的定义文件。即使改变从8位ATtiny目标,以一个8位的Atmega(其中位定义语法从改变PBx
到PORTBx
,例如),需要更改代码。
_BV(b)
而不是(1<<b)
使事情变得混乱。我通常定义与位助记符_BV()
,如#define ACK _BV(1)
。