最近出たこの本、すごくいい。

マイコンもATmega168で最新だし、gccでのコードが載っているのでよくわかる。

AVRマイコン活用ブック—オリジナル電子ゲーム&ロボット製作
松原 拓也
電波新聞社 (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を整備しようかな