AVRマイコンの割り込み

 AVRマイコンにはタイマ、AD変換、その他の複数の割り込みが存在する。ここでは、割り込みの基本的な動作・プログラミング手順と、外部割り込みへの適用について説明する。

 AVRマイコン(他のマイコンでもほぼ同様であるが)での、割り込み処理の流れは、

             

      ※ SERGはステータスレジスタ。
    Iビットを操作する事で割り込み全体を禁止/許可する。

      Iビットを1にする場合は sei()
                    0にする場合は cli()

             を実行する事

 の様になる。

具体的には、タイマや外部割り込み信号線から割り込み信号が与えられると、

  1.  SREGレジスタのIビットをチェックして、内容が1にセットされていて、
  2.  個別の割り込みマスクが設定されていなければ、
  3.  CPUは割り込みを受け付け、
  4.  ベクタテーブルから割り込みハンドラのアドレスを参照し、
  5.  割り込みハンドラにジャンプする。
    【注意】 割り込みハンドラ内では、デフォルトでSREG:I=0となっているため、他の割り込みは禁止される。
         割り込みハンドラがリターンする時にSREG:I=1となる。(多重割り込みの禁止)

のように動作する。


AVRマイコンには、

  • 5本の外部割り込み(INT0~3、INT6)
    • INT0:4ピン、 INT1:5ピン、 INT2:6ピン、 INT3:7ピン、 INT6:30ピン

               

  • 8本のピン変化割り込み(PCINT0~7)
    • PCINT0:22ピン、 PCINT1:23ピン、 PCINT2:24ピン、 PCINT3:25ピン
    • PCINT4:26ピン、 PCINT5:27ピン、 PCINT6:28ピン、 PCINT7:29ピン

の外部割り込み信号線がある。いずれも他の機能と共用されているので、設定で割り当てを変える必要がある。
外部割り込みピン変化割り込みの違いは、割り込みイベントの発生条件の違いによる。(レベルトリガ、エッジトリガについては、こちら)外部割り込みでは、以下の様に、割り込みイベントの発生条件を4つの中から選択できるが、ピン変化割り込みでは信号レベルの変化(1→0とか)の1種類となる。


外部割り込み信号線による割り込みのプログラミングの手順

具体的なプログラミングの手順は以下の通りである。

  1. 割り込みハンドラの定義
  2. 割り込みイベントの発生条件を設定
  3. 割り込みマスクの設定
  4. 全ての割り込みを許可

以下、順に説明する。


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)

cli();    // 全ての割り込みを禁止(SREG:I = 0)

 

サンプルプログラム

......

/*
 * INTx 割り込みハンドラ
 *    割り込み発生時は、PC7を3回点滅させる。
 */
//INTx 割り込みのベクタテーブルを指定
ISR(INT0_vect) // ピン割り込み(INT0 4ピン)
//ISR(INT1_vect)  //ピン割り込み(INT1 5ピン)
//ISR(INT2_vect)  //ピン割り込み(INT2 6ピン)
//ISR(INT3_vect)  //ピン割り込み(INT3 7ピン)
//ISR(INT6_vect)  //ピン割り込み(INT6 30ピン)
{
    int i;

    for (i=0; i<3; i++)
    {
        PORTC = 0x80;  // PC7(オンボードLED)をON
        _delay_ms(100);

        PORTC = 0x00;  // PC7(オンボードLED)をOFF
        _delay_ms(100);
    }        
}


