Arduino実験キットで楽ちんマイコン開発 (マイコン活用シリーズ), p.183
割り込み処理を軽くするために,外的要因の発生だけ割り込み処理で検知して,それに伴う処理は定常処理で行うという方法がよく使われます.〈略〉具体的には、割り込み処理でソフトウェアのフラグをセットし,それを定常処理でポーリングして,外的要因の発生を検知したら本処理を実行させるという方法です.〈略〉ポーリングに割り込みを併用する場合は,ポーリング処理では単純にフラグの状態をチェックするだけなので,オーバヘッドはほとんど無視できます.
C言語による PICプログラミング大全, p.301
割り込み処理で長くかかる処理をしなければならない場合は、フラグを使って割り込み処理内ではフラグだけセットし、実際の処理はメイン処理Aの中でフラグをチェックすることで行うようにします。
前回は、DS3231から出力される割り込み用信号をAVRでポーリングして検知したが、今度はAVRの外部割り込み(INT0)を利用して検知する。ただし上記書籍のアドバイスに従って、割り込みサービスルーチンはアラームの発動を受けてフラグを立てるだけにとどめ、必要な処理はイベントループ内で実行することにする。
#include <avr/io.h> #include <util/delay.h> #include "USART.h" #include "myI2Cv2.h" #include "DS3231.h" volatile uint8_t alarmActivated = 0; ISR(INT0_vect){ alarmActivated = 1; // INT0に割り込みがかかったら(DS3231の!INT信号のfalling edgeが検知されたら)、それを示すフラグを立てる。 } void initInterrupt0(){ EIMSK |= (1 << INT0); // INT0 (外部割り込み要求0)を有効化する。 EICRA |= (1 << ISC01); // 立ち下がりエッジで割り込むことにする。 sei(); // グローバル割り込みを有効化する。 } int main(){ initUSART(); // DDRD &= ~(1 << PD2); // PD2のIOをINにする(0にする)(INが初期値なので省略できる)。内部プルアップはしない。 DS3231 rtc; // リアルタイムクロックDS3231 (I2Cスレーブ)を実体化する。 myI2Cv2.enable(80); // システムクロックの80分周をI2CクロックとしてAVRのI2Cモジュールを有効化する。 //rtc.setDateTimeMan(); // USART経由で手動で時刻合わせをして、 printString("***** Set the alarm 1 *****\n"); // USART経由で手動でアラーム1の発動タイミングを設定して、 rtc.setAlarmMan(1); printString("***** Set the alarm 2 *****\n"); // USART経由で手動でアラーム2の発動タイミングを設定して、 rtc.setAlarmMan(2); rtc.enableAlarm(3); // アラーム1、アラーム2を両方有効化して、 initInterrupt0(); // AVRの外部割り込み(INT0)を有効化して、 while(1){ if(alarmActivated){ // アラームが発動したら、 uint8_t whichAlarm = rtc.whichAlarmActivated(); // どちらのアラームが発動したのかを調べて、(1または2、両方発動時は3) rtc.getDateTimeBCD(); // それに応じて何かをして、 rtc.printDateTime(); printString(" Alarm "); printNibble(whichAlarm); printString(" has been activated.\n"); rtc.clearAlarmFlag(whichAlarm); // そのアラーム発動フラグを解除する。 alarmActivated = 0; } _delay_ms(100); } // unreachable: rtc.disableAlarm(3); // アラーム1、アラーム2を両方無効化する。 myI2Cv2.disable(); return 0; }