Skip to content

XRTC_PCF85063A

朝日薫 edited this page Dec 20, 2022 · 11 revisions

XRTC_PCF85063A I2CカレンダーICクラス

これはNXP PCF85063AカレンダーIC(外部RTC)を制御するインタフェースを提供する。 この I2CデバイスIC は "Duino" 系列製品のオンボードに搭載されており 内臓周辺機能での計時なしに長周期割込、アラーム割込、カレンダー日時保持を提供する。

以下の解説では暗に "Duino" ボード固有機能を前提にした内容も含まれることに注意されたい。

用例

#include <XRTC_PCF85063A.h>
XRTC_PCF85063A XRTC = {Wire};
void setup (void) {
  pinControlRegister(PIN_PF1) = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
  Serial.begin(CONSOLE_BAUD);
  Wire.initiate(TWI_SM);
  if (!XRTC.update()) {
    Serial.println(F("Failed XRTC"));
    for (;;);
  }
  XRTC.startPeriodTimer(1);
  set_sleep_mode(SLEEP_MODE_STANDBY);
  sleep_enable();
}
ISR(PORTF_PORT_vect) {
  PORTF_INTFLAGS = PIN1_bm;
}
void loop (void) {
  digitalWrite(LED_BUILTIN, TOGGLE);
  if (XRTC.update()) {
    bcddatetime_t BCD = XRTC.getBcdDateTimeNow();
    Serial
      .print(_BCDDT(BCD)->col.year, ZHEX, 4)
      .write('-')
      .print(_BCDDT(BCD)->col.month, ZHEX, 2)
      .write('-')
      .print(_BCDDT(BCD)->col.day, ZHEX, 2)
      .write(' ')
      .print(_BCDDT(BCD)->col.hour, ZHEX, 2)
      .write(':')
      .print(_BCDDT(BCD)->col.minute, ZHEX, 2)
      .write(':')
      .print(_BCDDT(BCD)->col.second, ZHEX, 2)
      .ln();
  }
  Serial.flush();
  sleep_cpu();
}

この用例ではXRTCに1秒周期割込を指示し、 それをPIN_PF1端子で捉えて CPU休止状態を解除し、 シリアルモニターに現在時刻を表示してまた CPU休止状態に入る動作を繰り返す。 時刻取得と表示には <bcddatetime.h> を利用している。

時刻設定を使わずに単に周期割込を発生させたいだけならstartPeriodTimer()を、 単発割込を発生させたいだけならstartCountdownTimer()を使えば良い。 割込出力はオープンドレインなので、外部入力端子にプルアップ設定は必要。

/* 60秒周期割込 : 毎00秒発動 */
XRTC.setMinuteInterruptEnable(true).activeTimer();

/* 30秒周期割込 : 毎00秒と毎30秒発動 */
XRTC.setHarfMinuteInterruptEnable(true).activeTimer();

/* その他任意長周期割込 : 1〜15300 秒範囲 : 現時刻起点 */
XRTC.startPeriodTimer(20);

/* 単発タイムアウト割込 : 1〜15300 秒範囲 : 現時刻起点 */
XRTC.startCountdownTimer(20);

/* 単発割込解除 : 解除するまで割込端子は LOW を維持 */
XRTC.clearTimerFlag();

/* 割込タイマー動作停止 */
XRTC.deactiveTimer();

このデバイスを使用せず、時刻管理も不要なら次の方法で停止できる。 停止しなければ不意に周期割込等が発生する場合がある。

/* デバイスを初期状態に戻し、計時機能停止 */
XRTC.reset();
XRTC.stop();

世紀補正

