Sample Site

ARDUINO RTC-LCD

Arduino はじめました

Arduino 始めました。リアルタイムタイマーリレーを完成させる予定です。このページでは、とりあえず LCD(液晶表示器)に RTC(リアルタイムクロック)からデータを取得し、現在時刻を1秒毎に表示するところまで掲載します。

ard_0001_rtclcd.png

今回準備したハードウェアとソフトウェア

  • ハードウェア
  • 1.Nano Clone (ATmega328PB)
  • 2.DS3231SN モジュール (I2C)
  • 3.LCD 2004 モジュール (I2C)
  • 4.ジャンパーワイヤー (オスメス) 8本
  • 5.抵抗器5.6kΩ (LCD のバックライト調整用)
  • 6.ブレッドボード
  • 7.USBケーブル (miniB)
  • ソフトウェア
  • 8.Arduino IDE 2.3.2 (Linux 64bit Appimage)
  • 9.MiniCore (Urboot bootloader)
  • 11.DS3232RTC (library)
  • 12.Arduino Time Library
  • 13.LiquidCrystal I2C (library)
  • 1.Nano Clone(ATmega328PB) 315yen
  • ard_0002_nanoclone.png

    Arduino Uno(純正品)を購入したのですが、意外と消費電流が大きいし、I2Cは2個しか刺さらないしで、これは教則的な使用方法を学ぶ、教材の立ち位置なのかな、と思いました。 そこで、中華サイトにて上記 Uno の 1/10以下(315円/個)の値段で購入した Nano Clone をブレッドボードに挿して使用してみました。
    この Clone に使用されているマイコンは純正(328P)ではなく、上位互換品(328PB)です。購入時から焼かれているブートローダーが 328P 用のオールドバージョン(スケッチ書き込みの通信速度が現行の半分の速度)でしたので、MiniCore をインストールしてブートローダーを焼き直し、 ボードを ATmega328 として使用しています。

  • 2.DS3231SN モジュール (I2C) 229yen
  • ard_0003_rtc.png

    お試しで 5 枚購入しました。すべて DS3231SN と IC に刻印されていましたが、32kHz の出力を測定すると 32.768kHz を大幅に下回るものが 4 枚(32.661〜32.663kHz) ありました。差は 100Hz 以上(笑)、明らかに偽物です。まあ、正規ルートでこの IC を購入すると、1 IC あたり 2000yen 前後(時価)するので、フェイクであることはわかっていたのですが。 電池を入れて放置すること数日。何故か 2100年 になっているもの、ランダムにリセットされるもの、温度のズレが10度以上あるもの、3 日で 2 秒遅れるもの、とバラエティに富んでいます。残り 1 枚は 32.765Hz で時刻のズレは数日ではわからないものでした。これは中古かもしれません(刻印が他のものと違う)。5 枚中 3 枚は使用できないので、DS3231S#(SNより使用温度範囲が狭い)正規品を発注し、IC 取り外しの刑に処しました。

    ard_0006_fakeRTC.jpg

    発注の翌日には IC が届いたので、早速取り付けて

    ard_0007_modrtc.jpg

    分解能 1Hz 誤差 1ppm の精度で周波数測定できるかもしれない、というカウンターで確認

    ard_0008_32kfreq.jpg

    これが普通の DS3231S# です。DS3231 のデータシートにありますが、32.768kHz が出力されるのです。MIN も MAX も ありません、判で押したように 32.768kHzなのです。 これが狂っているものは、偽物か DS3231M かまたは壊れかけの中古品です(個人的見解)。

    正規 IC は chip1stop(チップワンストップ)様にて 6 ピース購入いたしました。破格のお値段と迅速なるご発送ありがとうございました。

    結局 RTC モジュール 1 台あたりの合計金額は 229(基板) + 959(IC) = 1,188yen となりました。ちなみに筆者のラズパイ用 RTC (seeed studio製 DS3231SN 搭載) は、購入当時(2021年) 1,299yen でした。2024年現在、これ 2,244yen に跳ね上がってます。某王手通販サイトでは 3,980yen おそるべし。

  • 3.LCD 2004 モジュール (I2C) 708yen
  • ard_0004_lcd.png

    LCDもI2C接続のものを選びました。20文字×4行の表示領域を持つものです。専用のモジュールが裏側にはんだ付けされています。バックライトが眩しすぎましたので、ショートピンを外して、5.6kΩ の抵抗を取り付けました。

    スケッチ

    とにかく、後のことを考えると delay() の使用は NG ですので、色々考えた結果、millis() で1秒を計測後、経過時間をゼロに初期化する方法にしました。これで疑似的なマルチタスクが可能になりそうです(Windows 3.1 的な)。

    時刻の設定は、筆者所有の raspberry pi 4 を使用します。筆者のラズパイはほぼ音楽専用機ですが、RTC (DS3231) を取り付けてあります。これの代わりに今回の"偽 DS3231SN" シールドを取り付け、以下のコマンドで現在時刻を設定しました。ntpサーバと同期しているので書き込み時の値は正確です。

    $ sudo hwclock -w --local

    --local を指定しない場合、UTC(世界協定時刻)が設定され、日本の場合だと9時間ずれます。

    time_show.ino
    1 : // LCD Clock for DS3231SN/M 2 : // Nano Clone (atmega328PB MiniCore board:ATmega328) 3 : // LCD2004 I2C 4 : // DS3231 Shield 5 : // Jumper Wire 8 6 : 7 : #include <DS3232RTC.h> 8 : #include <LiquidCrystal_I2C.h> 9 : LiquidCrystal_I2C lcd(0x27, 20, 04); //0x27 (value of jumper selection) 10 : DS3232RTC myRTC; 11 : const char *week_day[] = { 12 : "NOP", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; 13 : tmElements_t tm; 14 : extern volatile unsigned long timer0_millis; 15 : unsigned long interval = 1000; 16 : int status = 1; 17 : 18 : void setup() { 19 : lcd.init(); 20 : lcd.backlight(); 21 : lcd.setCursor(0,0); 22 : lcd.print("RealTimeClock v1.0"); 23 : myRTC.begin(); 24 : //Sync your display to RTC 25 : int sec0, sec1 = 1024; 26 : while(1) { 27 : myRTC.read(tm); 28 : sec0 = int(tm.Second); 29 : if (sec0 - sec1 == 1) break; 30 : sec1 = sec0; 31 : } 32 : // set | adjust time 33 : // Install the Li-battery in the RTC and replace raspberry-pi4's RTC(DS3231) 34 : // $ sudo hwclock -w --local 35 : // remove the RTC from raspberry pi immediately . 36 : } 37 : 38 : void loop() { 39 : if (status == 1){ 40 : myRTC.read(tm); 41 : char buff[15]; 42 : sprintf(buff, "%d/%02d/%02d %s", tm.Year + 1970, 43 : tm.Month, tm.Day, week_day[tm.Wday]); 44 : lcd.setCursor(0, 1); 45 : lcd.print(buff); 46 : sprintf(buff, "%02d:%02d:%02d", tm.Hour, tm.Minute, tm.Second); 47 : lcd.setCursor(0, 2); 48 : lcd.print(buff); 49 : char buff2[6]; 50 : float temp = myRTC.temperature(); 51 : temp = temp / 4.0; 52 : dtostrf(temp, 5, 2, buff2); 53 : sprintf(buff, "TEMP = %s \xdf\x43", buff2); 54 : lcd.setCursor(0, 3); 55 : lcd.print(buff); 56 : status = 0; 57 : } 58 : 59 : unsigned long tMillis = millis(); 60 : 61 : if (tMillis >= interval) { 62 : status = 1; 63 : noInterrupts (); 64 : timer0_millis = 0; 65 : interrupts (); 66 : } 67 : }

    avrdude: 8608 bytes of flash verified
    この行数で約 1/4 のプログラム領域を消費してしまいました。この先タイマー時刻(ON / OFF)を入力するためのロータリーエンコーダーやボタンの入力処理、強制 ON / OFF 処理をコーディングするのですが、ちょっと不安になる勢いです。

    25 行目からの RTC と LCD の同期ですが、特に重要ではありません。しかし、これがないと、どんなに高精度の RTC を使用したとしても、最大 1 秒の表示ズレを起動時に発生させます。筆者的には、なんだか負けたような気がして、許容できません。とはいえ、LCD の表示更新スピードが遅いので、必ず起動時のタイムラグが生じます。millis() も正確な 1 秒を刻めませんし、世の中にはどうしようもないことがありますね。

    動作確認

    ard_0005_rtclcd.jpg

    消費電流 16mA (USB 電圧 5.134 V)