1−1.使用方法2.内蔵EEPROM外部割り込みはその名の通り、外部から割り込み要求を受け付けるときに使用します。例えばプッシュスイッチをつないで、スイッチが押されたときに割り込みを発生させる時などは、この外部割り込みを使用することになります。
外部割り込み端子は6ピンです。これはポートDのbit2と兼用なので、外部割り込みを使用する場合には、ポートDの入出力設定で、bit2は入力にしておかなければなりません。プルアップの設定も可能なので、スイッチを接続する場合にはONにしておけばいいでしょう(詳細は第2回参照)。
外部割り込みを使用するにはまず、MCUCRで外部割り込み発生条件を設定しなければなりません。第1回でも書きましたがもう一度確認すると、
ISC01 ISC00 外部割り込み発生条件 0 0 INT0端子が0の時、割り込み発生 0 1 予約済み(この設定はしないこと) 1 0 INT0端子の立ち下がりで割り込み発生 1 1 INT0端子の立ち上がりで割り込み発生
となっています。ISC01とISC00がともに0の時は、INT0端子が0の間、ずっと割り込みを発生させ続けます。ISC01=1、ISC00=0の時はINT0端子が1から0に変化した瞬間に、ISC01=1、ISC00=1の時はその逆にINT0端子が0から1に変化した瞬間に、割り込みが発生します。プッシュスイッチをINT0端子につなぐ場合は通常、内部プルアップを有効にしてスイッチの片方の端子をGNDにつなぎ、ISC01=1、ISC00=0として、立ち下がりで割り込みが発生するようにしておきます。
その後、GIMSKのINT0を1にすると、外部割り込みが有効となります。もちろん、SEI命令で割り込み自体を有効にするのをお忘れなく。
上で述べたようにプッシュスイッチをつなぐ場合のプログラムは、
.INCLUDE "1200def.inc" .DEF STACK = R16 .DEF TEMP = R17 ; リセットベクトルと割り込みベクトルの指定 RJMP RESET ; リセット($000) RJMP EXT_INT0 ; 外部割り込み($001) RJMP RESET ; タイマー0オーバーフロー($002) RJMP RESET ; アナログコンパレータ($003) RESET: ; bit2のみ入力に設定 LDI TEMP, 0xFB OUT DDRD, TEMP ; bit2の内部プルアップを有効に設定 LDI TEMP, 0x04 OUT PORTD, TEMP ; 外部割り込み、立ち下がりで発生 LDI TEMP, (1<<ISC01) OUT MCUCR, TEMP ; 外部割り込みを有効に LDI TEMP, (1<<INT0) OUT GIMSK, TEMP SEI ; 〜ここにメインプログラムを記述〜 EXT_INT0: IN STACK, SREG ; 〜ここに外部割り込み処理プログラムを記述〜 OUT SREG, STACK RETI
となります。
1−2.特殊な使い方1−1.で外部割り込みを使用するには、ポートDのbit2を入力にしなければならないと書きましたが、実は出力に設定しても外部割り込みは使用可能です。この場合、bit2に出力されたデータがそのまま外部割り込み端子の入力になります。つまり、プログラムで外部割り込みを発生されることが可能になるわけです(ソフトウェア割り込み)。プログラムで示すと、
.INCLUDE "1200def.inc" .DEF STACK = R16 .DEF TEMP = R17 ; リセットベクトルと割り込みベクトルの指定 RJMP RESET ; リセット($000) RJMP EXT_INT0 ; 外部割り込み($001) RJMP RESET ; タイマー0オーバーフロー($002) RJMP RESET ; アナログコンパレータ($003) RESET: ; ポートDはすべて出力に設定 LDI TEMP, 0xFF OUT DDRD, TEMP ; すべて0を出力 LDI TEMP, 0x00 OUT PORTD, TEMP ; 外部割り込み、立ち上がりで発生 LDI TEMP, ((1<<ISC01) + (1<<ISC00)) OUT MCUCR, TEMP ; 外部割り込みを有効に LDI TEMP, (1<<INT0) OUT GIMSK, TEMP SEI ; ここでソフトウェア割り込み発生 LDI TEMP, 0x04 OUT PORTD, TEMP EXT_INT0: IN STACK, SREG ; 〜ここにソフトウェア割り込み処理プログラムを記述〜 OUT SREG, STACK RETI
となります。通常ソフトウェア的に別の処理プログラムを実行させる場合にはRCALL命令を使うので、この例はあまり意味がありませんが、たとえば通常は外部から割り込みを受け付け、特別な時にプログラムからその割り込みを発生させたい時などには利用できると思います。
AT90S1200には64バイトのデータ用内蔵EEPROMがあります。使い方の例としては、データテーブルをあらかじめEEPROM内に書き込んでおいて、実行時にそれを読み出す、などが考えられます。もちろん実行中の書き込みも可能ですから、書き換えもできます。ただ書き込みは多少遅い(最大4mS)ので、それだけは注意しなければなりません。読み出し/書き込みの例を以下に示します。3.アナログコンパレータ
.INCLUDE "1200def.inc" .DEF STACK = R16 .DEF TEMP = R17 ; EEPROM、$00番地を指定 LDI TEMP, 0x00 OUT EEAR, TEMP ; EEDRに0x12を書き込み LDI TEMP, 0x12 OUT EEDR, TEMP ; そのデータをEEPROMに書き込み SBI EECR, EEWE WAIT: ; EEWEが0になるまで待つ SBIC EECR, EEWE RJMP WAIT ; EEPROM、$00番地を指定 LDI TEMP, 0x00 OUT EEAR, TEMP ; EEPROMから読み出し SBI EECR, EERE ; そのデータをEEDRからTEMPに読み出し IN TEMP, EEDR
ここで新しく出てきた命令を説明しておきます。SBIは「Set Bit in I/O register」の頭文字を取ったもので、I/Oレジスタのあるビットを1にします。書式はSBI I/Oレジスタ, ビット
となります。上の例では2回出てきますが、前者はEECR($1C)のEEWE(bit1)を1にします。またここには出てきませんが、逆にI/Oレジスタのあるビットを0にしたい場合にはCBIという命令をつかいます。ただしこの2つの命令はどちらもI/Oレジスタ$00〜$1Fまででしか使用できないので注意が必要です。
その後のSBIC命令は「Skip if Bit in I/O register Cleared」の略で、I/Oレジスタのあるビットが0ならば、次の命令をスキップするという命令です。書式はSBIと同じく、SBIC I/Oレジスタ, ビット
となります。また逆にあるビットが1の時にスキップするSBISという命令もあります。この2つの命令もI/Oレジスタ$00〜$1Fまででしか使用できないので注意してください。私的意見として、SBIC、SBISは下手に多用するとプログラムが読みにくくなるので、コメントはちゃんと書いておいた方が良いと思われます。
アナログコンパレータを使用する良い例はちょっと思いつきませんが、要するに2つの入力に加えられる電圧の大小の変化で割り込みを発生させるときに使用します。アナログコンパレータの出力は、AIN0がAIN1よりも大きいときは1、その逆の時は0になっています。例えばコンパレータ出力が0から1になるときに割り込みを発生させる場合には次のようになります。
.INCLUDE "1200def.inc" .DEF STACK = R16 .DEF TEMP = R17 ; リセットベクトルと割り込みベクトルの指定 RJMP RESET ; リセット($000) RJMP RESET ; 外部割り込み($001) RJMP RESET ; タイマー0オーバーフロー($002) RJMP ANA_COMP ; アナログコンパレータ($003) RESET: ; ポートBのbit1、bit0を入力に設定 LDI TEMP, 0xFC OUT DDRB, TEMP ; 内部プルアップはなし LDI TEMP, 0x00 OUT PORTB, TEMP ; コンパレータ出力の立ち上がりで割り込み発生 LDI TEMP, ((1<<ACIS1) + (1<<ACIS0)) OUT ACSR, TEMP ; コンパレータ割り込みを有効に SBI ACSR, ACIE SEI ; 〜ここにメインプログラムを記述〜 ANA_COMP: IN STACK, SREG ; 〜ここにアナログコンパレータ割り込み処理プログラムを記述〜 OUT SREG, STACK RETI