PCF85063Aの場合、年は2桁精度かつセンチュリービット機能を持たない。 このため00年には常に2月29日があり、2000年以外と一致しない。 つまり時刻管理の有効範囲は1900-03-01から2100-02-28である。 しかし曜日はそれと無関係に正しく更新されるので、 getCenturyDateTimeNow()メソッドは以下の補正を加えることで 1900-01-01から2299-12-31の400年間を正しく返却できる。

  1. 現在年月日を2000-01-01から2099-12-31と見做して MJD(修正ユリウス通日)を取得。
  2. MJDから得られる曜日から現在保持している曜日を減じて7の剰余Xを得る。
  3. X0であるなら2000年代であるから補正不要。
  4. MJDが51603以下(2000-02-29以前)である場合、
    a. MJDが51603であるなら存在してはならない閏日であるからYをマーク。
    b. X5であるなら1900年代であるからMJDより36524を減じる。
    c. X1であるなら2100年代であるからMJDに36525を加える。
    d. X3であるなら2200年代であるからMJDに73049を加える。
  5. MJDが51604以上(2000-03-01以降)である場合、
    a. X6であるなら1900年代であるからMJDより36525を減じる。
    b. X2であるなら2100年代であるからMJDに36524を加える。
    c. X4であるなら2200年代であるからMJDに73048を加える。
  6. 補正されたMJDから新たな年月日を導く。これは同時に存在しない02-2903-01に置換する。
  7. Yがマーク済なら現在年月日は誤りなので、新たな年月日を現在年月日に設定する。

上記の補正判定から漏れた年月日と曜日の組は、 グレゴリウス暦には存在しないので2000年代と見做さざるを得ない。 何故ならグレゴリウス暦は以下の式に従って、400年間で年月日と曜日の組が循環しているからだ。

400年 × 365日 + 閏日97日 == 146097日 == 20871週 × 7日(端数なし)

この性質から100年毎の同月同日の曜日はただ4通りしかなく、 それを超える範囲は曜日補正法では求めることが出来ない。

<XRTC_PCF85063A.h>

依存性:<api/TWIM.h> <bcddatetime.h>

classXRTC_PCF85063Aを定義する。

クラスインスタンス

初期化子にはTWIM_Classインスタンス(Wire等)を与える。 その I2C Bus を別途初期化することで、デバイス通信準備が整う。 通信速度は通常 100kbps(TWI_SM)を指示するが、 400kbps(TWI_FM)でも、 10kbps(TWI_LM)でも良い。

#include <XRTC_PCF85063A.h>
XRTC_PCF85063A XRTC = {Wire};
...
Wire.initiate(TWI_SM); /* Wire.begin(100000L) も可 */
XRTC.update();

デバイス制御

PCF85063Aの場合、2種類の精度校正機能がある。 また1バイトの任意RAM保持機能がある。

bool update (void)

デバイスの現在の制御状態を取得する。実行は即時。成功すれば真を返す。 これには現在の時刻情報の他、各種制御状態が含まれる。 遅延中の設定命令は反映されずに破棄される。 このメソッドは、これ以後の他の制御に先立って呼ばれなければならない。

bool load (void)

これはupdate()メソッドの別名として機能する。

bool saveSettings (void)

デバイスに新たな制御状態を反映させる。実行は即時。成功すれば真。 これは「実行は遅延」と説明された設定変更を、デバイスに送信する。

bool reset (void)

デバイスを再起動する。実行は即時。update()も続けて実行され、成功すれば真。 現在時刻は破棄されて2000-01-01 00:00:00から計時を始め、 アラームとタイマーは停止され、 周波数出力(COT)端子制御は初期設定となり、 isPowerDown()は真となる。

bool isPowerDown (void)

デバイスが再起動したか、バックアップ電源喪失を経験したなら真を返す。 現在時刻は信用できない。 あらたな時刻を再設定するまで真に留まる。

デバイス設定

bool isExternalTestMode (void)

テストモードが有効なら真。通常運用では使用しない。

bool isCapacitorSelection (void)

水晶発振子負荷容量設定の選択値を返す。通常運用では使用しない。

uint8_t getRamByte (void)

ユーザー設定RAMバイトの設定値を返却する。保持できるのは1バイトだけである。

XRTC_PCF85063A& setExternalTestMode (const bool t_enable)

テストモードの有効/無効/で設定する。実行は遅延。メソッドチェーンが後続できる。 通常運用では使用しない。

XRTC_PCF85063A& setCapacitorSelection (const bool t_enable)

水晶発振子負荷容量12.5pf/7pfの切替を/で設定する。実行は遅延。メソッドチェーンが後続できる。 通常運用では使用しない。

"Duino" ボードでは通常7pf水晶発信子が搭載されているので既定値でよい。

XRTC_PCF85063A& setRamByte (const uint8_t t_ram_byte)

