つくって楽しい!ラボ

小さな「できた!」を、ゆっくり積み重ねていくモノづくりブログ。

ArduinoでRTCを使って現在時刻を取得する方法!配線からコードまで解説

 

 

記事に広告(アフィリエイト広告)が含まれています。

こんにちは!今回は、電子工作の定番「Arduino」を使って、リアルタイムクロック(RTC)モジュールから現在時刻を取得する方法を共有します。

「サンプル通りにやったのに動かない…」という初心者あるあるな壁にぶつかったので、その解決策も含めて記録に残します。この記事が、誰かのモノづくりのハードルを下げるきっかけになれば嬉しいです。

概要

Arduino本体には時計機能がありません(電源を切るとリセットされてしまいます)。そこで、外部のRTC(リアルタイムクロック)モジュールを使って、正確な時間を刻めるようにします。

使用部品

  • Arduino UNO

  • クロックモジュール RTC 

  • ジャンパー線

このブログでは ELEGOO(エレゴー)製の Arduino 互換品を使って実験しています。Arduino互換品と聞くと品質が心配になる方もいるかもしれませんが、ELEGOO の製品は「互換品とは思えない品質」 で、Arduino公式ボードと同じように問題なく使えます。それでいて 価格はかなりリーズナブル なのが魅力です。
特にスターターキットは、

  • Arduino互換ボード
  • モータ(DC,サーボモータ,ステッピングモータ)
  • 各種センサ
  • 電源モジュール
  • ブレッドボード
  • ジャンパーワイヤ

といった 電子工作で必要なパーツが一式そろっており、初めてでもすぐに実験を始められる 便利なセットになっています。

動作イメージ

シリアルモニタに、秒単位で現在時刻が表示されるようにします。

 

クロックモジュールRTCとは?

原理と詳細

RTCモジュールは、水晶発振子を内蔵した時計専用のICです。 最大の特徴は、バックアップ用のボタン電池を搭載できる点です。これにより、Arduinoの電源を切っても、電池が切れるまで内部で時間を刻み続けてくれます。

使用時の注意点

  • ボタン電池が入っているか・向きが正しいか確認
  • 初回のみ「現在時刻を設定する処理」が必要
  • I2C通信を使うため、SDA / SCLピンの接続ミスに注意

回路・接続

接続は非常にシンプルです。RTCは「I2C(アイ・スクエア・シー)」という通信方式を使います。

RTCピン Arduinoピン 役割
VCC 5V 電源
GND GND グランド
SDA A4 (or SDA) データ信号
SCL A5 (or SCL) クロック信号

※配線時の注意点

SDAとSCLの接続先を間違えないようにしましょう。Arduino UNOの場合、SDAはA4、SCLはA5ピンです(専用のSDA/SCLピンがある基板でも、内部的にはA4/A5と繋がっています)。

プログラム(コード)

ライブラリの選択に注意!

今回、ELEGOO社製のキットに付属していたサンプルコード(DS3231ライブラリ使用)を試したところ、ライブラリのアップデートの影響か、うまく動作しませんでした。 そこで今回は、より汎用性が高く安定している DS3232RTCライブラリ(JChristensen製) を使用します。

■豆知識:DS3232RTC vs DS3231ライブラリ

DS3231(NorthernWidget製)かつての定番ですが、最近の環境ではコンパイルエラーや動作不良が報告されることがあります。DS3232RTC(JChristensen製) DS3231とDS3232の両方に対応しており、メンテナンスも継続されています。Timeライブラリとの親和性が高く、コードが書きやすいのが特徴です。

比較表:DS3232RTC vs DS3231(NorthernWidget)

比較項目 DS3232RTC (JChristensen) DS3231 (NorthernWidget)
主な目的 Arduinoシステム時間管理 チップの機能(ハードウェア)制御
依存ライブラリ TimeLib.h (Time) が必須 Wire.h (標準) のみでOK
時間の扱い

Unixタイム(1970年からの秒数)

※計算や比較が非常に得意

年・月・日・時・分 がバラバラ

※そのまま表示するのに便利

温度センサー △ 取得可能だが、メイン機能ではない ◎ 非常に簡単 (getTemperature関数あり)
アラーム機能 ○ 強力だが、設定コマンドが専門的 ◎ 専用の関数が用意されており直感的
向いている用途

・データロガー(記録)

