AVR-GCCで外部入力割り込みことSIG_INTERRUPT0, SIG_INTERRUPT1を使った。

ピンへの入力電圧が高くなる瞬間/低くなる瞬間を検知(edge detection)して割り込みを起こせる機能で、スイッチや赤外線の解析などに使える。

普通、マイコンのピンへの入力はループの中で毎回いちいち if(bit_is_set(PORT,BIT)) とかやって監視しなければならないが、外部入力割り込みを使えばイベントドリブンなコードが簡単に書ける。地味だけど凄く良い。

(ハードウェアを制御する部分とメインルーチンを分けて書かないと、状態遷移や例外処理で頭がおかしくなってしまう)

DSC00608.jpg

チャタリング防止を施したスイッチを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消灯

sbi,cbiマクロはこっち