AVRでの割り込みの使い方
今回の内容
AVRでの割り込みの使い方を説明します。AVRはATmega88シリーズを使います。割り込みには、シリアル割り込みやピン入力が変化したときの割り込み等がありますが、今回はタイマー割り込みについて説明します。
次回の内容
次回は、AVRのUSART機能を使用して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の割り込み
| ビット | 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の割り込み
| ビット | 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の割り込み
| ビット | 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でシリアル通信へ >> |