うしこlog
公開: 2013/07/18

AVRでの割り込みの使い方

今回の内容

 AVRでの割り込みの使い方を説明します。AVRはATmega88シリーズを使います。割り込みには、シリアル割り込みやピン入力が変化したときの割り込み等がありますが、今回はタイマー割り込みについて説明します。

次回の内容

 次回は、AVRのUSART機能を使用してAVRとパソコンとの間でシリアル通信をするための知識や準備をします。

[追記] AVRに関する記事を以下の記事にまとめましたので、ぜひご覧ください。

AVRに関する記事

割り込みの種類

AVRの割り込みの種類には、以下のようなものがあります。

AVRの割り込みの種類
シンボル 名前 説明
INT0_vect 外部割込みピン INT0 外部ピンの変化で割り込み
INT1_vect 外部割込みピン INT1 外部ピンの変化で割り込み
PCINT0_vect 外部割込みピン INT0 ピンの論理変化割り込みのみサポート
PCINT0〜23まである
TIMER0_COMPA_vect タイマ0
コンペアマッチA
タイマ0でコンペアマッチAのとき割り込み
TIMER0_COMPB_vect タイマ0
コンペアマッチB
タイマ0でコンペアマッチBのとき割り込み
TIMER0_OVF_vect タイマ0
オーバーフロー
タイマ0でカウンタ最大値を超えたとき割り込み
TIMER1_COMPA_vect タイマ1
コンペアマッチA
タイマ1でコンペアマッチAのとき割り込み
TIMER1_COMPB_vect タイマ1
コンペアマッチB
タイマ1でコンペアマッチBのとき割り込み
TIMER1_CAPT_vect タイマ1
捕獲イベント
タイマ1で ICR1に達したときに割り込み
TIMER1_OVF_vect タイマ1
オーバーフロー
タイマ1でカウンタ最大値を超えたとき割り込み
TIMER2_COMPA_vect タイマ2
コンペアマッチA
タイマ2でコンペアマッチAのとき割り込み
TIMER2_COMPB_vect タイマ2
コンペアマッチB
タイマ2でコンペアマッチBのとき割り込み
TIMER2_OVF_vect タイマ2
オーバーフロー
タイマ2でカウンタ最大値を超えたとき割り込み
SPI_STC_vect SPIシリアル転送完了 SPIシリアル転送完了のとき割り込み
USART_RX_vect USART受信完了 USART(シリアル通信)受信完了のとき割り込み
USART_UDRE_vect USART送信可能 USART(シリアル通信)送信可能のとき割り込み
USART_TX_vect USART送信完了 USART(シリアル通信)送信完了のとき割り込み

 割り込みのタイミングは、ピン入力の変化時や、タイマーで指定した時間の経過時、シリアル通信イベント時などがあります。もちろん、他にも割り込みの種類があります。
使いたい割り込みのシンボルは、ISR()関数の引数に指定して使います。

割り込み処理の基本

 割り込みを許可する命令は、sei命令です。割り込み関数(ISR)からmainへ戻る命令は、ret命令です。
mainから、割り込み関数(ISR)に処理が移るとき、いったん割り込みが禁止されます。割り込み処理が終わると、割り込みをまた許可しないといけません。そのため、ret命令とsei命令を組み合わせた、reti命令があります。reti命令で割り込み処理が終わります。
また、割り込みを禁止にするには、cil命令を使います。

#include <avr/io.h>
#include <avr/interrupt.h>  //割り込みを使用するため

//ISR-main間で使う変数count
//コンパイラは、この変数を最適化しない
volatile unsigned char count;

//割り込み関数
ISR(TIMER0_OVF_vect) //timer0でオーバーフローが起きたとき
{
  count++;
}

int main()
{
  //ここで割り込みを行うためにレジスタの設定をする
  
  //cil();  //割り込み禁止
  sei();    //割り込み許可
  while(1){
    //普段の処理
  }
  
  return 0;
}

