< 資料 >
Download: Rtc8564AttachInterrupt.zip
Sketch: Rtc8564AttachInterruptSleep ▼
/*
* sketch name : Rtc8564AttachInterruptSleep
* summary : RTC8564で定周期タイマー割り込み & スリープ
* releases : 2011/3/15
*/
#include <Wire.h>
#include <Rtc8564AttachInterrupt.h>
#include <Sleep.h>
/* RTCタイマ開始日付時刻 */
#define RTC_SEC 0x00 // 秒
#define RTC_MIN 0x18 // 分
#define RTC_HOUR 0x23 // 時
#define RTC_DAY 0x15 // 日
#define RTC_WEEK 0x02 // 曜日(00:日 〜 06:土)
#define RTC_MON 0x03 // 月
#define RTC_YEAR 0x11 // 西暦
byte date_time[7] = {
RTC_SEC
,RTC_MIN
,RTC_HOUR
,RTC_DAY
,RTC_WEEK
,RTC_MON
,RTC_YEAR
};
/* 電源リセット確認フラグ */
boolean init_flg = false;
/* 計測間隔(RTC割り込み間隔) */
#define RTC_INTERRUPT_TERM 10
/* 外部割り込みピン */
#define RTC_INTERRUPT_PIN 2
/* 定周期タイマ間隔設定単位 0:秒/1:分 */
#define RTC_INTERRUPT_MODE 0
void setup() {
Serial.begin(9600);
// 日付時刻初期化
Rtc.initDatetime(date_time);
// RTC開始
Rtc.begin();
// 定周期割り込みタイマ継続確認
if (!Rtc.isInterrupt()) {
// 割り込み設定
Rtc.syncInterrupt(RTC_INTERRUPT_MODE, RTC_INTERRUPT_TERM);
}
// 割り込み設定
pinMode(RTC_INTERRUPT_PIN, INPUT);
digitalWrite(RTC_INTERRUPT_PIN, HIGH);
}
void loop() {
// 初期化(電源OFF=>ON)すぐ後は計測しない
if (init_flg) ReadRTC();
init_flg = true;
// スリープ開始
SleepClass::powerDownAndWakeupExternalEvent(0);
}
void ReadRTC()
{
Rtc.available();
Serial.print(0x2000 + Rtc.years(), HEX);
Serial.print("/");
Serial.print(Rtc.months(), HEX);
Serial.print("/");
Serial.print(Rtc.days(), HEX);
Serial.print(" ");
Serial.print(Rtc.hours(), HEX);
Serial.print(":");
Serial.print(Rtc.minutes(), HEX);
Serial.print(":");
Serial.print(Rtc.seconds(), HEX);
Serial.print(" ");
Serial.println((int)Rtc.weekdays());
Serial.println();
}
Library Code:
Rtc8564AttachInterrupt.h ▼
#ifndef Rtc8564AttachInterrupt_h
#define Rtc8564AttachInterrupt_h
#include <inttypes.h>
class Rtc8564AttachInterrupt
{
private:
void init(void);
uint8_t _seconds;
uint8_t _minutes;
uint8_t _hours;
uint8_t _days;
uint8_t _weekdays;
uint8_t _months;
uint8_t _years;
bool _century;
public:
enum {
BCD = 0,
Decimal = 1,
};
Rtc8564AttachInterrupt();
void begin(void);
void beginWithoutIsValid(void);
void initDatetime(uint8_t date_time[]);
bool isInitDatetime(void);
void sync(uint8_t date_time[],uint8_t size = 7);
void syncInterrupt(unsigned int mode, unsigned long term);
bool available(void);
bool isvalid(void);
bool isInterrupt(void);
uint8_t seconds(uint8_t format = Rtc8564AttachInterrupt::BCD) const;
uint8_t minutes(uint8_t format = Rtc8564AttachInterrupt::BCD) const;
uint8_t hours(uint8_t format = Rtc8564AttachInterrupt::BCD) const;
uint8_t days(uint8_t format = Rtc8564AttachInterrupt::BCD) const;
uint8_t weekdays() const;
uint8_t months(uint8_t format = Rtc8564AttachInterrupt::BCD) const;
uint8_t years(uint8_t format = Rtc8564AttachInterrupt::BCD) const;
bool century() const;
};
extern Rtc8564AttachInterrupt Rtc;
#endif
Rtc8564AttachInterrupt.cpp ▼
extern "C" {
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
}
#include <WConstants.h>
#include <Wire.h>
#include "Rtc8564AttachInterrupt.h"
#define RTC8564_SLAVE_ADRS (0xA2 >> 1)
#define BCD2Decimal(x) (((x>>4)*10)+(x&0xf))
// Constructors ////////////////////////////////////////////////////////////////
Rtc8564AttachInterrupt::Rtc8564AttachInterrupt()
: _seconds(0), _minutes(0), _hours(0), _days(0), _weekdays(0), _months(0), _years(0), _century(0)
{
}
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();
}
// Public Methods //////////////////////////////////////////////////////////////
void Rtc8564AttachInterrupt::begin(void)
{
Wire.begin();
if(isvalid() == false) {
// RTC初期設定
init();
// 日付時刻プロパティがセットされていたら、その時刻をセット
if (isInitDatetime()) {
byte date_time[7];
date_time[0] = _seconds;
date_time[1] = _minutes;
date_time[2] = _hours;
date_time[3] = _days;
date_time[4] = _weekdays;
date_time[5] = _months;
date_time[6] = _years;
sync(date_time);
}
}
}
// RTC日付時刻継続確認なしの日付時刻初期化
void Rtc8564AttachInterrupt::beginWithoutIsValid(void)
{
Wire.begin();
// RTC初期設定
init();
// 日付時刻プロパティがセットされていたら、その時刻をセット
if (isInitDatetime()) {
byte date_time[7];
date_time[0] = _seconds;
date_time[1] = _minutes;
date_time[2] = _hours;
date_time[3] = _days;
date_time[4] = _weekdays;
date_time[5] = _months;
date_time[6] = _years;
sync(date_time);
}
}
// 日付時刻のプロパティセット
void Rtc8564AttachInterrupt::initDatetime(uint8_t date_time[])
{
_seconds = (date_time[0]) ? date_time[0] : 0x00;
_minutes = (date_time[1]) ? date_time[1] : 0x00;
_hours = (date_time[2]) ? date_time[2] : 0x09;
_days = (date_time[3]) ? date_time[3] : 0x01;
_weekdays = (date_time[4]) ? date_time[4] : 0x01;
_months = (date_time[5]) ? date_time[5] : 0x01;
_years = (date_time[6]) ? date_time[6] : 0x01;
}
// 日付時刻プロパティセット確認
bool Rtc8564AttachInterrupt::isInitDatetime(void)
{
bool flg = false;
if ((_seconds & 0x00) != 0x00) flg = true;
if ((_minutes & 0x00) != 0x00) flg = true;
if ((_hours & 0x09) != 0x09) flg = true;
if ((_days & 0x01) != 0x01) flg = true;
if ((_weekdays & 0x01) != 0x01) flg = true;
if ((_months & 0x01) != 0x01) flg = true;
if ((_years & 0x01) != 0x01) flg = true;
return flg;
}
// 日付時刻の初期化
void Rtc8564AttachInterrupt::sync(uint8_t date_time[],uint8_t size)
{
// 時計機能ストップ
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.send(0x00); // Control1 アドレス
Wire.send(0x20); // 00 Control 1, STOP=1
Wire.endTransmission();
// 日付時刻設定
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.send(0x02); // Seconds アドレス
Wire.send(date_time, size); // 日付時刻セット
Wire.endTransmission();
// 時計機能スタート
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.send(0x00); // Control1 アドレス
Wire.send(0x00); // 00 Control 1, STOP=0
Wire.endTransmission();
}
// 定周期割り込みタイマの初期化
// 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();
}
bool Rtc8564AttachInterrupt::available(void)
{
uint8_t buff[7];
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.send(0x02); // write reg addr 02
Wire.endTransmission();
Wire.requestFrom(RTC8564_SLAVE_ADRS, 7);
for(int i=0; i<7; i++){
if(Wire.available()){
buff[i] = Wire.receive();
}
}
_seconds = buff[0] & 0x7f;
_minutes = buff[1] & 0x7f;
_hours = buff[2] & 0x3f;
_days = buff[3] & 0x3f;
_weekdays = buff[4] & 0x07;
_months = buff[5] & 0x1f;
_years = buff[6];
_century = (buff[5] & 0x80) ? 1 : 0;
return (buff[0] & 0x80 ? false : true);
}
bool Rtc8564AttachInterrupt::isvalid(void)
{
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.send(0x02); // write reg addr 02
Wire.endTransmission();
Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
if(Wire.available()){
uint8_t buff = Wire.receive();
return (buff & 0x80 ? false : true);
}
return false;
}
// 定周期割り込みタイマの継続確認
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;
}
uint8_t Rtc8564AttachInterrupt::seconds(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_seconds);
return _seconds;
}
uint8_t Rtc8564AttachInterrupt::minutes(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_minutes);
return _minutes;
}
uint8_t Rtc8564AttachInterrupt::hours(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_hours);
return _hours;
}
uint8_t Rtc8564AttachInterrupt::days(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_days);
return _days;
}
uint8_t Rtc8564AttachInterrupt::weekdays() const {
return _weekdays;
}
uint8_t Rtc8564AttachInterrupt::months(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_months);
return _months;
}
uint8_t Rtc8564AttachInterrupt::years(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_years);
return _years;
}
bool Rtc8564AttachInterrupt::century() const {
return _century;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
Rtc8564AttachInterrupt Rtc = Rtc8564AttachInterrupt();
|
初期設定をする前は 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 コメント:
コメントを投稿