int main()
{
    CLKPR = 0x80; CLKPR = 0;    // 16MHz動作のための設定
    MCUCR &= ~(1 << PUD);      // プルアップを有効にする

/*
 ■外部割り込み(INT0~INT3)のマスクを設定する。各ビットが0の時、割り込みはマスク(禁止)される。(EIMSKレジスタ)
    使用可能な外部割り込みは、INT0~INT3、INT6
*/
    EIMSK |= 0x01;                    // Enable INT0(割り込みマスクを解除)
//    EIMSK |= 0x02;                    // Enable INT1(割り込みマスクを解除)
//    EIMSK |= 0x04;                    // Enable INT2(割り込みマスクを解除)
//    EIMSK |= 0x08;                    // Enable INT3(割り込みマスクを解除)
//    EIMSK |= 0x40;                    // Enable INT6(割り込みマスクを解除)

/*
 ■割り込みイベントの発生条件を選択する。(EICRAレジスタはINT0~INT3、EICRBレジスタはINT6)
      ISC?1   ISC?0 
        0       0     レベルトリガ(low active)
        0       1     エッジトリガ(両エッジ)
        1       0     エッジトリガ(立ち下がり)
        1       1     エッジトリガ(立ち上がり)

[EICRAレジスタ]
7(ISC31)  6(ISC30)  5(ISC21)  4(ISC20)  3(ISC11)  2(ISC10)  1(ISC01)  0(ISC00)
  INT3の発生条件        INT2の発生条件        INT1の発生条件        INT0の発生条件

[EICRBレジスタ]
7(未使用)  6(未使用)  5(ISC61)  4(ISC60)  3(未使用)  2(未使用)  1(未使用)  0(未使用)
                                    INT6の発生条件
*/

    EICRA |= 0x03;    //  INT0のトリガ選択(立ち上がりエッジで割り込み発生)
//    EICRA |= 0x0C;   //  INT1のトリガ選択(立ち上がりエッジで割り込み発生)
//    EICRB |= 0x30;    //  INT6のトリガ選択(立ち上がりエッジで割り込み発生)

    DDRC = 0x80;             // PortCのbit7を出力に。ボード上のLEDへの出力
    DDRD = 0x00;            //   PortDを入力に(INT0を使う場合)
    PORTD = 0x01;          //   PD0をプルアップ(INT0を使う場合)
//    DDRE = 0x00;            //   PortEを入力に(INT6を使う場合)
//    PORTE = 0x40;          //   PE6をプルアップ(INT6を使う場合)

    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レジスタは、割り込みイベントの有無を記録し、

  • 該当するビットが1で、かつ、割り込みが許可されている場合は、割り込みハンドラを呼び出し、ビットは0にリセット
  • 該当するビットが1で、かつ、割り込みが禁止されている場合は、割り込みハンドラは呼び出されず、ビットは1のまま。
  • 該当ビットが1の状態で、割り込み禁止状態から、割り込み許可状態に移行すると、割り込みハンドラが呼び出される。
  • EIFRの各ビットはソフトウエアで書き換え可能。(従って、このビットの制御によって、ソフトウエアで割り込みハンドラを
  • 呼び出したり、呼び出しをキャンセルすることが出来る。

のように使用することが出来る。
 


ピン変化割り込みのプログラミング手順

作成中...

 

 

多重割り込み

 割り込みハンドラを実行中に、別の割り込みイベントが発生するとどうなるか.... 考えてみよう。予想される解答は、

  1. 割り込みイベントは無視される。
  2. 割り込みイベントは保留される。
  3. 実行中の割り込みハンドラが、別の割り込みハンドラに割り込まれる。
  4. もう、訳分かんない。
  5. その他

 などであろうか。4と5は答えになって無いので無視するとして、1、2、3について考えてみる。

 まず、1の「割り込みイベントは無視される。」であるが、割り込みイベントが無視されると、

  • 時計が狂ったり
  • 音が鳴らなかったり
  • LEDが光らなかったり

 など、割り込みが関係する他の処理が動かない事になる。(あるいは正常に動作しない可能性が高い)
 これだと、色々、問題なので、実際には割り込みイベントが無視するという事は、一般には行わない。
 (無視するようにプログラミングする事は出来る。)

 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 誤り保護)



 

 

最終更新:2017年10月04日 18:37