前回からの続きです。ここでは省電力化のためスリープを使うとして、そこから復帰する方法を説明します。Arduinoのスリープモードにはいくつかありますが、簡単なのは前回のようにEnerlibライブラリを使ってスリープすることです。以下からダウンロードできます。

https://github.com/Arduino-IoT/libraries/tree/master/Enerlib

前回のスケッチでは、最後にenergy.PowerDown()としてスリープに入ってしまうので、ここから起きることなく、動作が止まってしまいます。ある時間に起きるためには、外部からInterruptという信号を送り、起こさなくてはなりません。そのためには、第7回で使用したRTCモジュールが使えます。まだ使っていないSQWという端子がありますが、ここからスリープ中のArduinoを起こす信号を送ることができます。まさしくアラーム時計そのものです。ArduinoにはWatchdog timerといって、自身で自身を叩き起こす機能もあるのですが、最大8秒までしか待ってくれないので、8秒ごとに起こされてすぐに眠らなくてはなりませんので、フィールドデータロガーのように1時間単位でスリープさせたいものには不便です。

 

 ここでは例として、毎時00分に起き、10秒だけリレー(第11回参照)をONにし、またすぐにスリープに入るシステムをつくります。Arduino UNO版とArduino Pro Mini版の接続を示しますが、スケッチはどちらも同じです。なお、第7回の手順に沿って、RTCの時刻合わせは済んでいるものとします。

 

UNO版(電源はUSBからとるものとして省略しています。VinとGNDに電池をつないでもいいです)

 

 

 

Pro Mini版

 

 

 

 

#include <Enerlib.h>
#include <DS3232RTC.h>
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <avr/sleep.h>
#include <avr/power.h>

Energy energy;
bool rtcint = true; // RTC interruptを作動させるフラグ
int RelayPin=9; // リレーに信号を送るピン

void setup(void)
{
    setSyncProvider(RTC.get);  // ここでRTCの時刻をもとにArduinoの時刻を合わせる
   
    if(timeStatus() != timeSet) 
       Serial.println("Unable to sync with the RTC");
    else
       Serial.println("RTC has set the system time");
    delay(1000);

    /* ----- Setting up RTC alarm ----- */
    RTC.alarmInterrupt(1, false); //秒に関するアラームをクリア
    RTC.alarmInterrupt(2, false); //分に関するアラームをクリア
    RTC.oscStopped(true); //このへんはまあ気にしない
    //RTC.alarm(2); //今回は2系統のアラームは使わない
    RTC.alarm(1); //アラームのフラグをクリア
    attachInterrupt(0, alcall, FALLING); //アラームが作動するとピンの電圧が下がる(FALLING)ので、その際は関数alcallを実行
    //RTC.setAlarm(ALM2_EVERY_MINUTE , 0, 0, 0); //今回は使わないが、例えばこれでもよい
    RTC.setAlarm(ALM1_MATCH_MINUTES, 0, 0, 0, 0);
    //RTC.alarmInterrupt(2, true); //今回は2系統のアラームは使わない
    RTC.alarmInterrupt(1, true); //アラームを有効化

    /* ----- Preparation of relay operation ----- */
    pinMode(RelayPin, OUTPUT);
    digitalWrite(RelayPin, LOW);
}

void loop(void)
{
    if (rtcint)
    {     
      rtcint = false;
      //RTC.alarm(2);
      RTC.alarm(1); //次にもう一度アラームが効くように、ここで再びフラグをクリア

      /* Turn on the relay */
      digitalWrite(RelayPin, HIGH); //リレーをON
      delay(10000); //10秒待つ
      digitalWrite(RelayPin, LOW); //リレーをOFF
    }

  /* Enter sleep */
  energy.PowerDown();
}

void alcall() {
  rtcint = true; 
}

 

これで、上記の通り動作するはずです。なお、フラグrtcintはtrueから始まるため、時刻に関わらず、立ち上げのときは一度だけリレーがONします。ここで、スケッチについて説明を加えておきます。第7回で紹介したJack ChristensenさんのライブラリにあるRTC.setAlarm()というメソッドで、アラームを設定するわけですが、アラームにはいろいろ種類があって、1の系統と2の系統があるようです。ライブラリのDS3232RCT.hを覗いてみると、以下のようなコードがあります。

 

    ALM1_EVERY_SECOND = 0x0F,

    ALM1_MATCH_SECONDS = 0x0E,

    ALM1_MATCH_MINUTES = 0x0C,     //match minutes *and* seconds

    ALM1_MATCH_HOURS = 0x08,       //match hours *and* minutes, seconds

    ALM1_MATCH_DATE = 0x00,        //match date *and* hours, minutes, seconds

    ALM1_MATCH_DAY = 0x10,         //match day *and* hours, minutes, seconds

    ALM2_EVERY_MINUTE = 0x8E,

    ALM2_MATCH_MINUTES = 0x8C,     //match minutes

    ALM2_MATCH_HOURS = 0x88,       //match hours *and* minutes

    ALM2_MATCH_DATE = 0x80,        //match date *and* hours, minutes

    ALM2_MATCH_DAY = 0x90,         //match day *and* hours, minutes

 

ここでは毎時00分で起こしたいので、ALM1_MATCH_MINUTESがよいです。これで、分が0、秒が0のときを指定してアラームが作動してくれます。ALM2の系統では秒を指定できません。それぞれのアラームによって引数の個数が違いますが、RTC.setAlarm()は常に4つの引数をとるようで、1つ目から順に秒、分、時間、日です。ここではALM1を使うので、RTC.alarm()やRTC.alarmInterrupt()の引数は1にしてください。attachInterrupt()関数中にalcallという関数が指定されていますが、これにより、アラームが作動するとalcall関数が実行されます。alcall内でrtcintのフラグがtrueになるので、loop()関数内が実行されることになります。loop()関数の最後にはまたスリープの文があるので、ここで再び眠りに入るわけです。

 

これで、1時間のうち10秒はかなりの電力を消費しますが(第11回の通り、リレーは3.3V×100mAくらい使います)、3590秒は節電状態に入ります。Pro Mini 3.3V 8MHzモデルの場合は数mAで眠り続けます。