マイクロパイソン(RTC)DS1307使い方

RTC1307をmicroPythonでプログラム

ネットで Attiny202を の使い方を探していると、 リアルタイムクロック DS の1307の記事に出会いました 。
昔からある IC のようで決して新しくはありませんが、面白そうなのでライブラリーを使わず分かりやすく 使い方をこれから説明していきたいと思います 。
Picoや アルディーノなどのデータロガー の日時の取得にも 使えそうです。
また今回チャットgptもプログラムの作成に利用してみました、大変参考になりました。

スポンサーリンク

準備するもの

DS1307ZN秋月電子電子で購入250円を使いましたーアマゾンで販売されてるDS1307 RTC   でもOKです
シードシャオ
クリスタル32.768Kh
LED
ミニブレッドボード
その他抵抗、ジャンパー線

配線図

今回はSeeed XIAO RP2040を使って試し、またLEDも使てみました。
配線図は下図です。

DS1307の説明

チャット GPT を使うと次のような検索結果が出てきました。

DS1307は、I2Cバスを介してコントロールされるRTC(一時クロック)デバイスであり、内部には時刻と日付を保持するためのレジスタがあります。以下に、DS1307のメインなレジスタとその設定方法を説明しますます。DS1307には、0x00から0x07までの8つのレジスタがあります。各レジスタは1バイト(8ビット)です。

  1. 0x00 (秒) レジスタ:
    • ビット 7-4: 10 秒の位 (秒の 10 の位)
    • ビット 3-0: 1 秒の位 (秒の 1 の位)
  2. 0x01 (分) レジスタ:
    • ビット 7-4: 10分の位 (10の位)
    • ビット 3-0: 1分の位 (分の1の位)
  3. 0x02 (時) レジスタ:
    • ビット 7 (午後/午前): 0 = 午前、1 = 午後
    • ビット 6-5: 10 時位 (12 時間形式の時間の 10 の位)
    • ビット 4-0: 1 時の位 (時の 1 の位)
  4. 0x03 (曜日) レジスタ:
    • ビット 2-0: 曜日 (1 = 日曜日、2 = 月曜日、…、7 = 土曜日)
  5. 0x04 (日) 登録:
    • ビット 7-5: 10 日の位 (10 の位)
    • ビット 4-0: 1 日の位 (1 日の位)
  6. 0x05 (月) レジスタ:
    • ビット 7-5: 10 月の位 (月の 10 の位)
    • ビット 4-0: 1 月の位 (月の 1 の位)
  7. 0x06 (年) レジスタ:
    • ビット 7-4: 10 年の位 (年の 10 の位)
    • ビット 3-0: 1年の位 (年の1の位)
  8. 0x07 (制御) レジスタ:
    • ビット 7: CH ビット (クロック停止)。1 に設定すると、クロックが停止します。
    • Bit 4: OUT Bit。1に設定すると、SQW/OUTピンから1Hzのクロック出力が行われます。
    • ビット 3-0: SQWE ビット。SQW/OUT ピンの出力周波数を制御します。ビットの値によって、出力周波数が異なります。

DS1307 のレジスタを設定するには、I2C を使用してそれらのアドレスにデータを書き込む必要があります。具体的なコードや手順は使用しているプログラミング言語やマイクロコントローラーによって異なりますが、I2C 通信ライブラリを使用してデータを送信する方法を学ぶことで、DS1307のレジスタを設定することができます。
ダータは2進化10進数でやり取りします。
上の説明を解りやすく図にしました。


プログラム

チャット GPTに質問すると、このようなプログラム返答してきました。

import machine
import utime
DS1307 RTCのI2Cアドレス
DS1307_I2C_ADDR = 0x68

DS1307のレジスタアドレス

SECONDS_REG = 0x00
MINUTES_REG = 0x01
HOURS_REG = 0x02
DAY_REG = 0x03
DATE_REG = 0x04
MONTH_REG = 0x05
YEAR_REG = 0x06
CONTROL_REG = 0x07

1桁の数値を2桁の文字列に変換する関数

def format_number(number):
  return “{:02d}”.format(number)

DS1307から時刻を取得する関数

def get_time():
  i2c = machine.I2C(sda=machine.Pin(4), scl=machine.Pin(5))
  time_data = i2c.readfrom_mem(DS1307_I2C_ADDR, SECONDS_REG, 7)
  seconds = (time_data[0] & 0x0F) + ((time_data[0] >> 4) & 0x07) * 10
  minutes = (time_data[1] & 0x0F) + ((time_data[1] >> 4) & 0x07) * 10
  hours = (time_data[2] & 0x0F) + ((time_data[2] >> 4) & 0x03) * 10
  day = time_data[3]
  date = (time_data[4] & 0x0F) + ((time_data[4] >> 4) & 0x03) * 10
  month = (time_data[5] & 0x0F) + ((time_data[5] >> 4) & 0x01) * 10
  year = (time_data[6] & 0x0F) + ((time_data[6] >> 4) & 0x0F) * 10 + 2000
  return (year, month, date, hours, minutes, seconds)

DS1307に時刻を設定する関数

