モチベーション
Arduinoで10分ごとのインターバルで処理を実行したいが、処理中以外はディープスリープして電力消費を節約しようとした。
Arduinoのディープスリープからの復帰を内部ウォッチドッグタイマー(WDT)を利用して行っていたが、たまに無限再起動に陥り処理ができなくなることがあった(WDTの暴走と思われる)。
外部RTCモジュールを利用するれば回避できるかもしれないので、ディープスリープからの復帰用に定期的な(10分ごとの)割り込み信号を発生させたい。
RTCモジュール
RTCモジュールとして、RV-1805を組み込んだものを買っていた。数年放置してるうちにディスコンになってたけど…
Qwiic - RV-1805搭載 リアルタイムクロックモジュール--販売終了www.switch-science.com
で、定期的に信号を出すのがalarm(時刻で設定)の他にcountdown timer(時間で設定)があるらしい。今回は時刻は関係ないのでcountdown timerの方を使う。
使用機材
- Arduino Pro Mini (3.3V, 8Mhz)
- RV-1805搭載 RTCモジュール
接続
Qwiic対応のやつ持ってないので普通に接続。
- RTCモジュールの3.3VとGNDをArduino Pro Mini (3.3V)のVCCとGNDに接続。
- I2C通信用にRTCモジュールとArduino Pro MiniのSDA同士、SCL同士を結線。
- 割り込み信号用にRTCモジュールのINTとArduino Pro Miniの3番ピンを結線。
今回はI2Cで接続するのこれだけなので、RTCモジュールのI2Cプルアップ抵抗はそのまま使う設定。プルアップ抵抗使わない場合はモジュールのI2Cと書かれたジャンパーの部分のハンダを外せばいいらしい(Hookup Guide参照)。
コード
ライブラリとして次のものを用いる。
なお、次のコードは上記ライブラリのExample 1の改変である。ライブラリ自体はインストールせず、.inoファイルと同一フォルダーに突っ込んで使っている。
#include "SparkFun_RV1805.h" const byte interruptPin = 3; RV1805 rtc; void setup() { Wire.begin(); Serial.begin(9600); Serial.println("Alarm from RTC Example"); if (rtc.begin() == false) { Serial.println("Something went wrong, check wiring"); } //アラーム無効化 rtc.setAlarmMode(0); // Alarm disabled rtc.disableInterrupt(INTERRUPT_AIE); //Disable the Alarm Interrupt //カウントダウンタイマーと割り込み有効化 rtc.setCountdownTimer(10, COUNTDOWN_MINUTES, true, true); //10分毎、繰り返しあり、パルス rtc.enableInterrupt(INTERRUPT_TIE); //Enable the Timer Interrupt //RTCモジュールの出力を外部割り込み信号とする attachInterrupt(digitalPinToInterrupt(interruptPin), callback_func, FALLING ); } void loop() { if (rtc.updateTime() == false) //Updates the time variables from RTC { Serial.print("RTC failed to update"); } String currentDate = rtc.stringDate(); //Get the current date in dd/mm/yyyy format String currentTime = rtc.stringTime(); //Get the time Serial.print(currentDate); Serial.print(" "); Serial.println(currentTime); delay(60000); } void callback_func(){ Serial.println("Interrupted"); }
これで、10分ごとに1回割り込みが発生するようにできた。
ライブラリについて
SparkFun_RV1805.cppのsetCountdownTimer(uint8_t duration, uint8_t unit, bool repeat, bool pulse)だが、内部で
// Set timer value writeRegister(RV1805_CTDWN_TMR, (duration - 1)); writeRegister(RV1805_TMR_INITIAL, (duration - 1));
というコードがある。RV1805_CTDWN_TMRのレジスタ(0x19)は1回目のカウントダウンタイマーの値で、RV1805_TMR_INITIALのレジスタ(0x1A)はrepeatを有効にした時に再度セットされる値である。ここで、Application Manualには、(Timer Initial Value + 1)/(Countdown Timer Frequency)が周期になると書かれている。
これでsetCountdownTimer(2, COUNTDOWN_MINUTES, true, true)として実行してみると、初期化から1分後に最初の割り込みが発生、その後は2分毎のインターバルで割り込みが発生している。
これを見るに、RV1805_CTDWN_TMRのレジスタ(0x19)に関しては、1を減算する必要はないのではないか。つまり次のコードのようにする。
// Set timer value writeRegister(RV1805_CTDWN_TMR, duration); writeRegister(RV1805_TMR_INITIAL, (duration - 1));
duration = 1のときはうまく動作しないが、1分単位なら60秒としてsetCountdownTimer(60, COUNTDOWN_SECONDS, true, true)とすればよい。
参考
- Hookup Guide Qwiic Real Time Clock Module (RV-1805) Hookup Guide - SparkFun Learn
- Application Manual https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-1805-C3_App-Manual.pdf
- SparkFun_RV-1805_Arduino_Library https://github.com/sparkfun/SparkFun_RV-1805_Arduino_Library