最近出たこの本、すごくいい。
マイコンもATmega168で最新だし、gccでのコードが載っているのでよくわかる。
電波新聞社 (1982/01)
売り上げランキング: 23347
でもIOの操作で16進数とか使うのがあんまり好きじゃない。別にどう書いても動けばいいんだけど…
PORTB = 0x21;
とか。0x21、つまり10進数の33を代入しているので、PB5とPB0のピンを出力に設定しているという事だ。
でもこう書いたほうが好きだな。
PORTB = _BV(PB5)|_BV(PB0);
それかアセンブラ風にこういうのも好き。
sbi(PORTB,PB5);
sbi(PORTB,PB0);
こういう書き方の方が16進数慣れてない人には見やすい。ピン配置とプログラムをある程度柔軟に変えやすいのが近代的。(PB0からPB3に変えるのも、エディタの置換で一発だ)
どうなってるのかというと……
■PB5やPB0とは何か?
C:\WinAVR\avr\include\avr\iom8.h を見ると
/* PORTB */
#define PB7 7
#define PB6 6
#define PB5 5
#define PB4 4
#define PB3 3
#define PB2 2
#define PB1 1
#define PB0 0
と宣言されている。なので
PORTB = _BV(PB5)|_BV(PB0);
は
PORTB = _BV(5)|_BV(0);
と同じ事。
■_BV()とは何か?
C:\WinAVR\avr\include\avr\sfr_defs.h を見ると
#define _BV(bit) (1 << (bit))
となっている。
PORTB = _BV(5)|_BV(0);
は
PORTB = 1<<5|1<<0;
となる。
つまり、_BVはn+1桁目のビットだけがセットされた数を返すマクロだ。
■論理和
最後に | は、両辺のビットの論理和をとるので
0b100|0b001 == 0b101;
になる。
というわけで_BVを使うのがわかりやすい。
■sbi, cbi
sbiとcbiをマクロで定義しておくと、レジスタ操作はアセンブラ風に書けて、ルーチンはC言語で書ける。
#define sbi(BYTE,BIT) BYTE|=_BV(BIT)
#define cbi(BYTE,BIT) BYTE&=~_BV(BIT)
こんな風に。
sbi(PORTB,PB5);
sbi(PORTB,PB0);
■関連:s.h.log: AVR-GCCのレジスタ操作関数&マクロ
loop_until_bit_is_set(UCSRA,UDRE);
とか
if(bit_is_set(PINC, PC0)) return 0;
if(bit_is_set(PINC, PC1)) return 1;
if(bit_is_set(PINC, PC2)) return 2;
if(bit_is_set(PINC, PC3)) return 3;
if(bit_is_set(PINC, PC4)) return 4;
if(bit_is_set(PINC, PC5)) return 5;
とかもある。
そろそろ自分のlibcを整備しようかな