ユーザー設定RAMバイトを0255の範囲で設定する。実行は遅延。メソッドチェーンが後続できる。

使用は任意。保存期間はバックアップキャパシタ次第。 デバイス再起動で0初期化される。 1バイトしか保持できないので用途は限られるだろう。

NIMEM機能を使うほうがより大容量を保持できてかつ非破壊検査が出来る。

時刻精度校正

bool isCorrectionOffsetMode (void)

精度校正モード設定の選択値を真理値で返す。

bool isCorrectionInterruptEnable (void)

精度校正が有効である時、補正パルスの割込端子出力が設定されているならば真。通常運用では使用しない。

uint8_t getCorrectionOffset (void)

精度校正の現在の補正値を返却する。

XRTC_PCF85063A& setCorrectionOffsetMode (const bool t_enable)

精度校正モードの1/0の別を/で設定する。実行は遅延。メソッドチェーンが後続できる。

校正モード0の場合、2時間毎(時桁が偶数の時)起点で指定数の 1/32768秒×分 を増やすか減らす。 つまり調整可能精度は ±4.34 ppm 粒度。

例えば精度校正値が-3だと、2時間に付き 1/32768秒 が 1分間隔で 3回減らされる。

校正モード1の場合、4分毎(分桁が4の倍数の時)起点で指定数の 1/32768秒×秒 を増やすか減らす。 つまり調整可能精度は ±4.069 ppm 粒度。

例えば精度校正値が-3だと、4分に付き 1/32768秒 が 1秒間隔で 3回減らされる。

精度校正は時刻刻みに対して行われるが、周波数出力端子の出力周波数には影響しない。

XRTC_PCF85063A& setCorrectionInterruptEnable (const bool t_enable)

精度校正モードで補正クロックが挿入/除去されるとき、 割込端子を活動させるかを/で設定する。実行は遅延。メソッドチェーンが後続できる。

XRTC_PCF85063A& setCorrectionOffset (const uint8_t t_offset)

精度校正値を-64+63の範囲で設定する。実行は遅延。メソッドチェーンが後続できる。 更新反映は次回校正時刻から有効。

時刻制御

時刻管理には既定の 24時間表現モードと、12時間表現モードとがある。 両者の切替は透過ではないので時刻の再設定が必要になる。

PCF85063Aの年管理は2桁だがセンチュリービットはサポートされていない。 このため年が00の場合、常に閏日(2月29日)が存在する。 しかし曜日更新はそれと別に機能するからソフトウェアで閏日補正を行うことができ、 19002299年範囲の西暦を正しく扱うことが出来る。

なおPCF85063Aにはタイムスタンプ(ストップウォッチ)モードはなく、切り替えもできない。

bool start (void)

計時停止中のデバイスに計時を再開させる。実行は即時。成功すれば真。 成功すればちょうど 0.5秒後に最初の計時(秒の桁の)インクリメントが発生する。 計時タイミング合わせに使用する。

bool stop (void)

計時中のデバイスに計時を停止させる。実行は即時。成功すれば真。 計時タイミング合わせ、あるいはデバイスを使用しない場合の省電力待機に使用する。

bool isRunning (void)

デバイスが計時中なら真を返す。stop()メソッドを実行するまで真に留まる。

bool isStopped (void)

デバイスが計時停止中なら真を返す。start()メソッドを実行するまで真に留まる。

bool is12hourMode (void)

デバイスが12時間表現モードで稼働中なら真を返す。 24時間表現モード(既定値)で稼働中なら偽を返す。

XRTC_PCF85063A& setRunning (const bool t_enable)

計時機能の計時/停止/で設定する。実行は遅延。メソッドチェーンが後続できる。 start() stop()と機能は同じだが即時実行ではない。

XRTC_PCF85063A& set12hourMode (const bool t_enable)

時刻表示モードの12時間制/24時間制の別を/で設定する。実行は遅延。メソッドチェーンが後続できる。

時刻表示モード変更後の時刻保持内容は不正であるから、改めて設定しなければならない。

時刻取得

time_t getEpochNow (void)

現在時刻をtime_t型のUNIX Epochに変換して返却する。 UTC(世界協定時)か否かは使用者定義による。

返却値は現在時刻が西暦20002099年範囲のあいだのみ正しい。

time_t now (void)

