ATtiny202でDS1307 RTCを動かす!自作ソフトI2C&UARTで超軽量時計

ATtiny202でRTC動作!ATtiny202でDS1307 RTCを動かす!自作ソフトI2C&UARTで超軽量時計
スポンサーリンク

マイコンで時刻を扱いたいときに便利なのがRTC(リアルタイムクロック)です。
今回は、定番のRTCモジュール「DS1307」を使用し、ATtiny202で時刻表示を行うプログラムを作成しました。
しかも今回は、

  • Wireライブラリ不使用
  • 自作ソフトI2C(SoftI2C_VPORT)ダウンロード使いかたはこちらのブログで紹介しています。
  • 自作UART(SimpleUART)

という構成で、プログラム容量は約1410バイトに収まりました。
「小容量マイコンでもRTCを使いたい!」という方に参考になる内容になっています。

スポンサーリンク

使用した環境

マイコン:ATtiny202
RTC:DS1307(I2C接続)アマゾンで数年前に購入しました。

通信:

  • ソフトI2C(自作)
  • UART(自作)

接続図

下図のように接続しました。

rtc-attiny202接続図

DS1307の基本動作

DS1307はI2Cで通信し、内部レジスタに時刻情報を保持しています。

アドレス内容
0x00
0x01
0x02
0x03曜日
0x04
0x05
0x06

ポイントはここです👇

読み出す前にレジスタアドレスを指定する必要がある

重要ポイント(ハマりどころ)

i2c.start();
i2c.write(DS1307_ADDR << 1);  // 書き込みモード
i2c.write(0x00);              // 秒レジスタ
i2c.stop();

これをやらないと、
正しく時刻が取得できません

理由はシンプルで、
どこから読むか」を指定していないためです。
DS1307は内部ポインタを持っているので、最初に 0x00(秒レジスタ)を指定する必要があります。

プログラム全文

#include <SimpleUART.h>
#include <string.h>
#include <SoftI2C_VPORT.h>
#define DS1307_ADDR 0x68
SoftI2C_VPORT i2c(1, 2);  // SDA=PA1, SCL=PA2
// Initialize with 16 bytes buffer
SimpleUART<16> myUART;

// 英語曜日(1=日曜)
const char* weekStr[7] = {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

uint8_t bcdToDec(uint8_t val) {
  return (val >> 4) * 10 + (val & 0x0F);
}

uint8_t decToBcd(uint8_t val) {
  return ((val / 10) << 4) | (val % 10);
}
void rtc_write_time(uint8_t sec, uint8_t min, uint8_t hour,
                    uint8_t day, uint8_t date, uint8_t month, uint8_t year) {
  i2c.start();

  // 書き込みモード
  if (!i2c.write(DS1307_ADDR << 1)) {
    myUART.println("ADDR NACK (WRITE)");
    i2c.stop();
    return;
  }
  i2c.write(0x00);
  i2c.write(decToBcd(sec) & 0x7F);
  i2c.write(decToBcd(min));
  i2c.write(decToBcd(hour));
  i2c.write(decToBcd(day));
  i2c.write(decToBcd(date));
  i2c.write(decToBcd(month));
  i2c.write(decToBcd(year));
  i2c.stop();
  delay(5);
}

void rtc_read(uint8_t *buf) {
  i2c.start();
  i2c.write(DS1307_ADDR << 1);  // 書き込みモード
  i2c.write(0x00);              // 秒レジスタ
  i2c.stop();
  i2c.start();
  i2c.write((DS1307_ADDR << 1) | 1);  //読み込みモード
  for (uint8_t i = 0; i < 7; i++) {
    buf[i] = i2c.read(i < 6);  //7バイト読みこみ終わりにする
  }

  i2c.stop();
}

void setup() {
  myUART.init(9600);
  rtc_write_time(   // 最初に一度だけ実行して時刻日時を設定します
    20,  // 秒
    44,  // 分
    13,  // 時
    6,   // 曜日(例:土曜=6)
    24,  // 日
    4,   // 月
    26   // 年(2026 → 26)
    );
}
void loop() {
  uint8_t buf[7];
  rtc_read(buf);

  uint8_t sec = bcdToDec(buf[0] & 0x7F);
  uint8_t min = bcdToDec(buf[1]);
  uint8_t hour = bcdToDec(buf[2]);
  uint8_t wday  = bcdToDec(buf[3]);  // 曜日
  uint8_t day = bcdToDec(buf[4]);
  uint8_t month = bcdToDec(buf[5]);
  uint8_t year = bcdToDec(buf[6]);
  myUART.print("20");
  myUART.print(year);
  myUART.print("/");
  myUART.print(month);
  myUART.print("/");
  myUART.print(day);
  myUART.print(" (");

  // 曜日表示
  if (wday >= 1 && wday <= 7) {
    myUART.print(weekStr[wday - 1]);
  } else {
    myUART.print("???");
  }

  myUART.print(") ");
  myUART.print(":");
  myUART.print(hour);
  myUART.print(":");
  myUART.print(min);
  myUART.print(":");
  myUART.println(sec);

  delay(1000);
}

プログラムの解説

■ BCD変換

DS1307はBCD形式なので変換が必要です。

uint8_t bcdToDec(uint8_t val) {
  return (val >> 4) * 10 + (val & 0x0F);
}
uint8_t decToBcd(uint8_t val) {
  return ((val / 10) << 4) | (val % 10);
}

 時刻の書き込み

myUART.init(9600);
  rtc_write_time(
    55,  // 秒
    58,  // 分
    7,  // 時
    1,   // 曜日(例:土曜=6)
    13,  // 日
    4,   // 月
    26   // 年(2026 → 26)
    );
}

👉 初回だけ実行すればOKです

※コメントアウトして使うのがポイント

時刻の読み出し

void rtc_read(uint8_t *buf) {
  i2c.start();
  i2c.write(DS1307_ADDR << 1);  // 書き込みモード
  i2c.write(0x00);              // 秒レジスタ
  i2c.stop();
  i2c.start();
  i2c.write((DS1307_ADDR << 1) | 1);  //読み込みモード
  for (uint8_t i = 0; i < 7; i++) {
    buf[i] = i2c.read(i < 6);  //7バイト読みこみ終わりにする
  }

  i2c.stop();
}

流れはこうです:

  1. 読み取り開始位置(0x00)を指定
  2. 再スタート
  3. 読み込みモードで7バイト取得

UART表示

myUART.print("20");
myUART.print(year);

実行結果

2026/4/24 (Fri) :13:45:48
2026/4/24 (Fri) :13:45:49
2026/4/24 (Fri) :13:45:50

このように1秒ごとに時刻が表示されます。

RTCの電池バックアップについて

DS1307は充電式 LIR2032 ボタン電池を接続することで、

電源OFFでも時刻を保持できます

今回の環境でも問題なく動作しました。

今後の拡張(次回予告)

次はさらに実用的にしていきます👇

  • PCからUART経由で時刻設定
  • 自動時刻入力
  • コマンド操作対応

「マイコン単体で時計設定できる仕組み」を作る予定です

まとめ

今回の記事では、ATtiny202を使ってDS1307 RTCを動かし、
時刻表示を行う方法を紹介しました。

ポイントをまとめると👇

  • 自作I2CでもDS1307は十分動作する
  • 読み込み前に「0x00指定」が必須
  • プログラムは約1410バイトと超軽量
  • 電池バックアップで時刻保持もOK

小容量マイコンでもここまでできるので、省メモリ設計の参考にもなると思います。

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