#---------------------------------------------------------------------------
# EPSON TOYOCOM RTC-8564 テストプログラム
# based on: http://iizukakuromaguro.sakura.ne.jp/365_rtc8564/365_rtc8564.html
#---------------------------------------------------------------------------
class RTC8564
REG_ADDR_CONTROL1= 0x00
REG_ADDR_CONTROL2= 0x01
REG_ADDR_SECONDS= 0x02
REG_ADDR_MINUTES= 0x03
REG_ADDR_HOURS= 0x04
REG_ADDR_DAYS= 0x05
REG_ADDR_WEEKDAYS= 0x06
REG_ADDR_MONTHS = 0x07
REG_ADDR_YEARS= 0x08
REG_ADDR_MINUTE_ALARM= 0x09
REG_ADDR_HOUR_ALARM= 0x0A
REG_ADDR_DAY_ALARM = 0x0B
REG_ADDR_WEEKDAY_ALARM= 0x0C
REG_ADDR_CLOCKOUT_FREQ =0x0D
REG_ADDR_TIMER_CONTROL= 0x0E
REG_ADDR_TIMER = 0x0F
STOP_BIT = 5 # CONTROL1
INTERRUPT_PERIODIC= 4 # CONTROL2
ALARM_FLAG = 3 # CONTROL2
TIMER_FLAG = 2 # CONTROL2
ALARM_INTERRUPT_ENABLE = 1 # CONTROL2
TIMER_INTERRUPT_ENABLE = 0 # CONTROL2
VOLTAGE_LOW = 7 # SECONDS
ALARM_ENABLE = 7 # MIN ALARAM - WEEKDAY ALARAM
CLOCK_OUT_ENABLE = 7 # CLKOUT
CLOCK_OUT_FREQ_32768Hz= 0x00 # CLKOUT
CLOCK_OUT_FREQ_1024Hz= 0x01 # CLKOUT
CLOCK_OUT_FREQ_32Hz = 0x02 # CLKOUT
CLOCK_OUT_FREQ_1Hz = 0x03 # CLKOUT
TIMER_ENABLE = 7 # TIMER CONTROL
TIMER_CLOCK_4096Hz = 0 # TIMER CONTROL
TIMER_CLOCK_64Hz = 1 # TIMER CONTROL
TIMER_CLOCK_1Hz = 2 # TIMER CONTROL
TIMER_CLOCK_1_60Hz = 3 # TIMER CONTROL
MINUTES_MASK = 0b01111111
HOURS_MASK = 0b00111111
DAYS_MASK = 0b00111111
WEEKDAYS_MASK = 0b00000111
MONTHS_MASK = 0b00011111
RTC8564_ADDR = 0x51 # I2C 7bit address
def initialize
@tm = {
"year" => nil,
"month" => nil,
"day" => nil,
"hour" => nil,
"min" => nil,
"sec" => nil,
"weekday" => nil
}
@wire = Wire.new(0x0, Wire::DutyCycle_2)
end
#---------------------------------------------------------------------------
# DECIMAL -> BCD 変換
#---------------------------------------------------------------------------
def rtc8564_dec2bcd( data )
return ((( data / 10) << 4) + (data % 10))
end
#---------------------------------------------------------------------------
# BCD -> DECIMAL 変換
#---------------------------------------------------------------------------
def rtc8564_bcd2dec( data )
return ((( data >> 4) * 10) + (data % 16))
end
#---------------------------------------------------------------------------
# CLKOUT端子の周波数設定
#
# 引数:
# CLOCK_OUT_FREQ_32768Hz : 32.768 kHz
# CLOCK_OUT_FREQ_1024Hz : 1.024 kHz
# CLOCK_OUT_FREQ_32Hz : 32 Hz
# CLOCK_OUT_FREQ_1Hz : 1 Hz
#---------------------------------------------------------------------------
def rtc8564_clock_out_freq( freq )
rtc8564_write_byte( REG_ADDR_CLOCKOUT_FREQ, freq )
end
#----- CLKOUT端子には出力しない(消費電力減) ---------------------
def rtc8564_clock_out_enable
rtc8564_set_bit( REG_ADDR_CLOCKOUT_FREQ, CLOCK_OUT_ENABLE )
end
#----- CLKOUT端子に出力する -----------------------------------
def rtc8564_clock_out_disable
rtc8564_clear_bit( REG_ADDR_CLOCKOUT_FREQ, CLOCK_OUT_ENABLE )
end
#---------------------------------------------------------------------------
# 1バイトRTC8564に書き込む
#
# 引数1:RTC8564のレジスターアドレス
# 引数2:レジスターに書き込む値
#---------------------------------------------------------------------------
def rtc8564_write_byte(addr, data)
@wire.beginTransmission(RTC8564_ADDR)
@wire.write(addr)
@wire.write(data)
@wire.endTransmission()
end
#---------------------------------------------------------------------------
# 1バイトRTC8564から読み出す
#
# 戻り値:読み出した値
#---------------------------------------------------------------------------
def rtc8564_read_byte(addr)
@wire.beginTransmission(RTC8564_ADDR)
@wire.write(addr)
@wire.endTransmission
@wire.requestFrom(RTC8564_ADDR, 1)
return @wire.read
end
#---------------------------------------------------------------------------
# RTC8564のレジスターの特定ビットの値を調べる
#
# 戻り値 true:ビットの値が1 false:ビットの値が0
#---------------------------------------------------------------------------
def rtc8564_test_bit(addr, bit_position)
data = rtc8564_read_byte( addr )
data &= (0x01 << bit_position)
if data == 0x00
return false
else
return true
end
end
#---------------------------------------------------------------------------
# RTC8564のレジスターの特定ビットをセットする
#---------------------------------------------------------------------------
def rtc8564_set_bit(addr, bit_position)
data = rtc8564_read_byte( addr )
data |= (0x01 << bit_position)
rtc8564_write_byte( addr, data )
end
#---------------------------------------------------------------------------
# RTC8564のレジスターの特定ビットをクリヤする
#---------------------------------------------------------------------------
def rtc8564_clear_bit(addr, bit_position)
data = rtc8564_read_byte( addr )
data &= ~(0x01 << bit_position)
rtc8564_write_byte( addr, data )
end
#---------------------------------------------------------------------------
# RTC8564の初期化
#
# 日時設定、アラーム無効、CLKOUT出力なし、タイマー無効
#---------------------------------------------------------------------------
def rtc8564_init(year, month, day, hour, minute, second)
rtc8564_write_byte(REG_ADDR_CONTROL1,0x20)
rtc8564_write_byte(REG_ADDR_CONTROL2,0x00)
rtc8564_set_time( year, month, day, hour, minute, second)
rtc8564_alarm_disable
rtc8564_clock_out_disable
rtc8564_write_byte(REG_ADDR_TIMER_CONTROL,0x00)
rtc8564_write_byte(REG_ADDR_TIMER,0x00)
rtc8564_clear_bit( REG_ADDR_CONTROL1, STOP_BIT )
end
#---------------------------------------------------------------------------
# アラーム機能
# ・日時週時刻はそれぞれ個別に設定可能なため
# 毎週月曜の12:00にアラーム発生といった使い方ができる
#---------------------------------------------------------------------------
#------ アラーム発生日の設定 -------------------------------------
def rtc8564_set_alarm_day( day )
rtc8564_write_byte(REG_ADDR_DAY_ALARM, rtc8564_dec2bcd(day))
end
#------ アラーム発生時刻の設定 -----------------------------------
def rtc8564_set_alarm_hour( hour )
rtc8564_write_byte(REG_ADDR_HOUR_ALARM, rtc8564_dec2bcd(hour))
end
#------ アラーム発生分の設定 -------------------------------------
def rtc8564_set_alarm_minute( minute )
rtc8564_write_byte(REG_ADDR_MINUTE_ALARM, rtc8564_dec2bcd(minute))
end
#------ アラーム発生週の設定 -------------------------------------
def rtc8564_set_alarm_weekday( weekday )
rtc8564_write_byte(REG_ADDR_WEEKDAY_ALARM, weekday )
end
#------ アラーム発生時にINT端子をLOWにする -----------------------
def rtc8564_alarm_interrupt_enable
rtc8564_set_bit( REG_ADDR_CONTROL2, ALARM_INTERRUPT_ENABLE )
end
#------ INT端子には出力しない ------------------------------------
def rtc8564_alarm_interrupt_disable
rtc8564_clear_bit( REG_ADDR_CONTROL2, ALARM_INTERRUPT_ENABLE )
rtc8564_alarm_disable
end
#------ アラームを無効にする -------------------------------------
def rtc8564_alarm_disable
rtc8564_set_bit( REG_ADDR_DAY_ALARM, ALARM_ENABLE )
rtc8564_set_bit( REG_ADDR_HOUR_ALARM, ALARM_ENABLE )
rtc8564_set_bit( REG_ADDR_MINUTE_ALARM, ALARM_ENABLE )
rtc8564_set_bit( REG_ADDR_WEEKDAY_ALARM, ALARM_ENABLE )
rtc8564_alarm_clear
end
#------ アラームイベント(アラーム発生フラグ)のクリヤ -------------
def rtc8564_alarm_clear
rtc8564_clear_bit( REG_ADDR_CONTROL2, ALARM_FLAG )
end
#------ アラームが発生したか否かの確認 ---------------------------
# これを使ってアラームイベント発生を検知するためにはloop内で呼び続ける必要がある
# 戻り値
# true:イベント発生
# true:イベントは発生していない
#-----------------------------------------------------------------
def rtc8564_alarm_test
if rtc8564_test_bit(REG_ADDR_CONTROL2, ALARM_FLAG )
return true
else
return false
end
end
#---------------------------------------------------------------------------
# タイマー設定
# ・一定周期でイベントを発生させるために使う
# ・タイマーはダウンカウンターでゼロになるとイベント発生
#---------------------------------------------------------------------------
#----- タイマーの設定 --------------------------------------------
# 2つの引数の組み合わせでイベント発生させる
# 引数1:ダウンカウンタープリセット値
# 引数2:カウントダウンさせるためのクロック速度
#-----------------------------------------------------------------
def rtc8564_timer_set( count, clock )
rtc8564_timer_disable
rtc8564_write_byte(REG_ADDR_TIMER_CONTROL, clock )
rtc8564_write_byte(REG_ADDR_TIMER, count )
rtc8564_timer_enable
end
#----- タイマーを有効にする --------------------------------------
def rtc8564_timer_enable
rtc8564_set_bit( REG_ADDR_TIMER_CONTROL, TIMER_ENABLE )
end
#----- タイマーを無効にする --------------------------------------
def rtc8564_timer_disable
rtc8564_clear_bit( REG_ADDR_TIMER_CONTROL, TIMER_ENABLE )
end
#----- イベント発生時にINT端子の出力をLOWにする ------------------
def rtc8564_timer_interrupt_enable
rtc8564_set_bit( REG_ADDR_CONTROL2, TIMER_INTERRUPT_ENABLE )
end
#----- イベント発生時にINT端子に出力しない -----------------------
def rtc8564_timer_interrupt_disable
rtc8564_clear_bit( REG_ADDR_CONTROL2, TIMER_INTERRUPT_ENABLE )
end
#----- イベント発生フラグをクリヤする ----------------------------
def rtc8564_timer_clear
rtc8564_clear_bit( REG_ADDR_CONTROL2, TIMER_FLAG )
end
#----- イベントが発生したか否かをテストする ----------------------
# これを使ってイベント発生を検知するためにはloop内で呼び続ける必要がある
# 戻り値
# true:イベント発生
# true:イベントは発生していない
#-----------------------------------------------------------------
def rtc8564_timer_test
if rtc8564_test_bit(REG_ADDR_CONTROL2, TIMER_FLAG )
return true
else
return false
end
end
#---------------------------------------------------------------------------
# RTC8564に日時を設定する
#---------------------------------------------------------------------------
def rtc8564_set_time(year, month, day, hour, minute, second)
rtc8564_write_byte(REG_ADDR_SECONDS, rtc8564_dec2bcd(second))
rtc8564_write_byte(REG_ADDR_MINUTES, rtc8564_dec2bcd(minute))
rtc8564_write_byte(REG_ADDR_HOURS, rtc8564_dec2bcd(hour))
rtc8564_write_byte(REG_ADDR_DAYS, rtc8564_dec2bcd(day))
rtc8564_write_byte(REG_ADDR_WEEKDAYS, rtc8564_calc_weekday(year,month,day))
rtc8564_write_byte(REG_ADDR_MONTHS, rtc8564_dec2bcd(month))
rtc8564_write_byte(REG_ADDR_YEARS, rtc8564_dec2bcd(year-2000))
end
#---------------------------------------------------------------------------
# RTC8564から日付時刻を取得する
#
# 引数:日時構造体へのポインタ
#---------------------------------------------------------------------------
def rtc8564_get_time
@tm["year"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_YEARS )) + 2000
@tm["month"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_MONTHS ) & MONTHS_MASK )
@tm["day"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_DAYS ) & DAYS_MASK )
@tm["hour"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_HOURS ) & HOURS_MASK )
@tm["min"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_MINUTES ) & MINUTES_MASK)
@tm["sec"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_SECONDS ))
@tm["weekday"] = rtc8564_bcd2dec( rtc8564_read_byte( REG_ADDR_WEEKDAYS ))
return @tm
end
#---------------------------------------------------------------------------
# 日時を書式整形して出力する rtc8564_get_time()で日時を取得した後に呼び出す
#
# 引数1:文字列の先頭アドレス
# 引数2:日時が格納されている構造体
#---------------------------------------------------------------------------
def rtc8564_sprintf
return sprintf("%04u-%02u-%02u %02u:%02u:%02u\n", @tm["year"], @tm["month"], @tm["day"], @tm["hour"], @tm["min"], @tm["sec"] )
end
#---------------------------------------------------------------------------
# Zellerの公式による曜日の計算 RTC8564は曜日を自動計算できない
#
# return: 0:日曜 6:土曜
#---------------------------------------------------------------------------
def rtc8564_calc_weekday( year, month, day )
if month <= 2
month += 12
year -= 1
end
return ((year + year/4 - year/100 + year/400 + ((13 * month + 8)/5) + day) % 7).to_i
end
#---------------------------------------------------------------------------
# RTC8564の初期電源投入確認
# enziの電源は切るがRTC8564は常時通電の場合、これを呼び出して
#
# 戻り値 true:最初の電源投入 false:すでに電源投入初期化済み
#---------------------------------------------------------------------------
def rtc8564_is_power_on
if rtc8564_test_bit(REG_ADDR_SECONDS, VOLTAGE_LOW )
return true
else
return false
end
end
end
r = RTC8564.new
delay(1000) # RTC8564が安定動作するのを待つ
if r.rtc8564_is_power_on
r.rtc8564_init( 2016, 10, 31, 14, 10, 0 ) # 電源初期投入時のみ時刻の設定
end
s=SimpleHttp.new("ntp-a1.nict.go.jp").get("/cgi-bin/time")
a=s.date.split("2016")[1].split("GMT")[0].split(" ")[0].split(":")
b=[a[0].to_i+9,a[1].to_i,a[2].to_i]
r.rtc8564_init( 2016, 10, 30, b[0], b[1], b[2]+2 )
puts "start"
# r.rtc8564_clock_out_freq( CLOCK_OUT_FREQ_1Hz ) # CLKOUTの周波数を1Hzに設定
# RTC8564rtc8564_clock_out_enable # CLKOUT端子に出力
#
# r.rtc8564_set_alarm_minute( 1 ) # 毎時01分にアラームベントを発生させる 1時間ごとに発生する
# r.rtc8564_alarm_interrupt_enable # アラームイベントでINT端子をLOWにする
#
# r.rtc8564_timer_set( 10, TIMER_CLOCK_1Hz ) # 10秒おきにタイマーイベントを発生させる
# r.rtc8564_timer_interrupt_enable # タイマーイベントでINT端子をLOWにする
loop do
r.rtc8564_get_time
buf = r.rtc8564_sprintf
puts buf
if r.rtc8564_alarm_test # アラームイベント発生確認
puts "alarm"
r.rtc8564_alarm_clear
end
if r.rtc8564_timer_test # タイマーイベント発生確認
puts "timer"
r.rtc8564_timer_clear
end
delay(1000)
end