getEpochNow()の別名。

bcddatetime_t getBcdDateTimeNow (void)

現在時刻をbcddatetime_t型で(年月日時分秒を)返却する。 20002099範囲で、曜日情報は含まない。

有効範囲外の時刻では曜日が正しくならない。

bcddatetime_t getCenturyDateTimeNow (void)

現在時刻をbcddatetime_t型で(年月日時分秒を)返却する。 19002299範囲で、曜日情報は含まない。

グレゴリウス暦は 400年周期で循環しているため、範囲外の指定は結果的に丸められる。

uint8_t getWeekdays (void)

現在時刻が保持している曜日を返す。範囲は0:日(Sun)6:土(Sat)である。

年の精度が2桁の場合、 保持している年月日を21世紀と見做して曜日を算出し、それと異なるなら 保持している年月日は21世紀ではないと判定できる。 グレゴリウス暦でのその曜日組み合わせは計4通りしか存在しないので、 それらを20〜23世紀の何れかであると見做すことができる。

他の3種はグレゴリウス暦に現れるはずがないので、結果は未知である。

時刻設定

bool adjustEpoch (const time_t t_time)

time_t型で現在時刻を設定する。実行は即時。成功すれば真。 現在時刻には正しい曜日が設定される。

設定可能なのは西暦20002099年範囲のあいだに限られる。
閏日のない年の 2月29日は、3月1日とみなされる。

bool adjustBcdDateTime (const bcddatetime_t t_bcd)

bcddatetime_t型で現在時刻を設定する。実行は即時。成功すれば真。 には19002299範囲が指定でき、 現在時刻には正しい曜日が設定される。

グレゴリウス暦は 400年周期で循環しているため、範囲外の指定は結果的に丸められる。
閏日のない年の 2月29日は、3月1日とみなされる。

bool adjustBcdDate (const bcddate_t t_bcd_date)

bcddate_t型で年月日のみを現在時刻に設定する。実行は即時。成功すれば真。 には19002299範囲が指定でき、 現在時刻には正しい曜日が設定される。

グレゴリウス暦は 400年周期で循環しているため、範囲外の指定は結果的に丸められる。
閏日のない年の 2月29日は、3月1日とみなされる。

bool adjustBcdTime (const bcdtime_t t_bcd_time)

bcdtime_t型で時分秒のみを現在時刻に設定する。実行は即時。成功すれば真。

bool adjustMjd (const date_t t_mjd)

date_t型の MJD(修正ユリウス通日)で年月日のみを現在時刻に設定する。実行は即時。成功すれば真。 には19002299範囲が指定でき、 現在時刻には正しい曜日が設定される。

グレゴリウス暦は 400年周期で循環しているため、範囲外の指定は結果的に丸められる。
閏日のない年の 2月29日は、3月1日とみなされる。

bool adjust (const bcddatetime_t t_bcd)

adjustBcdDateTime()の別名。bcddatetime_t型を渡す。

bool adjust (const time_t t_time)

adjustEpoch()の別名。time_t型を渡す。

アラーム制御

アラームには の5つの比較要素が有り、その論理和を取る。 複数の比較を有効にすると、その全てが真とならなければアラーム動作は発動しない。

アラーム動作自体は単発ストローブであり、発動フラグをクリアしなければ 次の比較条件を満たした時刻が訪れても、アラーム動作は発動しない。

アラーム発動中は割込端子がLOWに引かれたままとなるので、これをクリアしなければ他の割込もまた通知されない。

struct XRTC_ALARM_SETTINGS

アラーム比較条件を格納する構造体定義。 ひとつの曜日と、5つの比較フラグを保持している。

XRTC_ALARM_SETTINGS 説明
.WEEKDAYS 3bit 曜日指定 0-7
.SECOND bool 真で秒比較有効
.MINUTE bool 真で分比較有効
.HOUR bool 真で時比較有効
.DAY bool 真で日比較有効
.WEEKDAY bool 真で曜日比較有効

bool isAlarm (void)

アラームが発動したなら真を返す。 新たなアラームを設定するか、クリアするまで真に留まる。

これがクリアされなければ発動中のアラーム割込端子制御LOWは取り下げられない。

bool isAlarmInterruptEnable (void)

アラーム割込が有効なら真を返す。

