AVR-GCCで外部入力割り込みことSIG_INTERRUPT0, SIG_INTERRUPT1を使った。
ピンへの入力電圧が高くなる瞬間/低くなる瞬間を検知(edge detection)して割り込みを起こせる機能で、スイッチや赤外線の解析などに使える。
普通、マイコンのピンへの入力はループの中で毎回いちいち if(bit_is_set(PORT,BIT)) とかやって監視しなければならないが、外部入力割り込みを使えばイベントドリブンなコードが簡単に書ける。地味だけど凄く良い。
(ハードウェアを制御する部分とメインルーチンを分けて書かないと、状態遷移や例外処理で頭がおかしくなってしまう)
チャタリング防止を施したスイッチをINT0,INT1(90S2313の場合はPD2,PD3)に接続して、入力がある時それぞれPB0,PB2のLEDが光る。→ソースコード、映像(5.1MB)
※デジタル入力全般に言える事だけど、使わない入力ピンが存在してはならない。何も接続しないピンはDDRを出力に向けるか、チャタリング防止をつけるかしないと怪しい動きをしてしまう。
■INT0を使う場合の書き方
外部割込みは立ち上がり/立ち下りの片方しか検知できない。
しかし、立ち上がったら立下り検知設定に、立ち下がったら立ち上がり検知設定にすれば両方検知できる。
外部割り込みの設定関数としてmain()より上の行に
/* PORT設定 */
void port_init(void){
DDRB = 0xff;
DDRD = 0xff;
}/* 外部割り込み INT0設定 */
void interrupt0_init(void){
cbi(DDRD, PD2); // INT0入力
sbi(GIMSK, INT0); // 外部割り込み0許可
sbi(MCUCR, ISC01);
if(bit_is_set(PIND,PD2)) // 既に立ち上がってる時
cbi(MCUCR, ISC00); // INT0立ち下がりエッジ検出設定
else sbi(MCUCR, ISC00); // INT0立ち上がりエッジ検出設定
}
を書く。
初期状態によって立ち上がり/下がりどちらから始めるか分岐する様にした。
割り込み時の処理。
LED1を付けたり消したりする。
/* INT0 外部割り込み */
SIGNAL(SIG_INTERRUPT0){
if(bit_is_set(PIND,PD2)){ // 立ち上がりの時
LED1_SET(); // LED1点灯
cbi(MCUCR,ISC00); // 立ち下がり検出設定に切り替え
}
else{ // 立ち下がりの時
LED1_CLR(); // LED1消灯
sbi(MCUCR,ISC00); // 立ち上がり検出設定に切り替え
}
}
mainはこれだけ
int main(void){
port_init(); // PORT設定
interrupt0_init(); // INT0設定
// interrupt1_init(); // INT1設定(INT0だけ使う)
sei(); // 割り込み許可for(;;){
}
}
ちなみに読み込むヘッダファイルやマクロの設定はこんな感じ。
LEDのON/OFFもあんまりハードコーディングしたくない。
#include
#include
#include/** 動作設定 **/
#define TRUE 1
#define FALSE 0
#define NULL ‘\0’
#define sbi(PORT,BIT) PORT|=_BV(BIT) // PORTの指定BITに1をセット
#define cbi(PORT,BIT) PORT&=~_BV(BIT) // PORTの指定BITをクリア/** LED設定 **/
#define LED1_SET() sbi(PORTB,PB0) // LED1点灯
#define LED1_CLR() cbi(PORTB,PB0) // LED1消灯
#define LED2_SET() sbi(PORTB,PB1) // LED2点灯
#define LED2_CLR() cbi(PORTB,PB1) // LED2消灯