外部割り込みは INT0(PB2) ピンにより起動されるので、今回はこのポートを入力として使うが、割り込みが許可されていれば出力として設定されていても割り込みが起動されるので注意する必要がある。外部割り込みは、立ち上がり、立ち下がり、ピン変化(両エッジ)、又は Low レベルで起動できる。これは MCUCR(MCU Control Register) レジスタの bit1(ISC01) と bit0(ISC00) で設定できる (Interrupt Sense Control 0 bit1 and 0)。
赤外線受光素子の出力は負論理なので、立ち下がりエッジで割り込みを発生させる。 ISC01 をセット(1)し、 ISC00 をクリア(0)することで立ち下がりエッジで割り込みが発生する。初期値はどちらもクリアされている。
外部割り込みは、ステータスレジスタ(SREG)の全割り込み許可(I)ビットと一般割り込みマスクレジスタ(GIMSK)の外部割り込み許可 bit6(INT0) のセットにより有効となる。
ldi temp, (1<<ISC01) ;(1<<ISC01)はISC01ビットを1にするという意味 out MCUCR,temp ;外部割り込み、立ち下がりで発生 ldi temp,(1<<INT0) ; out GIMSK,temp ;外部割り込みを有効に sei ;Global Interrupt Enableこれだけで PB2 に立ち下がりパルスが入力される都度割り込みが発生する。割り込みが発生すると自動的にプログラムカウンターがスタックに保存され、 $002 番地にジャンプする。 そこで $002 番地に書かれた割り込みルーチンを実行する。割り込みルーチンの先頭でステータスレジスタ(SREG)の内容を保存してから割り込みルーチンを実行し、最後にステータスレジスタの内容を戻す。 reti 命令でスタックからプログラムカウンタが戻され、割り込みの発生したプログラムカウンタの次に実行を移す。
割り込みが発生するとステータスレジスタの全割り込み許可がクリアされ、割り込み処理が完了してスタックからプログラムカウンターが戻されると再び全割り込み許可がセットされる。この間にすでに割り込みが発生している場合はこの時点で再び割り込み処理が開始される。
.def stack = r16 rjmp reset rjmp ext_int0 ;外部割り込み要求0 reti reti reti reti reti reti reti reset: ;ここで PB2 に立ち下がりパルスが入力されると割り込みが発生する。 rjmp reset ext_int0: in stack,SREG ;ここで SREG の内容をレジスタに読み込んでおいて ;ここに割り込みプログラムを記述する out SREG,stack ;割り込み処理が完了したら SREG の内容を戻してから reti ;割り込みの発生した次のプログラムステップに戻る
ATtiny15L にプログラムを書き込んでテストボードにサーボをつなぎ、実際に動作を確認してみた。このままのプログラムでも十分実用になりそうだ。