スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

avr、ATTiny2313の外部割込み(改訂版)

以前avrの割り込みの記事を書きましたが、検索でここにたどり着いている方はその記事が目的のことが多いようです。
その記事を読み返して見たのですが、あまり解りやすい記事では無いと感じたので今日はそれを書き直します。

ということで今日はいつも見てくださっている方にはあまり面白くない内容となっています。ごめんなさいね。



説明は丁寧に、というよりかなりしつこく書いています。解っているところは読み飛ばしてください。

では本文、avr、ATtiny2313の割込み。今回はPB0~7で利用できる、PCINT0~7(PinChangeINTerrupt)の使い方とついでに8ビットタイマの簡単な使い方の説明です。こういうのはプログラムを実際見て弄ってみうるのが最善だと思いますので、早速プログラムからです。
サンプルプログラムはPB7~4に繋いだスイッチのON/OFFが変わるとそれをPB3~0に反映するというプログラム。「そのままスイッチにつなげば良いじゃん」とか言わないで。あくまでサンプルなんだから。
入力ピンが浮いてるとLEDが灯いたと等の電流の変化で入力値が変化して意図しない割り込みがかかってしまうことがります。入力になっているピンは必ず電源電圧かグランドに繋ぐようにしよう。おにーさんとの約束だ。

#include <avr/io.h>
#include <avr/interrupt.h>//半角の<>はhtmlタグとして認識されてしまうようなので全角になっています。コピペして使うなら半角に直してください。

#define DELAYTIME 240

void initialize(){
DDRB=0b00001111; //PB7~4を入力、PB3~0を出力
PORTB=0b00000000; //PB7~4は0出力、PB3~0はハイインピーダンス入力
GIMSK=0b00100000; //PCINTを有効に
PCMSK=0b11110000; //PCINT7~4のみ有効
TCCR0B=0b00000101; //タイマ、クロックを1024分周
TIMSK=0b00000000; //タイマ割り込み無効
sei();       //割り込み全体許可
}

int main (void) {
initialize();
while(1){}
}

ISR(PCINT_vect){ //外部割込みが発生するとこの関数が呼ばれる
GIMSK=0b0000000;  //PCINT無効
TCNT0=DELAYTIME; //タイマの現在の値をDELAYTIMEに。
TIMSK=0b00000010; //タイマ割り込み有効
}

ISR(TIMER0_OVF_vect){   //タイマのオーバーフロー割り込みが発生するとこの関数が呼ばれる
TIMSK=0b00000000; //タイマ割り込み無効
GIMSK=0b00100000; //PCINT有効
PORTB=(0b11110000&PORTB)|(0b00001111&(PINB>>4));
              //PB7~4の状態をPB3~0にコピー。ビット演算です。
}

実際に使用するなら、電源、RESET、グランド端子を繋ぎ、PB7~4にスイッチ、PB3~0に抵抗をはさんでLEDを繋ぎます。

プログラムの流れを追うと、まず電源が入ると各種初期化を行い、無限ループに入って待機。
PB7~4に変化があると、タイマをセット、タイマ割り込みを許可。少し時間が経つとタイマのオーバーフロー割り込みがかかるので、その時にPB3~0の値を変更。再び無限ループに戻り待機。


さて、先ずは基本から。avrには様々な機能がありますが、それらを使用するためには多くの場合、機能の設定→実際に使用する命令、という手順を踏むことになります。機能の設定は特定のレジスタに値を書き込むことによって行われます。具体的に何処に書き込むのかというと、データシートを見るとDDRBだとかPCMSKだとか、様々なレジスタが説明されていますのでそこに書き込みます。WinAVRを用いるならばavr/io.hやavr/interrupt.h等のヘッダをインクルードし、DDRB=0b000111;のように代入することによって行うことができます。
それらのレジスタは基本的にビットが1で有効、0で無効です。使わない機能については何もしなければデフォルトで0が代入されています。


