[example] 外部割り込み

●概要というか設定の流れ

  1. ISR() {.......} の中に割り込みでやりたい処理を記述。
  2. GIMSK で割り込みに使いたいピンを定義
    (ATmegaでは GICR という名前)
  3. MCUCR で立ち上がり/立ち下がり/常にローで などの割り込み発生パターンを定義
  4. sei() で全体割り込み開始。

cli()で全体割り込みを停止できる。
レジスタ関連の名称等は AVRマイコン・リファレンス・ブック がかなり参考になる。
是非読んだ方が良い。


●INT0だけを使うシンプルコード

【動作】

INT0でピカピカッっと点滅

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

/*     AVRwiki より拝借マクロ
    cbi()    addrのbit番目をLowに
    sbi()    addrのbit番目をHighに    */
#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)


ISR (INT0_vect,ISR_BLOCK)
{
    PORTB = 0xFF;        //LED on
    _delay_ms(500);        //0.5sec 点灯させる
    PORTB = 0x00;        //LED off
}


int main( void )
{
    DDRB = 0xFF;    // PortBをLED点灯のためOutputに
    DDRD = 0x00;    //    PortDをSW入力のためすべてInputに
    PORTD= 0xFF;    //    PortD全てプルアップ。
    /* INT0を許可する */
    sbi(GIMSK,INT0);
   
    /* INT0 は立ち下がりで割り込み発生するよう設定 */
    sbi(MCUCR,ISC01);

    sei();        //全体割り込み許可
    for (;;);    //永久ループ。何もしない
}





●INT0とINT1両方使うコード

長いようだけど実はとても単純。
INT0をに付け加えただけ

【動作】

INT0でピカピカッっと点滅
INT1で1秒間点灯


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

/* AVRwiki より拝借マクロ
cbi()    addrのbit番目をLowに
sbi()    addrのbit番目をHighに    */
#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)



ISR (INT0_vect,ISR_BLOCK) // PD2 がLOWになった時はピカピカと光る
{
    PORTB = 0xFF;    //LED on
    _delay_ms(100);
    PORTB = 0x00;    //LED off
    _delay_ms(100);
    PORTB = 0xFF;    //LED on
    _delay_ms(100);
    PORTB = 0x00;    //LED off
}

ISR (INT1_vect,ISR_BLOCK) // PD3 がLowになった時は1秒間光る
{
    PORTB = 0xFF;        //LED on
    _delay_ms(1000);
    PORTB = 0x00;        //LED off
}

int main( void )
{
    DDRB = 0xFF;        // PortBをLED点灯のためOutputに
    DDRD = 0x00;        // PortDをSW入力のためすべてInputに
    PORTD= 0xFF;        // PortD全てプルアップ。
    /* INT0とINT1を許可する */
    sbi(GIMSK,INT0);
    sbi(GIMSK,INT1);
   
    /* INT0,INT1は立ち下がりで割り込み発生するよう設定 */
    sbi(MCUCR,ISC01);
    sbi(MCUCR,ISC11);

    sei();              //全体割り込み許可
    for (;;);
}






●注意

ベクタ名の記述

ベクタの名前は旧名称と新名称があるので注意。旧名称でも今の所動く。
ネット上には旧名称の物が多い。
avr-libc: <avr/interrupt.h>: Interrupts
この本家来ライブラリを参考に。

 新名称旧名称
 
 INT0_vect SIG_INTERRUPT0  INT0割り込み
 INT1_vect  SIG_INTERRUPT1  INT1割り込み

永久ループの表現

C言語では永久ループを
  • for(;;);
  • for(;;)
    {
    }
  • while(1)
    {
    }
と書いて実現する事が多い。


割り込み内で使う変数の定義方法

割り込みルーチン内で変数を定義しても最適化で消えてしまうらしい。
なので、グローバル変数にした上で volatile の宣言を行う事。
とりあえずの例
volatile char bu;
volatile int s;

ISR (INT0_vect)
{
        for (s=0;s<=554;s++)
        {
            bu = pgm_read_byte_near(leddata + s);
            uart_putchar(bu);
        }
        _delay_ms(3000);        // 2秒待つ
}


●謎

最近のWinAVRでは ISR 中の割り込み有り無しを指定できるっぽい。
ISR_BLOCK, ISR_NOBLOCK, ISR_NAKED
の3パターン。
でも、検証してない。
ドキュメント参考。






Comments