2011年3月26日土曜日

Arduinoとリアルタイムクロック -3: 定周期タイマー割り込み & スリープ



前回の続きでRTC8564と定周期割り込みライブラリの詳細。

< 資料 >
Download: Rtc8564AttachInterrupt.zip
Sketch: Rtc8564AttachInterruptSleep ▼
Library Code:
    Rtc8564AttachInterrupt.h ▼
    Rtc8564AttachInterrupt.cpp ▼


< 定周期割り込みのタイムライン >

1. 通常計測時のタイムライン

RTC8564を使用して定周期割り込みタイマーを動かした場合、Arduino本体とは異なるタイムラインで
割り込みカウントダウンが実行され続ける。そのため、RTC割り込み信号が発信されてスリープが完了し、
何らかの処理を実行させている間にも設定した周期のカウントダウンは正確に実行される。

説明を追加

2. 電池・SDカード交換時のタイムライン

電気二重層コンデンサを使ったバックアップ回路をつなげば、電源をOFFにしてもコンデンサから電力供給が続く限り
定周期割り込みカウントダウンは実行され続ける。
つまりRTC8564のレジスタの日付時刻や設定は生きたままである。
スタンドアロンで組まれたシステムで電源をコンセントなどから供給しない場合の定点観測データロギングでは
これが最大の利点となる。


説明を追加


< RTC8564のレジスタ設定とライブラリ >

1. 日付時刻の設定

Rtc8564AttachInterrupt.cpp line20

void Rtc8564AttachInterrupt::init(void)
{
  delay(1000);
  Wire.beginTransmission(RTC8564_SLAVE_ADRS);
  Wire.send(0x00);  // write reg addr 00
  Wire.send(0x20);  // 00 Control 1, STOP=1
  Wire.send(0x00);  // 01 Control 2
  Wire.send(0x00);  // 02 Seconds
  Wire.send(0x00);  // 03 Minutes
  Wire.send(0x09);  // 04 Hours
  Wire.send(0x01);  // 05 Days
  Wire.send(0x01);  // 06 Weekdays
  Wire.send(0x01);  // 07 Months
  Wire.send(0x01);  // 08 Years
  Wire.send(0x00);  // 09 Minutes Alarm
  Wire.send(0x00);  // 0A Hours Alarm
  Wire.send(0x00);  // 0B Days Alarm
  Wire.send(0x00);  // 0C Weekdays Alarm
  Wire.send(0x00);  // 0D CLKOUT
  Wire.send(0x00);  // 0E Timer control
  Wire.send(0x00);  // 0F Timer
  Wire.send(0x00);  // 00 Control 1, STOP=0
  Wire.endTransmission();
}


とりあえず、全てのレジスタに一通りの設定をする。
レジスタはひとつひとつ設定値を指定してく方法の他に、上記のように設定値の送信キューをまとめて設定する方法がある。
この場合、開始のレジスタアドレスのみ最初に指定する。

RTC-8564NB アプリケーションマニュアル PAGE11
初期設定をする前は 00レジスタのSTOPビットに1、TESTビットに0を指定する。
16進数の『0x20』は、2進数では『00100000』( 2進数、8進数、10進数、16進数相互変換 )。
以下のレジスタへの設定値も同様に指定する。
最後に 00レジスタのSTOPビットに0を指定する。
Sketch では、上記の初期設定の後に、あらかじめ initDatetime()メソッドで指定していた日付時刻プロパティの日付時刻値を
上書きしている。

2. 定周期割り込みタイマー設定

Rtc8564AttachInterrupt.cpp line206

// 定周期割り込みタイマの継続確認
bool Rtc8564AttachInterrupt::isInterrupt(void)
{
  Wire.beginTransmission(RTC8564_SLAVE_ADRS);
  Wire.send(0x01);
  Wire.endTransmission();
  Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
  if(Wire.available()){
    return ((Wire.receive() & 0x04) != 0x04 ? false : true);
  }
  return false;
}


