2010-06-23
外部割り込み
今回は外部割り込みについて。外部割り込みは、タイマ割り込みなどと違ってピンの状態によってかかる割り込みです。これを使うことにより、例えばスイッチの状態変化から、あるいは接続したモジュールから割り込みを書ける事が出来るようになります。
対象マイコン
全部(のはず) ただし、今回確認しているのはATTiny2313だけです。
外部割り込み概要
外部割り込みの種類は大まかにINTとPCINTの2種類があります。INTはレジスタによって、割り込みの起こる条件を4種類設定できるのに対し、PCINTでは1種類しかありません。またINTピンは二つくらいしか用意されれませんが、PCINTはたくさん*1用意されているようです。ピンの配置はデータシートを確認しましょう。他にINTピンだとスタンバイモードのAVRを復帰させることが出来ます。
使用しそうなレジスタ一覧
| レジスタ | description |
|---|---|
| MCUCR | INTの割り込みの方法を設定(ATTiny2313等) |
| GIMSK | 外部割り込みマスクレジスタ(ATTiny2313等) |
| GIFR | 外部割り込みフラグレジスタ(ATTiny2313等) |
| EICRA | INT割り込みコントロールレジスタ(ATMega168等) |
| EIMSK | INT割り込みマスクレジスタ(ATMega168等) |
| EIFR | ITN割り込みフラグレジスタ(ATMega168等) |
| PCICR | PCINT割り込みコントロールレジスタ(ATMega168等) |
| PCIFR | PCINTフラグレジスタ(ATMega168等) |
| PCMSK | PCINTピンのマスクレジスタ |
今回登場するレジスタは一見多いように見えますが、Tiny系とMega系でレジスタが若干変わってるので合わせて列挙しただけです。Mega系ではINTとPCINTのレジスタ自体が分かれてます。
INT、PCINTの割り込みの使い方はほとんど一緒で
などが必要でしょう。もちろんsei()も必要となります。
INT
INTピンは大抵はINT0、INT1の二つ用意されています。機能は一緒で、それぞれ設定するbitが異なってるくらいです。割り込みの起こる条件はMCUCRあるいはEICRAから設定します。
MCUCR(ATTiny2313等)
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| MCUCR | PUD | SM1 | SE | SM0 | ISC11 | ICS10 | ISC01 | ISC00 |
EICRA(ATMega168等)
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| EICRA | - | - | - | - | ISC11 | ICS10 | ISC01 | ISC00 |
ここで設定するのはISCビットで、INT1はISC11:0から、INT0はISC01:0からそれぞれ設定することになります。
Interrupt Sence Control(ISC)
| ISCn1 | ISCn0 | description |
|---|---|---|
| 0 | 0 | INTピンのLレベルで割り込み |
| 0 | 1 | INTピンの論理変化で割り込み |
| 1 | 0 | INTピンの立ち下がりで割り込み |
| 1 | 1 | INTピンの立ち上がりで割り込み |
AVRのスタンバイモードからの復帰で使いたい場合はLレベル割り込み、つまりISCn1:0 = 0とする必要があります。
次にマスクレジスタです。
GIMSK(ATTiny2313等)
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| GIMSK | INT1 | INT0 | PCIE0 | PCIE2 | PCIE1 | - | - | - |
EIMSK(ATMega168等)
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| EIMSK | - | - | - | - | - | - | INT1 | INT0 |
ここで使うビットはINT1とINT0のみです。それぞれセットするとせっとした名前のピンの割り込み有効になります。
最後にピンと割り込みハンドラ名の対応関係です。
割り込みハンドラ名
| ピン | ハンドラ名 |
|---|---|
| INT0 | INT0_vect |
| INT1 | INT1_vect |
PCINT
PCINTはピンの論理変化割り込みしかサポートしていませんが、数が多いのが特徴です。割り込みの方法を設定するレジスタはありません。
PCINT位置(ATTiny2313等)
| ピン | ポート | PCIE | PCMSK |
|---|---|---|---|
| PCINT7..0 | PORTB | PCIE0 | PCMSK0 |
| PCINT10..8 | PORTA | PCIE2 | PCMSK1 |
| PCINT17..11 | PORTD | PCIE1 | PCMSK2 |
PCINT位置(ATTiny2313等)
| ピン | ポート | PCIE | PCMSK |
|---|---|---|---|
| PCINT7..0 | PORTB | PCIE0 | PCMSK0 |
| PCINT14..8 | PORTC | PCIE1 | PCMSK1 |
| PCINT23..16 | PORTD | PCIE2 | PCMSK2 |
ポート別にレジスタが割り振られてるみたいなので、ビットの操作はある程度しやすくはなってそうです。
問題はavr-libcのバージョンによっては?PCINT7..0しかビット名が割り振られてない場合があることです。その場合は使えるピンはPCINT7..0だけになるか、あるいは頑張って使えるようにするかです。ビットの名前も最後の数字がとれてるので注意です。
割り込みを許可するレジスタはGIMSKあるいはPCICRです。
GIMSK(ATTiny2313等)
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| GIMSK | INT1 | INT0 | PCIE0 | PCIE2 | PCIE1 | - | - | - |
PCICR(ATMega168等)
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| PCICR | - | - | - | - | - | PCIE2 | PCIE1 | PCIE0 |
使用するビットはPCIE2:0の3つです。PCMSKはそれぞれ使いたいピンに対応するビットをセットします。
PCINTでは割り込みハンドラ名はPCINT_vectになっています。
サンプルコード
スイッチ関係を扱うとどうしてもチャタリングが問題になってくるのでチャタリングの心配がいらないようなプログラムにしておきました。
INT(Dフリップフロップっぽいの)
/* ATTiny2313 */ #include <avr/io.h> #include <avr/interrupt.h> ISR(INT0_vect) { /* PD5の状態をPD6に読み込む */ if((~PIND & (1<<PD5)) == (1<<PD5)) { PORTD |= (1<<PD6); } else { PORTD &= ~(1<<PD6); } } int main(void) { /* PD6をL出力、その他をプルアップ有り入力設定 */ DDRD = (1<<PD6); PORTD = ~(1<<PD6); MCUCR = (1<<ISC01); // INT0立ち下がり GIMSK = (1<<INT0); // INT0の割り込み許可 sei(); while(1); return 0; }
PCINT(リセット優先RSフリップフロップっぽいの)
/* ATTiny2313 */ #include <avr/io.h> #include <avr/interrupt.h> ISR(PCINT_vect) { /* * PCINT0 でセット、PNINT1でリセット * PB0 <=> PCINT0; PB1 <=> PCINT1 */ if((~PINB & (1<<PB0)) == (1<<PB0)) PORTD |= (1<<PD6); if((~PINB & (1<<PB1)) == (1<<PB1)) PORTD &= ~(1<<PD6); } int main(void) { /* PD6をL出力設定 */ DDRD = (1<<PD6); PORTD = ~(1<<PD6); /* PORTBをプルアップ有り入力に設定 */ DDRB = 0x00; PORTB = 0xFF; GIMSK = (1<<PCIE); // PCINT7:0の割り込み許可 PCMSK = (1<<PCINT0)|(1<<PCINT1); // PCINT0, PCINT1をマスク sei(); while(1); return 0; }
詳しくは
ATTiny2313データシート http://www.atmel.com/dyn/resources/prod_documents/doc8246.pdf
*1:電源用のピン以外すべて?
- 3 http://twitter.com/hijouguchi
- 2 http://syobocal.g.hatena.ne.jp/gae/comment?date=20100514
- 2 http://twitter.com/
- 2 http://windows-keitai.com/?NetWalker/PC-Z1/よくある質問/通信編
- 2 http://www.google.co.jp/search?q=電子工作 開発環境&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&hl=ja&client=firefox-a
- 2 http://www.google.com/imgres?imgurl=http://f.hatena.ne.jp/images/fotolife/h/hijouguchi/20080811/20080811122951.png&imgrefurl=http://d.hatena.ne.jp/hijouguchi/20080811/1218426560&h=450&w=300&sz=343&tbnid=yufSbjRe1VL4hM:&tbnh=127&tbnw=85&prev=/images?q=
- 1 http://bit.ly/b9cXrU
- 1 http://blog-search.yahoo.co.jp/search?ei=UTF-8&p=名工大+実験&n=10&so=dd&merge=on&tflg=none&sq=M&b=2
- 1 http://blog-search.yahoo.co.jp/search?ei=UTF-8&p=dp2+ビューファインダー&n=10&so=dd&merge=on&tflg=none&sq=M&b=2
- 1 http://blog-search.yahoo.co.jp/search?ei=UTF-8&p=ios+4+アップデート&n=10&so=gd&merge=on&tflg=none&sq=M&b=2
