DS3231のI2C通信と時刻取得の実装手順

センサ―

ArduinoやESP32で、電源を切っても現在時刻を保持したい場合に便利なのがRTC(リアルタイムクロック)です。

RTCの中でもDS3231は、I²Cで簡単に接続でき、高精度な時刻管理ができるICとして広く使われています。

この記事では、DS3231のArduino・ESP32での使い方を中心に、配線、I²Cアドレス、時刻の取得・設定方法を解説します。

後半では、ライブラリを使わずにI²C通信でDS3231のレジスタを直接読み書きする方法についても解説します。

DS3231とは

DS3231は、I²C通信に対応した高精度なRTC(Real Time Clock:リアルタイムクロック)ICです。

RTCを使用すると、マイコンの電源を切っている間も時刻を保持できます。

例えば、次のような用途に利用できます。

  • 時計の製作
  • 決まった時刻に動作する装置
  • センサーデータへの日時記録
  • SDカードへ保存するファイルのタイムスタンプ
  • データロガー
  • IoT機器の時刻管理

DS3231は水晶振動子と温度補償回路を内蔵したTCXO(Temperature Compensated Crystal Oscillator)を使用しており、高精度に時刻を管理できるのが特徴です。

DS3231の主な仕様

項目 仕様
通信方式 I²C
I²Cアドレス 0x68(固定)
I²C通信速度 最大400kHz
精度 ±2ppm(0℃~+40℃)
時計 秒・分・時・曜日・日・月・年
うるう年補正 2100年まで対応
バックアップ バッテリーバックアップ対応
その他 温度センサー・アラーム×2・矩形波出力など

DS3231のI²Cアドレスは0x68です。

アドレスは固定されているため、同じI²CバスへDS3231を複数接続する場合は注意が必要です。

I²Cで複数のデバイスを接続する方法については、こちらの記事で詳しく解説しています。

Arduino・ESP32で複数のI²Cセンサーを同時に使う方法|アドレス重複の対処も解説

DS3231の日本語データシート

DS3231のレジスタや詳しい仕様を確認したい場合は、データシートを参照してください。

英語版データシートの内容を日本語で確認できるページも公開しています。

DS3231 データシート日本語

DS3231とArduino・ESP32の接続

DS3231はI²Cデバイスなので、基本的にはVCC・GND・SDA・SCLを接続します。

DS3231 役割
VCC 電源
GND GND
SDA I²Cデータ
SCL I²Cクロック

Arduino UNOの場合、一般的にはSDA=A4、SCL=A5を使用します。

ESP32ではI²Cに使用するGPIOを指定できます。使用しているESP32ボードのピン配置を確認してください。

I²C通信そのものについては、以下の記事でも詳しく解説しています。

I²Cとは?通信の仕組みを解説

I²CスキャナでDS3231を確認する

DS3231を接続したら、最初にI²Cスキャナを実行して通信できているか確認すると便利です。

正常に認識されていれば、I²Cスキャナに0x68が表示されます。

I2C device found at address 0x68

0x68が表示されない場合は、SDA・SCL・電源・GNDなどの配線を確認してください。

I²Cスキャナのプログラムはこちらの記事で紹介しています。

Arduino・ESP32でI²Cスキャナを使う方法|I²Cアドレスを調べるサンプルコード

Arduino・ESP32からDS3231を使う

Arduino IDEでは、DS3231を簡単に扱えるRTClibを利用できます。

Arduino IDEのライブラリマネージャーを開き、RTClibを検索してAdafruitのライブラリをインストールします。

ライブラリを使用すると、DS3231内部のBCD形式やレジスタを意識せずに日時を取得できます。

現在時刻を取得するサンプルプログラム

DS3231から現在日時を取得し、シリアルモニターへ表示する基本的なプログラムです。

#include <Wire.h>
#include <RTClib.h>

RTC_DS3231 rtc;

