ArduinoとRX8900CE UAを搭載したRTC(リアルタイムクロック)モジュールを使ってLCD(液晶ディスプレイ)時計を作りました。
集めたパーツ (2021/12/12追加)
ネット通販(秋月電子通商など)でパーツを集めてブレッドボードで組み立てました。RTCモジュールはRX8900を搭載したAE-RX8900(DIP化モジュール)です。温度補償発振器(DTCXO)を内蔵しており高精度で時刻を管理できます。
# | パーツ | 仕様 | 個数 | 備考 |
1 | Arduino Uno Rev3 | ATmega328 | 1 | 【M-07385】 |
2 | RTCモジュール | RX8900CE UA DIP化モジュール | 1 | 【K-13009】 |
3 | LCDモジュール | I2C接続 16×2行 白色バックライト [ACM1602NI-FLW-FBW-M01] | 1 | 【P-05693】 |
4 | 半固定ボリューム | 3362P 10KΩ | 1 | 【P-03277】 |
5 | 電気二重層コンデンサ | 1.5F 耐電圧 5.5V(タテ型) | 1 | 【P-04300】 |
6 | 保護抵抗 | 手持ちの200Ωを利用 | 1 | |
7 | ブレッドボード | EIC-801 | 1 | 【P-00315】 |
8 | ジャンパーワイヤ | オス-オス 10cmセット | 適量 | 【C-05371】 |
9 | スイッチングACアダプタ ※PCとUSB接続のみの場合は不要 | 9V 1.3A 100~240V | 【M-00030】 |
Arduinoの開発環境「Arduino IDE」のセットアップ手順
Arduinoの公式サイトからArduino IDEをダウンロードしてPCにインストールします。
Arduinoボードの開発環境となる「Arduino IDE」のインストール、各種センサやLCDといったモジュールとArduinoとの接続を容易にする「ライブラリ」を活用したスケッチ作成までの手順メモです。
ブレッドボードでArduinoとRTCモジュールの動作確認、スケッチ実行
RX8900モジュールの組み立て(2021/12/12更新)
RTCモジュールからのI2C線(SDAとSCLの2線)、3.3V線とGND線をArduino Uno Rev3の該当ピンに接続して、サンプルスケッチで動作確認を行います。RTCモジュールのI2Cアドレスは0x32です。RTCモジュール基板上のJ1をショートすると I2C プルアップ抵抗(10kΩ)が有効になります。
※この段階では写真中の電気二重層コンデンサによるバックアップは機能していません。スケッチ(3)で対応しました
LCDモジュールを実装する前のRX8900とArduino Uno Rev3で動作確認を行いました。Arduino IDEでスケッチ1、スケッチ2を実行してシリアルモニタに表示します。
スケッチ1:シリアルモニタに表示(1)
秋月電子通商のWebサイトでRTCモジュールのサンプルスケッチ(RX8900_SAMPLE.zip)が提供されています。このスケッチを実行すると、シリアルモニタから年月日、時分を入力後に、日時、曜日、時刻、チップ内部温度(外気温ではない)が出力されます。
シリアルモニタからの入力時には、画面右下の改行を「CRのみ」にしました。
スケッチ2:シリアルモニタに表示(2)
秋月電子通商のライブラリをもとに作られた GitHub:citrienaサイトのスケッチを利用させていただきました。このスケッチはシリアル出力なのは同じですが、PCとつないでArduino IDEを実行すると時刻合わせができます。
ライブラリとして「TimeLib.h」と「RX8900RTC.h」がincludeされているので、GitHubサイトから「Time-master.zip」と「RX8900RTC-master.zip 」をPCにダウンロードして保存(「Code」ボタンをクリックして「Download ZIP」)。
Arduino IDEのメニューの「スケッチ」→「ライブラリをインクルード」→「.ZIP形式の ライブラリを インストール」で ダウンロードしたZIPファイルを選んで追加します。
ライブラリを追加すると、 Arduino IDEのメニュー の「スケッチ例」→ 「カスタムライブラリのスケッチ例」に「RX8900RTC」が出てくるので 「RX8900RTC_TimeSet」 を開きます。
このスケッチを実行すると、シリアルモニタには実行した時刻(年月日、時分秒)が表示されます。
LCDモジュールを組み込んでバッテリーバックアップ対応のスケッチ修正
LCDモジュールの追加
ブレッドボードにLCDモジュール(ACM1602NI-FLW-FBW-M01)とコントラスト調整用の半固定抵抗を実装し、I2C線(SDAとSCLの2線)、3.3V線とGND線を延長して配線します。
電気二重層コンデンサ によるバッテリーバックアップの追加 (2021/12/12追加)
RX8900チップにはバックアップバッテリの充電、VDD電圧の低下を検出してバッテリーに自動切換えする「電源切替機能」が搭載されています。
RX8900モジュールにはVDD~GND間(C1)とVBATT~GND間(C2)に0.1μFのコンデンサが入っているので、今回の試作ではVBATT端子に電気二重層コンデンサ(1.5F)と手持ちの抵抗(200Ω)を追加しました。
スケッチ3:LCD表示、バッテリーバックアップ対応 (2021/12/17修正)
スケッチ2「RX8900RTC_TimeSet.ino」のシリアルポート出力部分をLCDモジュールへの出力に変更しました。
時刻設定にはArduino DS3232RTC Library sample sketchのcompileTime()を利用させていただきました。「add fudge factor to allow for compile time」とあるように正確な時刻設定には微調整が必要です。
電気二重層コンデンサ によるバッテリーバックアップが行われているので電源が復旧した際にスケッチ実行時刻:compileTimeに初期化されないように、RTC.getよりもcompileTimeが新しい時のみcompiletimeをRTC.setするように if 文を挿入しました。
ツェラー(Zeller)の公式を使って年月日から演算して曜日表示を追加。月、日、時、分、秒が0~9の1桁の場合、1桁目に 空白 もしくは 0 を追加して、右寄りの2桁で表示するように修正しました。
LCDモジュールのI2Cアドレスは0xa0。LCDモジュール用のI2Cライブラリは「構想100年」サイトの LcdCore_20120528.zip と LCD_ACM1602NI_20120528.zip を利用させていただきました。
RX8900RTC_TimeSet_LCD.ino
※ここをクリックするとコード表示を開閉できます。
#include <Arduino.h>
#include <Wire.h> // Arduino IDE のI2Cライブラリ
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
#include <RX8900RTC.h> // https://github.com/citriena/RX8900RTC
#include <LcdCore.h> // LCDコアライブラリ
#include <LCD_ACM1602NI.h> // 秋月I2C液晶用のI/Oライブラリ
RX8900RTC RTC;
LCD_ACM1602NI lcd(0xa0); // 0xa0は液晶モジュールのI2Cアドレス
void setup() {
Wire.begin(); // I2C初期化
lcd.begin(16, 2); // ディスプレイの行数(16)と桁数(2)
RTC.init(); // RTC初期化
//RTC.get()よりcompileTime()が新しい時はcompiletimeをRTC.set
time_t time_now, compiletime;;
time_now = RTC.get();
compiletime = compileTime();
if (time_now < compiletime)
{
RTC.set(compiletime); // set compiled time to RTC
//tmElements_t tm = {0, 0, 12, 2, 5, 5, CalendarYrToTm(2020)}; // second, minute, hour, week, day, month, year
//RTC.write(tm);
}
}
void loop() {
serialTime(RTC.read());
delay(1000);
}
// 秋月I2C液晶ディスプレイに表示
void serialTime(tmElements_t tm) {
// 年月日の表示
lcd.setCursor(0, 0);
lcd.print(tmYearToCalendar(tm.Year));
lcd.setCursor(4, 0);
lcd.print("/");
lcd.setCursor(5, 0);
lcdzeroSup(tm.Month);
lcd.setCursor(7, 0);
lcd.print("/");
lcd.setCursor(8, 0);
lcdzeroSup(tm.Day);
// 曜日の表示 0=日曜 1=月曜 2=火曜 3=水曜 4=木曜 5=金曜 6=土曜
int day_week ;
char DayWeekData[7][4] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"} ;
day_week = getDayWeek(tmYearToCalendar(tm.Year), tm.Month, tm.Day) ;
lcd.setCursor(11, 0);
lcd.print("(");
lcd.print(DayWeekData[day_week]) ;
lcd.print(")");
//時分秒の表示
lcd.setCursor(0, 1);
lcdzeroSup(tm.Hour);
lcd.setCursor(2, 1);
lcd.print(":");
lcd.setCursor(3, 1);
lcdzeroSup(tm.Minute);
lcd.setCursor(5, 1);
lcd.print(":");
lcd.setCursor(6, 1);
lcdzeroSup(tm.Second);
}
// 曜日の計算(ツェラー(Zeller)の公式)
int getDayWeek(int year,int month,int day) {
int w ;
if(month < 3) {
year = year - 1;
month = month + 12 ;
}
w = (year + (year/4) - (year/100) + (year/400) + (13*month+8)/5 + day ) % 7;
return w;
}
// 月、日、時、分、秒が0~9の場合、1桁目を 空白 もしくは 0 に置換
void lcdzeroSup(int digit) {
if(digit < 10)
lcd.print(' '); // 現在「空白」
lcd.print(digit);
}
// function to return the compile date and time as a time_t value
// from alarm_ex1.ino in Arduino DS3232RTC Library sample sketch by Jack Christensen.
time_t compileTime() {
const time_t FUDGE(10); //fudge factor to allow for upload time, etc. (seconds, YMMV)
const char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
char compMon[4], *m;
strncpy(compMon, compDate, 3);
compMon[3] = '\0';
m = strstr(months, compMon);
tmElements_t tm;
tm.Month = ((m - months) / 3 + 1);
tm.Day = atoi(compDate + 4);
tm.Year = atoi(compDate + 7) - 1970;
tm.Hour = atoi(compTime);
tm.Minute = atoi(compTime + 3);
tm.Second = atoi(compTime + 6);
time_t t = makeTime(tm);
return t + FUDGE; //add fudge factor to allow for compile time
}
電波時計モジュールで受信した日時データとRTCを同期させて時刻合わせ(2023/03/26追記)
今回のスケッチでは、起動時にArduino IDEのコンパイル時間を使って時刻合わせを行いました。このLCD時計に電波時計モジュールを追加することでJJY信号の日時情報を使ってPC接続なしで時刻合わせできました。
ビルやマンション内など電波を良好に受信できない環境では、疑似JJY電波を発生させるスマートフォンアプリを使っていつでも時刻合わせができます。