次はPCINTを使うときに変更する必要のあるレジスタの説明です。簡単に説明するだけなので、詳しいことはデータシートを見てください。また、以下の説明でレジスタの一部のビットに触れていないときでも大抵なんらかの機能が割り当てられています。特に意図が無ければ説明されていないビットは0にしておきましょう。それらのビットについて知りたければデータシートを見てください。
以下、8ビット中一番左端を第7ビット、右端を第0ビットと呼びます。
それでは、レジスタの説明に入ります。

SREG:第7ビットが1であれば割り込み全体の許可。sei()、cli()はこのレジスタを設定する関数。第7ビットはsei()でHi、cli()でLoになる。

DDRB:PB0~7を、入力にするか出力にするか決定する。Hiにしたビットと対応するピンが出力、Loにすると入力。
PORTB:ピンが入力と出力どちらになっているかで少し動作が違う。これもDDRBと同様、ビットとピンが一対一対応している。
   ピンが入力の時、Hiであればプルアップ抵抗付き入力、Loであればハイインピーダンス入力。
   ピンが出力の時、Hiであれば5V(というか電源電圧)出力、Loであれば0V出力。
PCMSK:これもビットとピンが一対一対応。Hiにしたビットと対応するピンのみPCINTが有効になる。
GIMSK:第5ビットがHiならPCINT有効、Loなら無効。
PINB:PCINTの使用前に変更するレジスタでは無いですが、ついでに。ピンの現在の状態を読み取る。DDRB等と同様ビットとピンが一対一対応。

次に8ビットタイマを使用するためのレジスタの説明です。
TCCR0B:第2、1、0ビットがタイマのクロック分周比を決定する。
   000でタイマの動作停止、001で分周比1、010で8分周、011で64分周、100で256分周、101で1024分周。
TIMSK:第1ビットが1であればタイマのオーバーフロー割り込み有効。
TCNT0:カウンタの現在の値です。TCNT0に値を代入することによって値を書き換えることも可能です。


割り込みが起こった時に実行する関数ですが、ISR(割り込みハンドラ名)という関数が割り込み原因に応じて実行されます。
PCINTとタイマ0のオーバーフローの割り込みハンドラ名はそれぞれPCINT_vectとTIMER0_OVF_vectです。それ以外の割り込みハンドラ名は
C:\WinAVR-********\doc\avr-libc\avr-libc-user-manual\group_avr_interrupts.html
(********は20081205等。日付と思われます)
を見て調べましょう。


ここで少しチャタリングについて説明しておきます。
チャタリングとは、(以下、wikipediaより)
リレーやスイッチの接点が切り替わった際に、微細で非常に速い機械的振動によって、電気信号が断続を繰り返す現象である。非常に短時間で消失する現象であるが、電子回路の誤動作の一因とされ、通常は電子回路を工夫することなどで予め対策が取られる。
(ここまでwikipediaより)
というものであり、ここではタイマを使ってチャタリングが収まった頃にピンの値を読み取ることによって対策を行います。
チャタリングは普通長くて10ms程度と言われているので、余裕を持って時間を取り、外部割込みがかかってから約16ms後にピンを読み取ります。
クロックは1MHz、分周比1024なのでタイマは約1msで1カウント、したがってタイマを240からカウントさせれば約16ms後に256(オーバーフロー)となり、タイマによる割り込みがかかります。
PINBからの読み取り処理はタイマ割り込みの中で行います。


とりあえずは以上です。何処が解り難かっただとか、もっと説明が欲しいとかあればコメントを頂ければ出来る限り修正したいと思います。
スポンサーサイト
コメント

うおお、
相変わらず難しいけどおもしろい…!
意味などまったくわかっていないのですがねw

Re: タイトルなし

あら、この記事書きかけで保存しただけのつもりだったのが公開になってるww
これどうしよう。

書き終わりました。
コメントの投稿
管理者にだけ表示を許可する

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。