にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

RV-1805搭載RCTモジュールを利用して10分インターバルの割り込み信号を作る

モチベーション

Arduinoで10分ごとのインターバルで処理を実行したいが、処理中以外はディープスリープして電力消費を節約しようとした。
Arduinoのディープスリープからの復帰を内部ウォッチドッグタイマー(WDT)を利用して行っていたが、たまに無限再起動に陥り処理ができなくなることがあった(WDTの暴走と思われる)。
外部RTCモジュールを利用するれば回避できるかもしれないので、ディープスリープからの復帰用に定期的な(10分ごとの)割り込み信号を発生させたい。

RTCモジュール

RTCモジュールとして、RV-1805を組み込んだものを買っていた。数年放置してるうちにディスコンになってたけど…

Qwiic - RV-1805搭載 リアルタイムクロックモジュール--販売終了www.switch-science.com

で、定期的に信号を出すのがalarm(時刻で設定)の他にcountdown timer(時間で設定)があるらしい。今回は時刻は関係ないのでcountdown timerの方を使う。

接続

Qwiic対応のやつ持ってないので普通に接続。

  • RTCモジュールの3.3VとGNDをArduino Pro Mini (3.3V)のVCCとGNDに接続。
  • I2C通信用にRTCモジュールとArduino Pro MiniのSDA同士、SCL同士を結線。
  • 割り込み信号用にRTCモジュールのINTArduino 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.cppsetCountdownTimer(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)とすればよい。