次に、定周期割り込みタイマーの継続確認を行う。
これは、システムの電源を切ってから再びONにした時にバックアップ電源で作動していたRTC8564のタイマー設定が生きていたら
前の設定を継続させるため。
確認は01レジスタのTFビットの値を調べる。
TFビットは定周期割り込みイベントが発生した後では"0" => "1"に変化しているため、
"1"だったら継続してる、"0"だったら設定が生きていないことになる。
isInterrupt()メソッドがFALSEを返した(前の設定が生きていなかった)場合、再びタイマー設定をやりなおす。
syncInterrupt()メソッドで設定する。

Rtc8564AttachInterrupt.cpp line144

// 定周期割り込みタイマの初期化
// param
//  mode: 割り込み周期モード選択フラグ / 0: 1秒(1Hz)周期, 1: 1分(60Hz)周期
//  term: 割り込み周期(0〜255)  mode:0 選択時は単位は「秒」、mode:1 選択時は単位は「分」
void Rtc8564AttachInterrupt::syncInterrupt(unsigned int mode, unsigned long term)
{
  // Control2レジスタ(定周期タイマの繰り返し・割り込み時の信号発信設定)
  Wire.beginTransmission(RTC8564_SLAVE_ADRS);
  Wire.send(0x01);  // Control2 address
  Wire.send(0x11);  // TI/TP:1(繰り返し割り込みモード),TIE:1(定周期割り込み時、Lレベルの割り込み信号を発生させる)
  Wire.endTransmission();
  
  // 定周期タイマ設定
  byte buf[2];
  if (mode == 1) {
    buf[0] = 0x83;  // TE:1(タイマON), TD1:TD0/1;1(カウントダウン周期を60Hz/1分に設定)
  } else {
    buf[0] = 0x82;  // TE:1(タイマON), TD1:TD0/1;0(カウントダウン周期を1Hz/1秒に設定)
  }
  buf[1] = term;    // タイマ周期を設定
  Wire.beginTransmission(RTC8564_SLAVE_ADRS);
  Wire.send(0x0E);  // Timer Control address
  Wire.send(buf, 2);
  Wire.endTransmission();
}


定周期タイマー割り込み設定は01レジスタと0Eレジスタで行う。

01レジスタのTI/TPビットは割り込み動作を1回で終わらせるか、それとも繰り返し行うかを設定する。
"1"で繰り返し、"0"で1回限りとなる。
01レジスタのTIEビットは割り込み信号の発生設定である。
"1"で割り込み発生時にINT端子からLレベル信号を出力し、"0"で信号発生を禁止する。
16進数の『0x11』は、2進数では『00010001』( 2進数、8進数、10進数、16進数相互変換 )。

0EレジスタのTEビットは定周期タイマー割り込みのON/OFFを設定する。
"1"で機能ON、"0"で機能OFFとなる。
0EレジスタのTD1・TD0ビットは定周期割り込みタイマーのカウントダウン周期クロックを設定する。
TD1:TD0/"1":"1" でカウントダウン周期を60Hz/1分に設定し、
TD1:TD0/"1":"0" でカウントダウン周期を1Hz/1秒に設定する。
syncInterrupt()メソッドの第一引数は、定周期タイマー割り込み周期の単位を設定するためのフラグである。
"1"ならば0Eレジスタには16進数の『0x83』(2進数で『10000011』)を設定する。
"0"ならば0Eレジスタには16進数の『0x82』(2進数で『10000010』)を設定する。



< Arduino側の設定 >

Arduino の外部割り込みピンはデジタル2ピンとデジタル3ピンであり、スケッチではデジタル2ピンを使用している。
RTC8564の定周期カウントダウンが終わって割り込みが発生すると、RTC8564のINTピンからLレベルの信号が発生し、
Arduinoのデジタル2ピンに入力される。
そうするとスリープが終わり、日付時刻がシリアル出力される。


0 コメント:

コメントを投稿