void setup()
{
  Serial.begin(115200);

  Wire.begin();

  if (!rtc.begin()) {
    Serial.println("DS3231が見つかりません");
    while (1);
  }
}

void loop()
{
  DateTime now = rtc.now();

  Serial.print(now.year());
  Serial.print("/");
  Serial.print(now.month());
  Serial.print("/");
  Serial.print(now.day());
  Serial.print(" ");

  Serial.print(now.hour());
  Serial.print(":");
  Serial.print(now.minute());
  Serial.print(":");
  Serial.println(now.second());

  delay(1000);
}

正常に通信できていれば、シリアルモニターへ次のように日時が表示されます。

2026/9/28 8:30:01
2026/9/28 8:30:02
2026/9/28 8:30:03

rtc.now()でDS3231から現在日時を取得し、DateTimeオブジェクトから年・月・日・時・分・秒を取り出しています。

DS3231の時刻を設定する

初めてDS3231を使用するときは、RTCへ正しい日時を設定します。

RTClibではrtc.adjust()を使って日時を設定できます。

rtc.adjust(DateTime(2026, 9, 28, 8, 30, 0));

上の例では、2026年9月28日 8時30分00秒を設定しています。

プログラムをコンパイルした日時を設定する方法もあります。

rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

ただし、この処理を毎回実行すると、マイコンを再起動するたびにRTCの時刻を書き換えてしまいます。

時刻設定用として一度実行したあとは、不要なrtc.adjust()を削除またはコメントアウトして使用します。

バックアップ電池で電源OFFでも時刻を保持できる

DS3231にはバックアップ電源入力があり、メイン電源がなくなってもRTCを動作させ続けることができます。

市販のDS3231モジュールでは、ボタン電池を取り付けられる製品が多く販売されています。

これによりArduinoやESP32の電源をOFFにしても時刻を保持できるため、次回起動時に再び正しい日時を取得できます。

ただし、使用できるバックアップ電池の種類や充電回路の有無はモジュールによって異なるため、使用する基板の回路・仕様を確認してください。

ここからはライブラリを使わずDS3231を制御する

ライブラリがない環境では、自分でI²C通信を実装することもできます。

ここからは、もともとこの記事で扱っていたPSoC6からDS3231を直接制御したときの考え方を解説します。

ArduinoやESP32ではRTClibを使えば簡単ですが、DS3231内部で実際にどのようなデータがやり取りされているのか理解したい場合にも参考になります。

DS3231のレジスタ

DS3231では、時刻情報がレジスタに格納されています。

アドレス 内容
0x00 秒
0x01 分
0x02 時
0x03 曜日
0x04 日
0x05 月
0x06 年

0x00から順番に読み出せば、秒・分・時・曜日・日・月・年をまとめて取得できます。

BCD方式

DS3231の時刻情報を直接扱うときに理解しておきたいのがBCD(Binary Coded Decimal)です。

BCDでは、1バイトの中で十の位を上位4ビット、一の位を下位4ビットで表現します。

例えば45秒の場合は、BCDでは0x45になります。

通常の整数からBCDへ変換する場合は、次のように計算できます。

uint8_t decToBcd(uint8_t value)
{
  return ((value / 10) << 4) | (value % 10);
}

逆にBCDから通常の整数へ戻す場合は、次のように変換できます。

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

ライブラリを使用する場合は、この変換をライブラリ側で処理してくれるため、通常は意識する必要はありません。

I²Cで時刻情報を書き込む

DS3231へ直接時刻を書き込む場合は、最初に書き込みを開始するレジスタアドレスを指定し、その後にデータを送信します。

DS3231では連続したレジスタへ複数バイトを順番に書き込めます。

例えば0x02からデータを書き込む場合、概念的には次のようになります。

uint8_t arr[] = {
  0x02, // 書き込み開始レジスタ
  0x34, // 0x02へ書き込み
  0x12  // 0x03へ書き込み
};

