RTC-8564NBでうるう年の実験。
前に作った、タイマーなんですが、
https://ameblo.jp/fc2miha/entry-12833772945.html
やっぱ、50日に一回具合悪くなるので、リアルタイムクロック化して安定させるべく、
以前購入していた、秋月のRTC-8564NBの動作確認テストの記事です。
■回路

■テスト
ちゃんと明日になるかな?
ver0.1
2021 4/17 23:59:55
2021 4/17 23:59:56
2021 4/17 23:59:57
2021 4/17 23:59:58
2021 4/17 23:59:59
2021 4/18 0:00:00 ← ちゃんと明日になった。
2021 4/18 0:00:01
2021 4/18 0:00:02
2021 4/18 0:00:03
2021 4/18 0:00:04
2021 4/18 0:00:05
■うるう年の確認
国立天文台の定義によると
「グレゴリオ暦法では、うるう年を次のように決めています。
(1)西暦年号が4で割り切れる年をうるう年とする。
(2)(1)の例外として、西暦年号が100で割り切れて 400で割り切れない年は平年とする。」
さらに
「例えば、西暦2004年、2008年、2012年……は(1)に当てはまりますので、
うるう年になります。また、西暦2100年、2200年、2300年は(2)に当てはまりますので、
平年となります。さらに、西暦2000年、2400年は、100でも割り切れますが400でも
割り切れてしまいますので、(2)には当てはまらず、(1)のとおりにうるう年となります。」
つまり、直近だと
2020年はうるう年、2024年もうるう年
2000年は100でも400でも割り切れるのでうるう年
かなり未来の2100年は4で割り切れるけど100でも割り切れるのでうるう年じゃない
ってなりますけど。
さて、試してみましょう。
今年。2021年2月
ver0.1
2021 2/28 23:59:55
2021 2/28 23:59:56
2021 2/28 23:59:57
2021 2/28 23:59:58
2021 2/28 23:59:59 ←うるう年でない。
2021 3/ 1 0:00:00
2021 3/ 1 0:00:01
2021 3/ 1 0:00:02
2020年2月
ver0.1
2020 2/28 23:59:55
2020 2/28 23:59:56
2020 2/28 23:59:57
2020 2/28 23:59:58
2020 2/28 23:59:59
2020 2/29 0:00:00 ←うるう年。
2020 2/29 0:00:01
2020 2/29 0:00:02
2020 2/29 0:00:03
2020 2/29 0:00:04
2024年2月
ver0.1
2024 2/28 23:59:55
2024 2/28 23:59:56
2024 2/28 23:59:57
2024 2/28 23:59:58
2024 2/28 23:59:59
2024 2/29 0:00:00 ←うるう年。
2024 2/29 0:00:01
2024 2/29 0:00:02
2024 2/29 0:00:03
2024 2/29 0:00:04
2000年2月
ver0.1
2000 2/28 23:59:55
2000 2/28 23:59:56
2000 2/28 23:59:57
2000 2/28 23:59:58
2000 2/28 23:59:59
2000 2/29 0:00:00 ←うるう年。
2000 2/29 0:00:01
2000 2/29 0:00:02
2000 2/29 0:00:03
2000 2/29 0:00:04
2000 2/29 0:00:05
2100年2月
ver0.1
2000 2/28 23:59:55 ←年がばぐってるね。
2000 2/28 23:59:56
2000 2/28 23:59:57
2000 2/28 23:59:58
2000 2/28 23:59:59
2000 2/29 0:00:00 ←うるう年になっているけど。不正解!!
2000 2/29 0:00:01
2000 2/29 0:00:02
2000 2/29 0:00:03
これって、2099年の次は2000年に戻るっていうやつだね。
まさこれは2000年問題!!
懐かしい。
そうそう。1999年の年末は世間が浮かれている中
我々はデータセンターで年越ししたものです。
やっぱ、2100年問題とかなるのかね?
いちおう、試してみよう。2100年問題。
2099年年末
ver0.1
2099 12/31 23:59:55
2099 12/31 23:59:56
2099 12/31 23:59:57
2099 12/31 23:59:58
2099 12/31 23:59:59
2000 1/ 1 0:00:00 ←ちゃんと?2000年に戻っている。
2000 1/ 1 0:00:01
2000 1/ 1 0:00:02
2000 1/ 1 0:00:03
このモジュール使う人は2100年問題に気をつけましょう。
原因は年を二桁だけで管理しているためです。
0~99までの範囲をふたつに分けて
0~50までは2100を加算
51~99までは2000を加算とすれば問題なくなるのでいちおう、
2099年まではプログラムを更新して使えるはずですけど
2100年は「うるう年じゃない」の扱い出来るようにしなきゃですね。
※いちおうこのモジュール、センチュリービットなるビットを立てて
2000年以降を識別できるようですが、2100年以降は識別できるかな?
ここから先は未来のエンジニアにお任せですね。
■プログラム
ここらへんhttp://www.straycats.net/wifky/wifky.cgi?p=Arduino+%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%AF%E3%83%AD%E3%83%83%E3%82%AF%E3%80%80RTC-8564NB
を参考にさせてもらいましたが、
コンパイルエラーになるでの、色々変更しました。
ライブラリーもあっちこっち色々あるみたいであれなんで、
一本のプログラムとして合体しちゃいましたので、
ライブラリーの方言?は気にしなくて良くなるはずです。
#include <Arduino.h>
#include <Wire.h>
#define BCD2Decimal(x) (((x>>4)*10)+(x&0xf))
#define Decimal2BCD(x) (((x/10)<<4)+(x%10))
extern "C" {
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
}
#include <inttypes.h>
class RTC8564
{
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,
};
RTC8564();
void begin(void);
void sync(uint8_t date_time[],uint8_t size = 7);
bool available(void);
bool isvalid(void);
uint8_t seconds(uint8_t format = RTC8564::BCD) const;
uint8_t minutes(uint8_t format = RTC8564::BCD) const;
uint8_t hours(uint8_t format = RTC8564::BCD) const;
uint8_t days(uint8_t format = RTC8564::BCD) const;
uint8_t weekdays() const;
uint8_t months(uint8_t format = RTC8564::BCD) const;
uint8_t years(uint8_t format = RTC8564::BCD) const;
bool century() const;
};
#define RTC8564_SLAVE_ADRS (0xA2 >> 1)
#define BCD2Decimal(x) (((x>>4)*10)+(x&0xf))
RTC8564::RTC8564()
: _seconds(0), _minutes(0), _hours(0), _days(0), _weekdays(0), _months(0), _years(0), _century(0)
{
}
void RTC8564::init(void)
{
delay(1000);
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.write(0x00); // write reg addr 00
Wire.write(0x20); // 00 Control 1, STOP=1
Wire.write(0x00); // 01 Control 2
Wire.write(0x00); // 02 Seconds
Wire.write(0x00); // 03 Minutes
Wire.write(0x09); // 04 Hours
Wire.write(0x01); // 05 Days
Wire.write(0x01); // 06 Weekdays
Wire.write(0x01); // 07 Months
Wire.write(0x01); // 08 Years
Wire.write(0x00); // 09 Minutes Alarm
Wire.write(0x00); // 0A Hours Alarm
Wire.write(0x00); // 0B Days Alarm
Wire.write(0x00); // 0C Weekdays Alarm
Wire.write(0x00); // 0D CLKOUT
Wire.write(0x00); // 0E Timer control
Wire.write(0x00); // 0F Timer
Wire.write(0x00); // 00 Control 1, STOP=0
Wire.endTransmission();
}
// Public Methods //////////////////////////////////////////////////////////////
void RTC8564::begin(void)
{
Wire.begin();
if(isvalid() == false)
init();
}
void RTC8564::sync(uint8_t date_time[],uint8_t size)
{
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.write(0x00); // write reg addr 00
Wire.write(0x20); // 00 Control 1, STOP=1
Wire.endTransmission();
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.write(0x02); // write reg addr 02
Wire.write(date_time, size);
Wire.endTransmission();
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.write(0x00); // write reg addr 00
Wire.write(0x00); // 00 Control 1, STOP=0
Wire.endTransmission();
}
bool RTC8564::available(void)
{
uint8_t buff[7];
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.write(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.read();
}
}
_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 RTC8564::isvalid(void)
{
Wire.beginTransmission(RTC8564_SLAVE_ADRS);
Wire.write(0x02); // write reg addr 02
Wire.endTransmission();
Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
if(Wire.available()){
uint8_t buff = Wire.read();
return (buff & 0x80 ? false : true);
}
return false;
}
uint8_t RTC8564::seconds(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_seconds);
return _seconds;
}
uint8_t RTC8564::minutes(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_minutes);
return _minutes;
}
uint8_t RTC8564::hours(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_hours);
return _hours;
}
uint8_t RTC8564::days(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_days);
return _days;
}
uint8_t RTC8564::weekdays() const {
return _weekdays;
}
uint8_t RTC8564::months(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_months);
return _months;
}
uint8_t RTC8564::years(uint8_t format) const {
if(format == Decimal) return BCD2Decimal(_years);
return _years;
}
bool RTC8564::century() const {
return _century;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
RTC8564 Rtc = RTC8564();
int yearDecimal2BCD(int yyyy){
int nDec = yyyy -1900;
int nDecHigh = nDec / 100;
int nDecLow = nDec % 100;
int bcdHigh = Decimal2BCD(nDecHigh);
int bcdLow = Decimal2BCD(nDecLow);
int nBCD = bcdHigh * 256 + bcdLow;
return nBCD;
}
void setup()
{
Serial.begin(9600);
Serial.println("ver0.1");
Rtc.begin();
//setDateTime(2021, 4, 17, 6, 23, 59, 55);
//setDateTime(2021, 2, 28, 0, 23, 59, 55);
//setDateTime(2020, 2, 28, 0, 23, 59, 55);
//setDateTime(2024, 2, 28, 0, 23, 59, 55);
//setDateTime(2000, 2, 28, 0, 23, 59, 55);
//setDateTime(2100, 2, 28, 0, 23, 59, 55);
setDateTime(2099, 12, 31, 0, 23, 59, 55);
}
void loop()
{
char buf[256];
Rtc.available(); //取得準備
sprintf(buf, " %04d %2d/%2d %2d:%02d:%02d",
Rtc.years(RTC8564::Decimal)+2000,
Rtc.months(RTC8564::Decimal),
Rtc.days(RTC8564::Decimal),
Rtc.hours(RTC8564::Decimal),
Rtc.minutes(RTC8564::Decimal),
Rtc.seconds(RTC8564::Decimal) );
Serial.println(buf);
delay(1000);
}
void setDateTime(int yyyy, int mm, int dd, int you, int hour, int min, int sec)
{
byte date_and_time[7];
date_and_time[0] = Decimal2BCD(sec); // 59秒
date_and_time[1] = Decimal2BCD(min); // 59分
date_and_time[2] = Decimal2BCD(hour); // 24時
date_and_time[3] = Decimal2BCD(dd); // 31日
date_and_time[4] = you; // 曜日 日=0,月=1,火=2,水=3,木=4,金=5,土=6,
date_and_time[5] = Decimal2BCD(mm); // 12月
// date_and_time[6] = 0x116; //Decimal2BCD(yyyy-2000); // 年
date_and_time[6] = yearDecimal2BCD( yyyy); //年
Rtc.sync(date_and_time);
}