AVRのI2Cモジュール / リアルタイムクロックDS3231 / アラームを使う / 割り込み用の信号を外部割り込み(INTx)で検知する

  • Arduino実験キットで楽ちんマイコン開発 (マイコン活用シリーズ), p.183

    割り込み処理を軽くするために,外的要因の発生だけ割り込み処理で検知して,それに伴う処理は定常処理で行うという方法がよく使われます.〈略〉具体的には、割り込み処理でソフトウェアのフラグをセットし,それを定常処理でポーリングして,外的要因の発生を検知したら本処理を実行させるという方法です.〈略〉ポーリングに割り込みを併用する場合は,ポーリング処理では単純にフラグの状態をチェックするだけなので,オーバヘッドはほとんど無視できます.

  • C言語による PICプログラミング大全, p.301

    割り込み処理で長くかかる処理をしなければならない場合は、フラグを使って割り込み処理内ではフラグだけセットし、実際の処理はメイン処理Aの中でフラグをチェックすることで行うようにします。

前回は、DS3231から出力される割り込み用信号をAVRでポーリングして検知したが、今度はAVRの外部割り込み(INT0)を利用して検知する。ただし上記書籍のアドバイスに従って、割り込みサービスルーチンはアラームの発動を受けてフラグを立てるだけにとどめ、必要な処理はイベントループ内で実行することにする。
f:id:ti-nspire:20200207114828p:plain:h300
f:id:ti-nspire:20200207115033p:plain:h500

#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;
}