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と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スキャナで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から時刻情報を取得する場合は、概念的には次の流れになります。
- DS3231へ書き込みモードでアクセスする
- 読み込み開始レジスタとして0x00を指定する
- リピートスタートする
- DS3231へ読み込みモードでアクセスする
- 必要なバイト数を受信する
- 最後のバイトを受信後、通信を終了する
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のファイルへ正確なタイムスタンプを設定する方法はこちらです。


