AVRプログラミングでは、レジスタビットは、a 1
を適切なビット位置に左シフトすることによって常に設定され、それらの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)
。