def set_time(year, month, date, hours, minutes, seconds):
  i2c = machine.I2C(sda=machine.Pin(4), scl=machine.Pin(5))
  time_data = bytearray(7)
  time_data[0] = (seconds % 10) + ((seconds // 10) << 4)
  time_data[1] = (minutes % 10) + ((minutes // 10) << 4)
  time_data[2] = (hours % 10) + ((hours // 10) << 4)
  time_data[3] = 0 # 曜日(0〜6の範囲で、RTCによっては無視されることがある)
  time_data[4] = (date % 10) + ((date // 10) << 4)
  time_data[5] = (month % 10) + ((month // 10) << 4)
  time_data[6] = (year – 2000) % 10 + (((year – 2000) // 10) << 4)
  i2c.writeto_mem(DS1307_I2C_ADDR, SECONDS_REG, time_data)

メインループ

while True:
  year, month, date, hours, minutes, seconds = get_time()
  print(“現在の時刻:{}-{}-{} {}:{}:{}”.format(format_number(year),
  format_number(month), format_number(date),
  format_number(hours), format_number(minutes), format_number(seconds)))
  utime.sleep(1)

このままではSeeed XIAO RP2040では動きません。
使えるように修正、また使いやすくするために一部変更します、また2進化10進数も簡単に説明します。
修正箇所
i2c = machine.I2C(sda=machine.Pin(4), scl=machine.Pin(5))
i2c = machine.I2C(1,sda=machine.Pin(6), scl=machine.Pin(7))
追加
week=[“日曜”,”月曜”,”火曜”,”水曜”,”木曜”,”金曜”,”土曜”]
set_time(2023,8,1,2,14,12,00) #タイムセットの時だけ使う
変更
def set_time(year, month, date, day, hours, minutes, seconds): day 追加

time_data[3] = 0 # 曜日(0〜6の範囲で、RTCによっては無視されることがある)
time_data[3] = day# 曜日(0〜6の範囲で、RTCによっては無視されることがある)0をdayにする


print(“現在の時刻:{}-{}-{} {}:{}:{}”.format(format_number(year),
   format_number(month), format_number(date),
  format_number(hours), format_number(minutes), format_number(seconds)))

year, month, date, day, hours, minutes, seconds = get_time() #day 追加
print(“現在の時刻:{}-{}-{} {} {}:{}:{}”.format(format_number(year), format_number(month), format_number(date),
week[day], format_number(hours), format_number(minutes), format_number(seconds)))

Week[day] 追加

2進化10進数
簡単に説明すると4ビット単位で表す数です。
0000 0001 は 10進数で1です 前の4ビットが 10の位 後ろの4ビットが1の位です
0001 0001 は    11です
0010 0001  は    21です
1バイトで 10進数0から99を表します

こちらがその処理プログラムです(seconds % 10) 1の位で (seconds // 10) 10の位です
time_data[0] = (seconds % 10) + ((seconds // 10) << 4) 10の位を4シフトして1バイトにしてます。

こちらが修正したプログラムです

import machine
import utime
# DS1307 RTCのI2Cアドレス
DS1307_I2C_ADDR = 0x68
# DS1307のレジスタアドレス
SECONDS_REG = 0x00
MINUTES_REG = 0x01
HOURS_REG = 0x02
DAY_REG = 0x03
DATE_REG = 0x04
MONTH_REG = 0x05
YEAR_REG = 0x06
CONTROL_REG = 0x07
# 1桁の数値を2桁の文字列に変換する関数
def format_number(number):
    return "{:02d}".format(number)
# DS1307から時刻を取得する関数
def get_time():
    i2c = machine.I2C(1,sda=machine.Pin(6), scl=machine.Pin(7))
    time_data = i2c.readfrom_mem(DS1307_I2C_ADDR, SECONDS_REG, 7)
    seconds = (time_data[0] & 0x0F) + ((time_data[0] >> 4) & 0x07) * 10
    minutes = (time_data[1] & 0x0F) + ((time_data[1] >> 4) & 0x07) * 10
    hours = (time_data[2] & 0x0F) + ((time_data[2] >> 4) & 0x03) * 10
    day = time_data[3]
    date = (time_data[4] & 0x0F) + ((time_data[4] >> 4) & 0x03) * 10
    month = (time_data[5] & 0x0F) + ((time_data[5] >> 4) & 0x01) * 10
    year = (time_data[6] & 0x0F) + ((time_data[6] >> 4) & 0x0F) * 10 + 2000
    return (year, month, date, day, hours, minutes, seconds)
# DS1307に時刻を設定する関数
def set_time(year, month, date, day, hours, minutes, seconds):
    i2c = machine.I2C(1,sda=machine.Pin(6), scl=machine.Pin(7))
    time_data = bytearray(7)
    time_data[0] = (seconds % 10) + ((seconds // 10) << 4)
    time_data[1] = (minutes % 10) + ((minutes // 10) << 4)
    time_data[2] = (hours % 10) + ((hours // 10) << 4)
    time_data[3] = day # 曜日(0〜6の範囲で、RTCによっては無視されることがある)
    time_data[4] = (date % 10) + ((date // 10) << 4)
    time_data[5] = (month % 10) + ((month // 10) << 4)
    time_data[6] = (year - 2000) % 10 + (((year - 2000) // 10) << 4)
    i2c.writeto_mem(DS1307_I2C_ADDR, SECONDS_REG, time_data)
week=["日曜","月曜","火曜","水曜","木曜","金曜","土曜"]
#set_time(2023,8,1,2,14,12,00)  #セットする時だけです
# メインループ
while True:
    year, month, date, day, hours, minutes, seconds = get_time()
    print("現在の時刻:{}-{}-{} {} {}:{}:{}".format(format_number(year), format_number(month), format_number(date),
                                 week[day], format_number(hours), format_number(minutes), format_number(seconds)))
    utime.sleep(1)

動かしてみました、動いています。



追加
もしLEDを1秒ごとに点滅するには下記の命令を追加してください。
set_time 関数の中の
time_data = bytearray(7)をtime_data = bytearray(8)にして

time_data[6] = (year – 2000) % 10 + (((year – 2000) // 10) << 4)
の下に
time_data[7] =0b00010000を追加してください。

タイトルとURLをコピーしました