最初の0x02で書き込み開始位置を指定します。

次の0x34が0x02へ書き込まれ、その後内部のアドレスが進み、0x12が0x03へ書き込まれます。

秒レジスタの0x00から開始して7バイトの時刻データを連続送信すれば、秒・分・時・曜日・日・月・年をまとめて設定できます。

I²Cで時刻情報を読み込む

DS3231から時刻を読み込む場合も、最初に読み込み開始レジスタを指定します。

0x00から時刻情報を取得する場合は、概念的には次の流れになります。

  1. DS3231へ書き込みモードでアクセスする
  2. 読み込み開始レジスタとして0x00を指定する
  3. リピートスタートする
  4. DS3231へ読み込みモードでアクセスする
  5. 必要なバイト数を受信する
  6. 最後のバイトを受信後、通信を終了する

0x00から7バイト連続して読み込めば、秒・分・時・曜日・日・月・年を取得できます。

取得した値はBCD形式なので、先ほど紹介した方法で通常の数値へ変換して使用します。

DS3231が認識されないとき

ArduinoやESP32からDS3231を認識できない場合は、まず次の項目を確認してください。

  • VCC・GNDが正しく接続されているか
  • SDA・SCLを逆に接続していないか
  • 使用しているマイコンのI²Cピンが正しいか
  • I²Cスキャナで0x68が検出されるか
  • モジュール側の電源電圧・信号電圧がマイコンに適しているか
  • I²Cバス上に同じ0x68のデバイスが存在していないか

まずI²Cスキャナで0x68が表示されるか確認すると、ソフトウェアと配線の問題を切り分けやすくなります。

DS3231とNTPの違い

ESP32などWi-Fiに接続できるマイコンでは、NTPを使ってインターネットから現在時刻を取得する方法もあります。

NTPはネットワークへ接続できれば正確な時刻を取得できますが、ネットワークへ接続できない環境では時刻を取得できません。

DS3231はネットワークを必要とせず、バックアップ電源があればマイコンの電源OFF中も時刻を保持できます。

そのため、オフライン機器やデータロガーなどではDS3231のようなRTCが便利です。

まとめ

DS3231は、ArduinoやESP32からI²Cで簡単に使用できる高精度RTCです。

  • I²Cアドレスは0x68
  • Arduino・ESP32からI²Cで接続できる
  • RTClibを使えば簡単に時刻を取得・設定できる
  • バックアップ電源によってマイコンの電源OFF中も時刻を保持できる
  • ライブラリを使わずレジスタを直接読み書きすることもできる
  • 時刻レジスタではBCD形式が使われている

まずDS3231をI²Cで接続し、I²Cスキャナで0x68が認識されることを確認してから、RTClibで時刻を取得してみると分かりやすいでしょう。

さらにI²Cの仕組みを理解したい場合は、ライブラリを使わずにレジスタを直接読み書きしてみると、I²C通信の理解にもつながります。

関連記事

DS3231を使ってFATFSのファイルへ正確なタイムスタンプを設定する方法はこちらです。

【FatFS】f_utime関数の使い方【マイコン実装】
なんやこれ、よくわからん。。。psoc6にfatfs入れて、f_utimeで軽くつまずいたのでまとめます。f_utimeとはf_utimeはファイルのタイムスタンプを設定する関数です。chanさんのページはこちらこのサイトのコード例にあるよ…

KUMITATE

読むだけでなく、
実際に動かして学びませんか?

クミタテは、組み込み開発や電子工作を 実践しながら学べる学習プラットフォームです。 ESP32を使ったプログラミングから、電子回路、センサー、 通信、基板設計まで、自分のペースで学習できます。

  • 無料で学べる実践的な教材を掲載
  • すぐに試せるサンプルプログラム付き
  • Googleアカウントですぐに登録可能
クミタテに無料登録する
センサ―
スポンサーリンク