実際には、割り込みを使いたいときはsei命令を、割り込みを使いたくないときはcil命令を書けばいいです。retやretiは、気にしなくてよい。

タイマ割り込みの使用方法

 タイマの割り込みを使うための、レジスタ設定およびプログラムを述べていきます。

 タイマに関しての記事は、AVRでPWMを使うを見ていただければレジスタの設定などが分かると思います。

タイマ0の割り込み

タイマ0割り込みレジスタ TIMSK0
ビット 7 6 5 4 3 2 1 0
名前 - - - - - OCIE0B OCIE0A TOIE0

OCIE0B :タイマ0のコンペアマッチBの割り込み (比較一致Bの割り込み)

OCIE0A :タイマ0のコンペアマッチAの割り込み (比較一致Aの割り込み)

TOIE0 :タイマ0のオーバーフロー割り込み


以下に、タイマ0で、コンペアマッチAで割り込みをするプログラム例を示します。

#include<avr/io.h>
#include <avr/interrupt.h>  //割り込みを使用するため

ISR(TIMER0_COMPA_vect) //timer0でのコンペアマッチAの割り込み関数
{
  //ここに割り込み時の処理を書く
}

int main(void){
   //timer0 制御レジスタA
  TCCR0A = 0b10000010;  //10:コンペアマッチAでLOW, 10:CTCモード
   //timer0 制御レジスタB
  TCCR0B = 0b00000001;  //分周なし
   //timer0 割り込み設定
  TIMSK0 = 0b00000010;  //コンペアマッチAの割り込みを設定
  
   //コンペアマッチするタイミング
  OCR0A = 32499;  //32.5msでコンペアマッチ @1MHz
  
  //ポートの設定とかする
  
  sei();  //割り込み許可
  while(1){   //無限ループ
  }
  return 0;   //プログラム終了
}

タイマ1の割り込み

タイマ1割り込みレジスタ TIMSK1
ビット 7 6 5 4 3 2 1 0
名前 - - ICIE1 - - OCIE1B OCIE1A TOIE1

ICIE1 :タイマ1の捕獲割り込み (タイマ(カウンタ)の値がICR1に達したときの割り込み)

OCIE1B :タイマ1のコンペアマッチBの割り込み (比較一致Bの割り込み)

OCIE1A :タイマ1のコンペアマッチAの割り込み (比較一致Aの割り込み)

TOIE1 :タイマ1のオーバーフロー割り込み


以下に、タイマ1で、捕獲割り込みをするプログラム例を示します。

#include<avr/io.h>
#include <avr/interrupt.h>  //割り込みを使用するため

//timer1での捕獲割り込み関数 (ICR1に達すると割り込み)
ISR(TIMER1_CAPT_vect) 
{
  //ここに割り込み時の処理を書く
}

int main(void){
   //timer1 制御レジスタA
  TCCR1A = 0b00000010;  //高速PWMモード(top値:ICR1)
   //timer0 制御レジスタB
  TCCR1B = 0b00011001;  //高速PWMモードで、分周なし
   //timer0 割り込み設定
  TIMSK1 = 0b00100000;  //捕獲割り込みを設定
  
   //割り込み発生する時間の設定
  ICR1 = 64999; //65.0ms @1MHz
  
  //ポートの設定とかする
  
  sei();  //割り込み許可
  while(1){   //無限ループ
  }
  return 0;   //プログラム終了
}

タイマ2の割り込み

タイマ2割り込みレジスタ TIMSK2
ビット 7 6 5 4 3 2 1 0
名前 - - - - - OCIE2B OCIE2A TOIE2

OCIE2B :タイマ2のコンペアマッチBの割り込み (比較一致Bの割り込み)

OCIE2A :タイマ2のコンペアマッチAの割り込み (比較一致Aの割り込み)

TOIE2 :タイマ2のオーバーフロー割り込み


タイマ2は、タイマ0と同じ使い方なので、プログラム例は省略します。

<< AVRでのタイマーとPWMの使い方 AVRのUSARTでシリアル通信へ >>