・複雑なタイマー処理

・時間の計算が必要なとき

・デジタル時計の表示

・温湿度計

・目覚まし時計(アラーム)

サンプルコード

Arduino IDEのライブラリマネージャーで「DS3232RTC」をインストールして使用してください。

/*
  DS3232RTC ライブラリを使用したサンプル
  特徴:ArduinoのTimeライブラリと同期して動作します
*/
#include   // http://github.com/JChristensen/DS3232RTC
#include     // http://playground.arduino.cc/Code/Time
#include 
DS3232RTC RTC;  // RTCクラス
void setup() {
  Serial.begin(9600);
  Wire.begin();  // ハードウェアI2C初期化
  // --- 時刻設定エリア (初回のみ実行し、2回目以降はコメントアウト推奨) ---
  // 時, 分, 秒,日,月,年 (例: 2026年1月30日 12時00分00秒)
//   setTime(21, 58, 0, 31, 1, 2026); 
//   RTC.set(now()); // Arduinoのシステム時刻をRTCに書き込む
  // -------------------------------------------------------------
  // Arduinoのシステム時刻の基準(Sync Provider)としてRTCを指定
  // これにより、now()関数を呼ぶだけでRTCの正確な時間が返ってきます
//  setSyncProvider(RTC.get);
  setSyncProvider([]() {
    return RTC.get();
  });
  if (timeStatus() != timeSet) {
    Serial.println("RTCとの同期に失敗しました");
  } else {
    Serial.println("RTCと同期しました");
  }
}
void loop() {
  // 日付と時刻を表示する関数を呼び出し
  digitalClockDisplay();
  
  delay(1000); // 1秒待機
}
void digitalClockDisplay() {
  // TimeLibの機能で簡単に表示できます
  Serial.print(year());
  Serial.print("/");
  printDigits(month());
  Serial.print("/");
  printDigits(day());
  Serial.print(" ");
  printDigits(hour());
  Serial.print(":");
  printDigits(minute());
  Serial.print(":");
  printDigits(second());
  Serial.println();
}
// 数字が1桁の場合に頭に0をつける関数 (例: 1 -> 01)
void printDigits(int digits) {
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

コード解説

① 全体のプログラム動作概要

このプログラムの主な目的は、「外部のリアルクロックモジュール(DS3232)から正確な時刻を読み取り、Arduino内部の時計を自動的に補正(同期)しながら、シリアルモニタに日時を表示し続けること」です。

  1. 起動時(Setup):
    I2C通信を開始し、Arduinoに対して「時刻の基準(親)はDS3232だよ」と教えます。

  2. 動作中(Loop):
    1秒ごとに現在の日付(年/月/日)と時刻(時:分:秒)をきれいに整形してPCの画面(シリアルモニタ)に送信します。

一度プログラムを書き込めば、RTCにボタン電池が入っている限り、Arduinoの電源を切っても時刻は維持されます。

② プログラムコードのポイント

このコードには、効率的かつスマートに時刻を扱うための重要なテクニックが3つ隠されています。

1. setSyncProvider による自動同期

このコードの最大の肝は setSyncProvider(...) という関数です。

通常、Arduinoの時間は電源を入れると0からスタートしてしまいますが、この関数を使うことで「定期的にRTCへ時間を聞きに行き、Arduino内部の時間を自動で合わせる」という処理を裏側で勝手に行ってくれます。これにより、ユーザーはズレを気にせず now()hour() を呼ぶだけで正確な時間を取得できます。

2. ラムダ式の活用

setSyncProvider の引数に注目してください。

setSyncProvider([]() {
    return RTC.get();
});

ここで []() { ... } という書き方(ラムダ式)が使われています。これは「名前のない関数」をその場で作るテクニックです。「RTCから時間を取得する関数」を直接プロバイダとして渡すことで、コードを簡潔に保っています。

3. 時刻設定の「2段階認証」的な手順

コード内の // 時刻設定エリアコメントアウト(無効化)されています。これは非常に重要なベストプラクティスです。

  • 初回: コメントを外して時刻を書き込む(RTCに時間をセット)。

  • 2回目: すぐにコメントアウトして再度書き込む。

    こうしないと、Arduinoを再起動するたびに、毎回「2026年1月30日...」に時間が巻き戻ってしまうからです。このコードはその運用を見越して書かれています。

③ 各行のプログラムコードの意味

それでは、コードをブロックごとに分けて詳しく見ていきましょう。

1. ライブラリのインクルードと準備

#include <DS3232RTC.h> // DS3232 RTCを制御するためのライブラリ
#include <TimeLib.h>    // Arduino内部で時間を扱うための標準ライブラリ
#include <Wire.h>       // I2C通信(SCL, SDAピン)を行うライブラリ
DS3232RTC RTC;  // RTCを操作するための「RTC」という名前のオブジェクトを作成

ここでは必要な道具箱(ライブラリ)を揃えています。DS3232RTCTimeLib は相性抜群の組み合わせです。

2. セットアップ(初期設定)

void setup() {
  Serial.begin(9600); // PCとの通信開始
  Wire.begin();       // I2C通信の開始(これがないとRTCと話せません)
  // --- 時刻設定エリア ---
  // setTime(21, 58, 0, 31, 1, 2026); 
  // RTC.set(now()); 
  // --------------------
  // ★ここが最重要ポイント
  // Arduinoの時刻合わせ係としてRTCを指定します
  setSyncProvider([]() {
    return RTC.get();
  });
  // 同期がうまくいったか確認
  if (timeStatus() != timeSet) {
    Serial.println("RTCとの同期に失敗しました");
  } else {
    Serial.println("RTCと同期しました");
  }
}

setSyncProvider によって、Arduinoは「あ、自分は時計を持っていないから、定期的に RTC.get() を実行して時間を合わせればいいんだな」と理解します。

3. メインループ(繰り返し処理)

void loop() {
  digitalClockDisplay(); // 下で作った表示用の関数を呼び出す
  delay(1000);           // 1秒待つ
}

loop の中は非常にシンプルです。表示処理を別の関数(digitalClockDisplay)に分けたことで、メインの処理が見やすくなっています。

4. 表示用関数と桁揃え

void digitalClockDisplay() {
  Serial.print(year());
  Serial.print("/");
  printDigits(month());
  // ... (省略) ...
  printDigits(second());
  Serial.println(); // 改行
}
void printDigits(int digits) {
  if (digits < 10)
    Serial.print('0'); // 1桁なら頭に0をつける
  Serial.print(digits);
}

printDigits 関数は、例えば「9時5分」を「09:05」と表示するための工夫です。これがあるだけで、ログデータの見やすさが格段に上がります。

④ 使用されている関数の意味

コード内で使われている専門的な関数を、分かりやすく翻訳しました。

関数名 役割 引数と戻り値
RTC.get() RTCモジュールから現在のハードウェア時刻を読み取ります。 戻り値: time_t 型(1970年1月1日からの経過秒数)。
setSyncProvider(関数) TimeLibに対し「時間の基準となる関数」を登録します。

引数: 時間を返す関数。

効果: これ以降、定期的にその関数が呼ばれ、システム時刻が補正されます。

now() 現在のシステム時刻を取得します。 戻り値: time_t 型。同期設定済みなら、実質的にRTCの正確な時間が返ります。
timeStatus() 現在の時刻同期の状態を確認します。 戻り値: timeSet(同期完了)、timeNeedsSync(要同期)、timeNotSet(未設定)のいずれか。
year(), month(), day()... time_t 型の時間データから、「年」「月」「日」などの要素を取り出します。 引数: なし(自動で now() の結果を使います)。

実験結果

一度プログラムで時刻を書き込むと、RTC内の電池のおかげで、時刻設定用のコード(setup内のコメント部分)を削除してプログラムを再書き込みしても、正しい時刻を保持して出力されることが確認できました。

ArduinoのUSBケーブルを抜いて放置し、数分後に再度繋いでも「今の時間」から再開されるのは、独立した時計を持っている安心感がありますね。

まとめ・応用

今回はRTCモジュールの基本について解説しました。 「付属のサンプルが動かない」というのは電子工作ではよくあることですが、別のライブラリを探すことで解決できる場合が多いです。

今後の応用案:

  • 特定の時間になったらアラームを鳴らす「目覚まし時計」

  • 植物への「自動水やり機」のスケジュール管理

  • SDカードと組み合わせて、時間付きの「温度ログ記録(データロガー)」

皆さんもぜひ、時間に連動したガジェット作りに挑戦してみてください!



にほんブログ村 その他趣味ブログ 電子工作へ
にほんブログ村