bool activeAlarm (const bool t_enable)

アラームの有効/無効/で設定する。実行は即時。成功すれば真。 アラームを有効化すると、アラーム割込もまた有効化される。 アラームを無効化すると、アラーム割込もまた無効化される。

bool clearAlarmFlag (void)

現在発動中のアラームをクリアする。実行は即時。成功すれば真。 発動したアラームをクリアしても、アラーム割込は無効化されない。

XRTC_PCF85063A& setAlarmSettings (const bcdtime_t t_bcd, XRTC_ALARM_SETTINGS t_enable_flags)

アラーム比較条件を設定する。実行は遅延。メソッドチェーンを後続できる。 引数にはひとつのbcdtime_t型の時分秒と、 一組のXRTC_ALARM_SETTINGS構造体を与える。

bcdtime_t getAlarmTime (void)

現在のアラーム比較時分秒をbcdtime_t型で返却する。

XRTC_ALARM_SETTINGS getAlarmSettings (void)

現在のアラーム比較設定をXRTC_ALARM_SETTINGS型で返却する。

タイマー制御

タイマー動作には周期動作と単発動作がある。 周期動作には更にふたつの組込固定長周期タイマーがある。

bool isTimer (void)

何れかのタイマーが発動したなら真を返す。 新たなタイマーを設定するか、クリアするまで真に留まる。

これがクリアされなければ単発動作で発動中のタイマー割込他院制御LOWは取り下げられない。

周期動作では初回発動時に真となり、以後真に留まる。 これをクリアすると、以後の周期発動と周期割込は停止する。

bool isTimerInterruptEnable (void)

タイマー割込が有効なら真を返す。

bool isTimerPeriod (void)

任意タイマーが周期動作設定なら真を返す。 任意タイマーが単発動作設定なら偽を返す。

XRTC_PCF85063A& setTimerEnable (const bool t_enable)

タイマー動作の有効/無効/で設定する。実行は遅延。メソッドチェーンが後続できる。 通常これは他のタイマー操作内で上書きされるため、使用する機会はない。

XRTC_PCF85063A& setTimerInterruptEnable (const bool t_enable)

タイマー割込動作の有効/無効/で設定する。実行は遅延。メソッドチェーンが後続できる。 通常これは他のタイマー操作内で上書きされるため、使用する機会はない。

bool deactiveTimer (void)

タイマー動作と割込を無効化する。実行は即時。成功すれば真。 現在のタイマー発動フラグはクリアされる。 activeTimer(false, false)に同じ。

bool activeTimer (const bool t_enable = true)

タイマー動作と割込の有効/無効/で設定する。実行は即時。成功すれば真。 現在のタイマー発動フラグはクリアされる。 activeTimer(void)activeTimer(true)に同じ。 activeTimer(false)activeTimer(false, false)に同じ。

bool activeTimer (const bool t_enable, const bool t_interrupt)

タイマー動作とタイマー割込の個別の有効/無効/で設定する。実行は即時。成功すれば真。 現在のタイマー発動フラグはクリアされる。 activeTimer(false, false)deactiveTime(void)に同じ。 activeTimer(true, true)activeTimer(void)に同じ。

activeTimer(false, true)は設定可能だが意味をなさない。

activeTimer(true, false)はタイマー発動フラグ更新のみ許可され、割込端子は駆動しない。 タイマーが発動したか否かはisTimer()で調べることができる。

bool clearTimerFlag (void)

現在のタイマー発動フラグをクリアして割込端子制御を取り下げる。実行は即時。成功すれば真。

周期動作タイマー設定

周期動作タイマーは有効である間、指定の周期長間隔で単発パルスストローブを繰り返す。 タイマー発動フラグは初回発動時に真となり、以後クリアされるまで真を維持する。 これをclearTimerFlag()でクリアすると、周期タイマー動作は停止される。

任意設定タイマーの他に60秒および30秒の固定長周期タイマーが別にあり、 任意動作の周期タイマーと同時に使用できる。 ただしタイマー発動フラグはひとつなので、どのタイマーが発動したかを知ることは出来ない。

bool isMinuteInterruptEnable (void)

組込60秒周期タイマーが有効なら真。

bool isHarfMinuteInterruptEnable (void)

