http://squeuei.hatenablog.com/entry/2016/08/16/201654squeuei.hatenablog.com
Chapter 8
割り込みを扱うときはISR()
を使う。厳密に言うところは関数じゃなくてマクロ。
引数として割り込みベクタを与える。割り込みベクタの定義はio.hに書いてある。
外部割り込み
外部割り込みを有効化するときは、2段階ある事を忘れないようにする。
- 使いたい割り込みベクタを有効化する
- 割り込みシステム全体を
sei()
で有効化する。
普通は割り込みに入るときにglobal interrupt enableがオフになるので、割り込み中に更なる割り込みが発生することは無い。それを許可したい場合は、ISRのなかでsei()
を呼ぶか、ISR_NOBLOCK
でISRを定義するかのどっちかにする。
割り込みを生じさせたくない場合はcli()
を使ってglobal interrupt enableをオフにする。再開したいときはsei()
を。
ピン変化割り込み
Pin-Change InterruptではPxyPCINTxが対応する。ただしxはアルファベットと数字で対応してるのでややこしい。PByはPCINT0,PCyはPCINT1、PDyはPCINT2みたいに。 割り込みベクタは全部のピンで共通なので、ISRの中でどのピンからの割り込みなのかを判定して処理しないといけない。
割り込みを受けるときは
- 同じバンクの複数のピンからトリガを受ける場合には
bit_is_clear(BUTTON_IN, BUTTON)
のようにどのピンからの割り込みなのかを調べる。 - 同じバンクに一つしかトリガを受けない場合には、立ち上がりと立ち下がりの両方に反応することに注意。どちらなのかを確認する必要がある。
ISRで変数を操作したいとき
ISRは引数を取れないので、mainからもISRからもアクセスできるグローバル変数を宣言する。 ただし、その変数はvolataileを付けること。つけないと、一度もmain内で変更されない変数とみなされて、コンパイラが定数に変更してしまうことがある。 空のforループを回すときにも同じ事をする。
Chapter 9
タイマ
タイマにはノーマルモードとCTCモードがある。 ノーマルモードではカウンタがオーバフローするまで動作する。タイマの種類にもよるが255あるいは65535。 CTCモードではOCRnAレジスタで指定した値までカウントする。 ATMega168の場合はTimer1が16bit、そのほかは8bit。現在のタイマーの値はTCNTxに格納されている。
CTCモードの場合はTCCRxA
レジスタでWGM01
を設定する。また、outputモードにする場合はTCCRxA
レジスタでCOMxA0
を設定する。また、outputモードにする場合は
Output Compare Resister OCRxA
ビットに
どのモードにせよ、プリスケーラを設定しなければ、タイマは動作しない。CSx2
、CSx1
、CSx0
の値を、データシートの表にしたがって設定する。
CPUスピード
CPUスピードを変える方法には“ヒューズ”を書き換える方法と、ソースコードの中で設定する方法の2つがある。
この本のサンプルコードに付属するMakefileではmake set_fast_fuse
することで8MHz動作に変更される。戻すときはmake set_default_fuses
。
そのほかにもAVRDUDEで設定変更ができるけど、例えばSPIEN-enable fuse bitを変更してしまうとSPIでのプログラミングができなくなったり(設定を戻すこともSPIではできない!)、CPUクロックソースを外部クロックに設定してしまったり(こっちはクロックや他のマイコンから1MHzの信号を印可してやればよいので、まだ対処しやすい)するので、注意が必要。
ソースコードで設定する場合には、Clock Prescalar Change Enableビットをセットしてから4クロック以内にプレスケーラの値を変更しないと行けない。これはけっこうやっかいなので、avr/power.h
にクロック変更用のマクロがすでに用意されている。
#include <avr/power.h>
clock_prescale_set(clock_div_1);
などとすればよい。
power.h
にはAVRに内蔵されている特定のモジュールの電源を落とすマクロなども用意されているので、省電力化したい場合には活用すると良い。