AVRマイコンにはタイマ、AD変換、その他の複数の割り込みが存在する。ここでは、割り込みの基本的な動作・プログラミング手順と、外部割り込みへの適用について説明する。
AVRマイコン(他のマイコンでもほぼ同様であるが)での、割り込み処理の流れは、
の様になる。
具体的には、タイマや外部割り込み信号線から割り込み信号が与えられると、
のように動作する。
AVRマイコンには、
の外部割り込み信号線がある。いずれも他の機能と共用されているので、設定で割り当てを変える必要がある。
外部割り込みとピン変化割り込みの違いは、割り込みイベントの発生条件の違いによる。(レベルトリガ、エッジトリガについては、こちら)外部割り込みでは、以下の様に、割り込みイベントの発生条件を4つの中から選択できるが、ピン変化割り込みでは信号レベルの変化(1→0とか)の1種類となる。
外部割り込み信号線による割り込みのプログラミングの手順
具体的なプログラミングの手順は以下の通りである。
以下、順に説明する。
1.割り込みハンドラの定義
割り込みハンドラは、割り込み発生時に呼び出される関数の一種と考えればよい。
割り込みハンドラの名前(関数名)は、割り込み毎に事前に定義されていて、イベント名+_vectとなっている。(gccの場合)
従って、INT0の割り込みハンドラは、
INT0_vect |
となる。Cのソースで、割り込みハンドラを記述するには、
ISR(INT0_vect) // INT0_vectをベクタと呼ぶ |
のように、記述する事。なお、イベント名と割り込みの対応は、下表「表:ベクタテーブル」を参照のこと。
割り込みハンドラ実行中は、割り込み禁止状態になっている。割り込みハンドラも割り込まれる多重割り込みを使用したいなら、ハンドラ内でsei()を呼ぶ必要がある。
2.割り込みイベントの発生条件を設定
以下の表から、各外部割り込み毎に、割り込みイベントの発生条件を選択する。
レベルトリガ、エッジトリガについては、こちらを参照
表:外部割り込み(INT0~INT3、INT6)の割り込みイベント発生条件
ISCn1 | ISCn0 | 機能 | トリガ種別 |
---|---|---|---|
0 | 0 | INTピンのLレベルで割り込み | レベルトリガ |
0 | 1 | INTピンの論理変化で割り込み | エッジトリガ |
1 | 0 | INTピンの立ち下がりで割り込み | エッジトリガ |
1 | 1 | INTピンの立ち上がりで割り込み | エッジトリガ |
※ISCn1などのnは外部割り込みの名前(INT0なら0)を表す。
具体的には、以下の通り、EICRAレジスタ及びEICRBレジスタの該当ビットに対して上の表の内容で、設定を行う。
表:EICRAレジスタのビット配置
bitの位置 (ビットの名前) |
7 (ISC31) |
6 (ISC30) |
5 (ISC21) |
4 (ISC20) |
3 (ISC11) |
2 (ISC10) |
1 (ISC01) |
0 (ISC00) |
機能 | INT3のイベント発生条件 | INT2のイベント発生条件 | INT1のイベント発生条件 | INT0のイベント発生条件 | ||||
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
表:EICRBレジスタのビット配置
bitの位置 (ビットの名前) |
7 (未使用) |
6 (未使用) |
5 (ISC61) |
4 (ISC60) |
3 (未使用) |
2 (未使用) |
1 (未使用) |
0 (未使用) |
機能 | INT6のイベント発生条件 | |||||||
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
従って、INT2の割り込みイベント発生条件を、エッジトリガ(立ち下がり)としたいなら、
bitの位置 (ビットの名前) |
7 (ISC31) |
6 (ISC30) |
5 (ISC21) |
4 (ISC20) |
3 (ISC11) |
2 (ISC10) |
1 (ISC01) |
0 (ISC00) |
機能 | INT3のイベント発生条件 | INT2のイベント発生条件 | INT1のイベント発生条件 | INT0のイベント発生条件 | ||||
設定値 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
EICRA = 0x20; // INT2の割り込みイベント発生条件を、立ち下がりエッジに設定 以下のような簡潔な記述方法もあるが、ビット演算を学ぶため16進表記で記述する。 EICRA = _BV(ISC21); |
とする。
3.割り込みマスクの設定
EIMSKレジスタの該当ビットを操作する事で、割り込みをマスク(禁止)、あるいは許可する事が出来る。
表:EIMSKレジスタのビット配置
bitの位置 (ビットの名前) |
7 (-) |
6 (INT6) |
5 (-) |
4 (-) |
3 (INT3) |
2 (INT2) |
1 (INT1) |
0 (INT0) |
機能 | - | 1:INT6割り込みを許可 0:INT6割り込みを禁止 |
- | - | 1:INT3割り込みを許可 0:INT3割り込みを禁止 |
1:INT2割り込みを許可 0:INT2割り込みを禁止 |
1:INT1割り込みを許可 0:INT1割り込みを禁止 |
1:INT0割り込みを許可 0:INT0割り込みを禁止 |
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
従って、INT6割り込みを許可したいなら、
bitの位置 (ビットの名前) |
7 (-) |
6 (INT6) |
5 (-) |
4 (-) |
3 (INT3) |
2 (INT2) |
1 (INT1) |
0 (INT0) |
機能 | - | 1:INT6割り込みを許可 0:INT6割り込みを禁止 |
- | - | 1:INT3割り込みを許可 0:INT3割り込みを禁止 |
1:INT2割り込みを許可 0:INT2割り込みを禁止 |
1:INT1割り込みを許可 0:INT1割り込みを禁止 |
1:INT0割り込みを許可 0:INT0割り込みを禁止 |
設定値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
EIMSK |= 0x40; // Enable INT6(割り込みを許可) 以下のような簡潔な記述方法もあるが、ビット演算を学ぶため16進表記で記述する。 EIMSK |= _BV(INT6); |
のように記述する。
4.全ての割り込みを許可
3.の割り込みマスクの設定では、個別に割り込みの許可・禁止を切り替えていたが、これに加えて以下の様に、sei()関数とcli()関数を用いてSREGレジスタのIビットを設定する事で、割り込みの許可・禁止を切り替える。
sei(); // 設定済みの、全割り込みを許可(SREG:I = 1) |
サンプルプログラム
......
/* for (i=0; i<3; i++)
/* /* [EICRBレジスタ] EICRA |= 0x03; // INT0のトリガ選択(立ち上がりエッジで割り込み発生) DDRC = 0x80; // PortCのbit7を出力に。ボード上のLEDへの出力 sei(); // 全割り込みを許可 while(1) { |
その他
割り込みが禁止(=マスク)された状態で割り込みイベントが発生すると、割り込みハンドラは呼び出されない。ただし割り込みイベントの発生は、EIFRレジスタに記録される。
また、EIFRレジスタに記録された割り込みイベントは、割り込みがsei()によって許可されるか、もしくはEIMSKレジスタにより割り込みが許可されると同時に処理(つまり割り込みハンドラの呼び出し)される。
割り込みが禁止された状態で、EIFRレジスタの割り込みイベントをクリアする事も出来る。(割り込みが許可されても、割り込みハンドラの呼び出しは行われなくなる)
表:EIFRレジスタのビット配置
bitの位置 (ビットの名前) |
7 (-) |
6 (INTF6) |
5 (-) |
4 (-) |
3 (INTF3) |
2 (INTF2) |
1 (INTF1) |
0 (INTF0) |
機能 | - | INT6 割込イベント発生:1 割込ハンドラ呼出:0 ※1、※2 |
- | - | INT3 割込イベント発生:1 割込ハンドラ呼出:0 ※1、※2 |
INT2 割込イベント発生:1 割込ハンドラ呼出:0 ※1、※2 |
INT1 割込イベント発生:1 割込ハンドラ呼出:0 ※1、※2 |
INT0 割込イベント発生:1 割込ハンドラ呼出:0 ※1、※2 |
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
※1ビットに1を書くと、0に解除可能
※2レベルトリガを選択すると、常に0
【注意】
EIFRレジスタは、割り込みイベントの有無を記録し、
のように使用することが出来る。
ピン変化割り込みのプログラミング手順
作成中...
多重割り込み
割り込みハンドラを実行中に、別の割り込みイベントが発生するとどうなるか.... 考えてみよう。予想される解答は、
などであろうか。4と5は答えになって無いので無視するとして、1、2、3について考えてみる。
まず、1の「割り込みイベントは無視される。」であるが、割り込みイベントが無視されると、
など、割り込みが関係する他の処理が動かない事になる。(あるいは正常に動作しない可能性が高い)
これだと、色々、問題なので、実際には割り込みイベントが無視するという事は、一般には行わない。
(無視するようにプログラミングする事は出来る。)
2の「割り込みイベントは保留される」については、あり得る話である。なぜなら、割り込みにも色々な種類があるわけで、優先順位の高い割り込みを優先するというのは、必要な機能と考えられる。優先順位の高い割り込みイベントが処理されている間は、その他は、おとなしく待っている(=保留)という事だ。
3については、2の延長線上の話で、「優先順位の低い割り込みが、優先順位の高い割り込みによって、処理を割り込まれる」
ということである。
ただし、優先順位が低い割り込みであったとしても、プログラムの処理の都合で、どうしても割り込まれたくないという事もある。
(こういう部分を、クリティカルゾーンという)そのような場合は、割り込みをマスクする事で、割り込みが発生しないような配慮を行う必要がある。(クリティカルゾーンは、可能な限り、少なくするべき)
多重割り込みのイメージは以下の様な感じ。
AVRマイコンでは、デフォルトでは多重割り込みは発生しない設定になっている。なぜなら、割り込みハンドラの呼び出し時に、SREGレジスタのIビットが0に設定(つまりcli()が実行されるってこと)なので、他の割り込みが禁止されるからだ。
多重割り込みを実現したいなら、割り込みハンドラ内で、sei()を実行する必要がある。
以下に一覧(ベクタテーブル)を示す。
表:ベクタテーブル
No | Program Addres | Source (割込イベント) |
Interrupt Definition(割り込みの詳細) |
1 | $0000 | RESET | External Pin, Power-on Reset, Brown-out Reset,Watchdog Reset, and JTAG AVR Reset (外部リセット入力、電源ONリセット、ウオッチドックリセット、JTAGリセット) |
2 | $0002 | INT0 | External Interrupt Request 0 (外部割り込み0:INT0ピン) |
3 | $0004 | INT1 | External Interrupt Request 1 (外部割り込み1:INT1ピン) |
4 | $0006 | INT2 | External Interrupt Request 2 (外部割り込み2:INT2ピン) |
5 | $0008 | INT3 | External Interrupt Request 3 (外部割り込み3:INT3ピン) |
8 | $000E | INT6 | External Interrupt Request 6 (外部割り込み4:INT6ピン) |
10 | $0012 | PCINT0 | Pin Change Interrupt Request 0 (ピン変化割り込み0:PCINT0) |
11 | $0014 | USB | General USB General Interrupt request (USB一般割り込み) |
12 | $0016 | USB | Endpoint USB Endpoint Interrupt request (USBエンドポイント割り込み) |
13 | $0018 | WDT | Watchdog Time-out Interrupt (ウオッチドック タイムアウト) |
17 | $0020 | TIMER1 | CAPT Timer/Counter1 Capture Event (タイマ/カウンタ1 キャプチャ) |
18 | $0022 | TIMER1 COMPA | Timer/Counter1 Compare Match A (タイマ/カウンタ1A 比較・一致) |
19 | $0024 | TIMER1 COMPB | Timer/Counter1 Compare Match B (タイマ/カウンタ1B 比較・一致) |
20 | $0026 | TIMER1 COMPC | Timer/Counter1 Compare Match C (タイマ/カウンタ1C 比較・一致) |
21 | $0028 | TIMER1 OVF | Timer/Counter1 Overflow (タイマ/カウンタ1 オーバフロー) |
22 | $002A | TIMER0 COMPA | Timer/Counter0 Compare Match A (タイマ/カウンタ0A 比較・一致) |
23 | $002C | TIMER0 COMPB | Timer/Counter0 Compare match B (タイマ/カウンタ0B 比較・一致) |
24 | $002E | TIMER0 OVF | Timer/Counter0 Overflow (タイマ/カウンタ0 オーバフロー) |
25 | $0030 | SPI (STC) | SPI Serial Transfer Complete (SPI 転送終了) |
26 | $0032 | USART1 RX | USART1 Rx Complete (USART1受信) |
27 | $0034 | USART1 UDRE | USART1 Data Register Empty (USART1データエンプティ) |
28 | $0036 | USART1TX | USART1 Tx Complete (USART1送信完了) |
29 | $0038 | ANALOG COMP | Analog Comparator (アナログ比較器) |
30 | $003A | ADC | ADC Conversion Complete (AD変換完了) |
31 | $003C | EE READY | EEPROM Ready (EEPROM操作可) |
32 | $003E | TIMER3 CAPT | Timer/Counter3 Capture Event (タイマ/カウンタ3 キャプチャ) |
33 | $0040 | TIMER3 COMPA | Timer/Counter3 Compare Match A (タイマ/カウンタ3A 比較・一致) |
34 | $0042 | TIMER3 COMPB | Timer/Counter3 Compare Match B (タイマ/カウンタ3B 比較・一致) |
35 | $0044 | TIMER3 COMPC | Timer/Counter3 Compare Match C (タイマ/カウンタ3C 比較・一致) |
36 | $0046 | TIMER3 OVF | Timer/Counter3 Overflow (タイマ/カウンタ3 オーバフロー) |
37 | $0048 | TWI | 2-wire Serial Interface (TWI) |
38 | $004A | SPM READY | Store Program Memory Ready (SPM操作可) |
39 | $004C | TIMER4 COMPA | Timer/Counter4 Compare Match A (タイマ/カウンタ4A 比較・一致) |
40 | $004E | TIMER4 COMPB | Timer/Counter4 Compare Match B (タイマ/カウンタ4B 比較・一致) |
41 | $0050 | TIMER4 COMPD | Timer/Counter4 Compare Match D (タイマ/カウンタ4C 比較・一致) |
42 | $0052 | TIMER4 OVF | Timer/Counter4 Overflow (タイマ/カウンタ4 オーバフロー) |
43 | $0054 | TIMER4 FPF | Timer/Counter4 Fault Protection Interrupt (タイマ/カウンタ4 誤り保護) |