組込30秒周期タイマーが有効なら真。

XRTC_PCF85063A& setMinuteInterruptEnable (const bool t_enable)

組込60秒周期長タイマーの有効/無効/で設定する。実行は遅延。メソッドチェーンが後続できる。 この組込周期タイマーは秒桁が00の時に単発割込を発生させる。

組込60秒周期タイマーは、任意設定周期タイマーと同時に使用できる。

XRTC_PCF85063A& setHarfMinuteInterruptEnable (const bool t_enable)

組込30秒周期長タイマーの有効/無効/で設定する。実行は遅延。メソッドチェーンが後続できる。 この組込周期タイマーは秒桁が0030の時に単発割込を発生させる。 従って組込60秒周期長タイマーの効果は隠蔽される。

組込30秒周期長タイマーは、任意設定周期タイマーと同時に使用できる。

bool startPeriodTimer (const uint16_t t_seconds)

任意設定周期長タイマーに、現時刻を起点とする周期長をt_secondsで与えて有効化する。実行は即時。成功すれば真。 タイマー発動フラグはクリアされる。 指定可能な最低値は1秒。 255秒までは秒刻みで指定可能。 それ以上は60秒刻みに丸められ、15300秒までが指定できる。 0を指定するとこのタイマー動作と割込は無効化される。

単発動作タイマー設定

単発動作タイマー割込は、その発動中は割込端子をLOWに引く。 それはclearTimerFlag()でクリアするまで取り下げられない。 タイマー発動クリアは周期動作も停止するので、単発動作と周期動作は両立しない。

struct XRTC_TIMER_SETTINGS

activateTimerを実行する際の詳細設定構造体。 通常これを使用する必要はない。

XRTC_TIMER_SETTINGS 説明
.Value uint8_t カウントダウン設定値0255
.InterruptMode bool 真で周期動作、偽で単発動作
.InterruptEnable bool 真で割込端子制御許可
.Enable bool 真でタイマー動作有効
.ClockFrequency 2bit カウントダウン周波数を以下で指定
0 4.096kHz
1 64Hz
2 1Hz
3 1/60Hz

XRTC_TIMER_SETTINGS getTimerValues (void)

任意設定タイマーの現在の詳細情報をXRTC_TIMER_SETTINGS構造体に返却する。

bool activateTimer (const XRTC_TIMER_SETTINGS t_settings)

任意設定タイマーに詳細かつ完全な動作設定をXRTC_TIMER_SETTINGSで与える。実行は即時。成功すれば真。 タイマー発動フラグはクリアされる。 通常これを使用する必要はない。

bool startCountdownTimer (const uint16_t t_seconds)

任意設定単発動作タイマーに、現時刻を起点とするカウントダウン時間をt_secondsで与えて有効化する。実行は即時。成功すれば真。 タイマー発動フラグはクリアされる。 指定可能な最低値は1秒。 255秒までは秒刻みで指定可能。 それ以上は60秒刻みに丸められ、15300秒までが指定できる。 0を指定するとこのタイマー動作と割込は無効化される。

任意設定単発動作タイマーが発動するとタイマー発動フラグが真になり、 それがクリアされるまで割込端子もLOWを維持する。

周波数出力端子制御

周波数出力端子(COT)は既定で 32.768kHz の矩形波(push-pull)を常時出力している。 この信号は "Duino" ボードのPIN_PF0にジャンパー設定で入力することができ、 RTC周辺機能に供給、または主制御クロックの自動校正、 あるいは直接的に主制御クロックとして使用することが出来る。

出力周波数は、1Hz出力を除いて精度校正の影響を受けない。

bool changeClockOutFrequency (const uint8_t t_clockfreq)

周波数出力端子(COT)の出力周波数を、以下のt_clockfreqで指定する。実行は即時。成功すれば真。

t_clockfreq 出力周波数 矩形波Duty比 計時停止時
0 32.768kHz 60:40〜40:60 不定
1 16.384kHz 50:50 不定
2 8.192kHz 50:50 不定
3 4.096kHz 50:50 LOW固定
4 2.048kHz 50:50 LOW固定
5 1.024kHz 50:50 LOW固定
6 1Hz 50:50 LOW固定
7 停止 - LOW固定

LINKS

multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)

Clone this wiki locally