TakSan0のアイコン画像
TakSan0 2024年02月03日作成 (2024年02月03日更新)
セットアップや使用方法 セットアップや使用方法 閲覧数 949
TakSan0 2024年02月03日作成 (2024年02月03日更新) セットアップや使用方法 セットアップや使用方法 閲覧数 949

[追加ハード不要] Arduino UNO R4 wifi を積んどくくらいなら時計にしちゃおう。

はじめに

あの Arduino UNO がパワーアップして、しかも WiFi が搭載されたボードもあるみたいと、勢いで Arduino UNO R4 wifi を購入した方も多い方思いますが、積んでいませんか?

時間が出来たら触ろうと思っていると、そうなりますよね。
私もそうでした…

という訳で、とりあえず、積んでおくくらいなら、時計にしてしまいませんか?
ということで時計を作ってみました。

※記事中の写真にマスキングテープを張っているのは、写真写りの都合です。実際は外して使います。

準備

  • PC
    Arduino IDE が動くPC (Windows / MAC / Linux) ならなんでもOK。

  • Arduino UNO R4 wifi
    そもそも積んでいるはずなので探せばあると思いますが、見つからなかった場合とか失くしてしまったのなら仕方がない。
    近くの電子部品屋や電子部品の通販で買えますので、 "Arduino WiFi 通販" とでも検索掛けて購入してください。

  • USB Type C コネクタ データ用 (充電用不可)

Arduino UNO R4 wifi には RTC も WiFi もディスプレイもついていますので、他に追加のハードは要りません。 楽勝ですよね。

インストール

Arduino IDE の導入します。
Arduino IDE 2. を使用する前提の手順になっていますので、まだ 1.8 シリーズを使い続けている方はこの際導入してみてもいいかもしれません。
既にインストール済みの場合は、スケッチ作成の所まで飛んでください。

ダウンロード

公式サイト URL に飛びます。
https://www.arduino.cc/en/software

赤枠の所で、自分の環境に合わせてダウンロードします。

ダウンロード場所

寄付を求められますが、[JUST DOWNLOAD] を選ぶとダウンロードできます。

寄付選択画面

email アドレスを入れ、上の同意をするの方にはチェックを入れて [JUST DOWNLOAD] をクリックします。

同意確認画面

ダウンロードが始まります。ダウンロードしたものを実行するとインストールが始まると思いますが、そのインストール方法は環境によって違うと思うので割愛します。ネットで調べましょう。

インストールが終わったら [File] - [Preferences...] で設定画面を開き、下の赤枠の箇所で言語を日本語にしておくといいと思います。

設定で言語を選択

ソフト書き込み

接続

先ずはボードを差してしまいましょう。
USB Type C のケーブルで PC と Arduino UNO R4 wifi を接続します。初回はドライバーのインストールが走ると思いますので、もし、「ドライバーをインストールします」といった内容の表示が出たら、インストールが終わり「準備が出来ました」とポップが上がるまで少し待ちます。

ArduinoIDE の起動

Arduino - IDE を立ち上げます。
既に使ったことがある人は、最後に使ったスケッチが開くかもしれません。
その場合は [ファイル] - [新規スケッチ作成] を選択します。
その後、下の画面の赤枠部分を押し、[他のボードとポートを選択] を押します。

ボードを選択画面を出す

ボードの所に "UNO r4" と入れて検索し、 Arduino UNO R4 WiFi を選択します。
さらに右側のポートの所のシリアルポートを選択します。ポートは PCに Arduino しか刺さっていなければ ひとつしか選択できないはずです。

ボードとポートを選択

プログラムソースを貼り付け

以下のコードブロックを全て選択してから 右クリック [コピー] でコピーします。

R4-WiFi_NtpClock.ino

// -----=====<<<<<[[[[[ Comments ]]]]]>>>>>=====----- /* This program is based on the sample program in the Arduino Official Tutorial linked to the URL below. [Arduino UNO R4 WiFi Real-Time Clock] https://docs.arduino.cc/tutorials/uno-r4-wifi/rtc/ [Using the Arduino UNO R4 WiFi LED Matrix] https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix/ */ // -----=====<<<<<[[[[[ Include ]]]]]>>>>>=====----- #include "Arduino_LED_Matrix.h" #include "RTC.h" #include <NTPClient.h> #include <WiFiS3.h> #include <WiFiUdp.h> #include "arduino_secrets.h" // -----=====<<<<<[[[[[ Define ]]]]]>>>>>=====----- #define LED_PIN 13 #define JST_OFFSET 9 #define TIMEZONE_OFFSET JST_OFFSET #define DISP_POS_HOUR_X 0 #define DISP_POS_HOUR_Y 0 #define DISP_POS_MIN_H_X 5 #define DISP_POS_MIN_L_X 9 #define DISP_POS_MIN_Y 0 #define DISP_POS_SEC_X 0 #define DISP_POS_SEC_Y 7 #define DISP_POS_A_X 0 #define DISP_POS_D_X 4 #define DISP_POS_J_X 8 #define DISP_POS_ADJ_Y 0 #define DISP_WIDTH 12 #define DISP_HEIGHT 8 #define HOUR_FONT_WIDTH 4 #define HOUR_FONT_HEIGHT 5 #define HOUR_FONT_BITS (HOUR_FONT_WIDTH * HOUR_FONT_HEIGHT) #define MIN_FONT_WIDTH 3 #define MIN_FONT_HEIGHT 6 #define MIN_FONT_BITS (MIN_FONT_WIDTH * MIN_FONT_HEIGHT) #define ADJ_FONT_WIDTH 4 #define ADJ_FONT_HEIGHT 7 #define ADJ_FONT_BITS (ADJ_FONT_WIDTH * ADJ_FONT_HEIGHT) /* #define ADJUSTING_HOUR 4 #define ADJUSTING_MIN 0 #define ADJUSTING_SECOND 0 */ #define ADJUSTING_IN_10_MIN #define ADJUSTING_CYCLE (10*60) // 10minites // -----=====<<<<<[[[[[ Types ]]]]]>>>>>=====----- // -----=====<<<<<[[[[[ Valiable ]]]]]>>>>>=====----- ArduinoLEDMatrix matrix; const char ssid[] = SECRET_SSID; // your network SSID (name) const char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) int wifiStatus = WL_IDLE_STATUS; WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP NTPClient timeClient(Udp); uint32_t matrix_data[3]; static bool need_to_adjust = true; // -----=====<<<<<[[[[[ Prototype ]]]]]>>>>>=====----- void printWifiStatus(); void connectToWiFi(); void drawTime(RTCTime* time); void drawAdjusting(); void setup(); void loop(); // -----=====<<<<<[[[[[ Tables ]]]]]>>>>>=====----- const uint32_t hour_font_data[] = { 0x075557, // 0 0x011111, // 1 0x071747, // 2 0x071717, // 3 0x055711, // 4 0x074717, // 5 0x074757, // 6 0x071122, // 7 0x075757, // 8 0x075717, // 9 0x0bbbbb, // 10 0x099999, // 11 0x0b9bab, // 12 }; const uint32_t min_font_data[] = { 0x03db6f, // 0 0x009249, // 1 0x039f27, // 2 0x039e4f, // 3 0x02de49, // 4 0x03ce4f, // 5 0x03cf6f, // 6 0x039292, // 7 0x03df6f, // 8 0x03de4f, // 9 }; const uint32_t adj_font_data[] = { 0x044aaeaa, // A 0x0caaaaac, // D 0x0E444449, // J }; void printWifiStatus(){ // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // print your board's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // print the received signal strength: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm"); } void connectToWiFi(){ Serial.println("\nStarting connection to server..."); // check for the WiFi module: if (WiFi.status() == WL_NO_MODULE) { Serial.println("Communication with WiFi module failed!"); // don't continue while (true); } String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) { Serial.println("Please upgrade the firmware"); } // Check the WiFi status wifiStatus = WiFi.status(); // attempt to connect to WiFi network: while (wifiStatus != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: wifiStatus = WiFi.begin(ssid, pass); // wait 10 seconds for connection: delay(10000); } Serial.println("Connected to WiFi"); printWifiStatus(); } void drawTime(RTCTime* time){ uint32_t font; uint32_t bit_mask; int8_t hour = time->getHour(); int8_t min = time->getMinutes(); int8_t sec = time->getSeconds(); int8_t x, y, hour_offset_y = (hour < 12)? 0: 1; int8_t disp_bit_pos; // Clear memset(matrix_data, 0x00u, sizeof(matrix_data)); // Disp the Hour part font = hour_font_data[((hour == 12)? 12: (hour%12))]; bit_mask = (uint32_t)(1<<(HOUR_FONT_BITS-1)); for (y = (DISP_POS_HOUR_Y + hour_offset_y); y < ( HOUR_FONT_HEIGHT + DISP_POS_HOUR_Y + hour_offset_y) ; y++) { for (x = DISP_POS_HOUR_X; x < (DISP_POS_HOUR_X + HOUR_FONT_WIDTH); x++ ) { disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 != ( font & bit_mask ) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } bit_mask >>= 1; } } // Disp the Minutes higher part font = min_font_data[min / 10]; bit_mask = (uint32_t)(1<<(MIN_FONT_BITS-1)); for (y = DISP_POS_MIN_Y; y < ( MIN_FONT_HEIGHT + DISP_POS_MIN_Y) ; y++) { for (x = DISP_POS_MIN_H_X; x < (DISP_POS_MIN_H_X + MIN_FONT_WIDTH); x++ ) { disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 != ( font & bit_mask ) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } bit_mask >>= 1; } } // Disp the Minutes lower part font = min_font_data[min % 10]; bit_mask = (uint32_t)(1<<(MIN_FONT_BITS-1)); for (y = DISP_POS_MIN_Y; y < ( MIN_FONT_HEIGHT + DISP_POS_MIN_Y) ; y++) { for (x = DISP_POS_MIN_L_X; x < (DISP_POS_MIN_L_X + MIN_FONT_WIDTH); x++ ) { disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 != ( font & bit_mask ) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } bit_mask >>= 1; } } // Disp the Seconds parts x = DISP_POS_SEC_X + ( sec * DISP_WIDTH / 60 ); y = DISP_POS_SEC_Y; disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 == ((sec % 5) & 1) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } // Send data to matrix matrix.loadFrame(matrix_data); } void drawAdjusting(){ uint32_t font; uint32_t bit_mask; int8_t x, y; int8_t disp_bit_pos; // Clear memset(matrix_data, 0x00u, sizeof(matrix_data)); // Disp the 'A' part font = adj_font_data[0]; bit_mask = (uint32_t)(1<<(ADJ_FONT_BITS-1)); for (y = DISP_POS_ADJ_Y; y < ( ADJ_FONT_HEIGHT + DISP_POS_ADJ_Y) ; y++) { for (x = DISP_POS_A_X; x < (DISP_POS_A_X + ADJ_FONT_WIDTH); x++ ) { disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 != ( font & bit_mask ) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } bit_mask >>= 1; } } // Disp the 'D' part font = adj_font_data[1]; bit_mask = (uint32_t)(1<<(ADJ_FONT_BITS-1)); for (y = DISP_POS_ADJ_Y; y < ( ADJ_FONT_HEIGHT + DISP_POS_ADJ_Y) ; y++) { for (x = DISP_POS_D_X; x < (DISP_POS_D_X + ADJ_FONT_WIDTH); x++ ) { disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 != ( font & bit_mask ) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } bit_mask >>= 1; } } // Disp the 'J' part font = adj_font_data[2]; bit_mask = (uint32_t)(1<<(ADJ_FONT_BITS-1)); for (y = DISP_POS_ADJ_Y; y < ( ADJ_FONT_HEIGHT + DISP_POS_ADJ_Y) ; y++) { for (x = DISP_POS_J_X; x < (DISP_POS_J_X + ADJ_FONT_WIDTH); x++ ) { disp_bit_pos = (y * DISP_WIDTH) + x; if ( 0 != ( font & bit_mask ) ) { matrix_data[disp_bit_pos / ( sizeof(matrix_data[0]) * 8 )] |= (uint32_t)(0x80000000 >> (disp_bit_pos % (sizeof(matrix_data[0]) * 8 ))); } bit_mask >>= 1; } } // Send data to matrix matrix.loadFrame(matrix_data); } void setup(){ // Setup serial Serial.begin(115200); while (!Serial); // Setup pins pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); // Startup libraries matrix.begin(); RTC.begin(); } void loop(){ static RTCTime lastTime = {0}; static int led_on = LOW; static int last_led_on = LOW; static int led_on_cntdown = 5; static int adjust_cntdown = ADJUSTING_CYCLE; RTCTime currentTime; // Adjusting time if needed if ( true == need_to_adjust) { Serial.println("\nAdjusting time now!"); drawAdjusting(); connectToWiFi(); timeClient.begin(); timeClient.update(); auto timeZoneOffsetHours = TIMEZONE_OFFSET; auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600); RTCTime timeToSet = RTCTime(unixTime); RTC.setTime(timeToSet); need_to_adjust = false; adjust_cntdown = ADJUSTING_CYCLE; } // Get the current time RTC.getTime(currentTime); // Update display if (lastTime.getSeconds() != currentTime.getSeconds() ) { drawTime(&currentTime); // Set the blink LED on led_on = HIGH; led_on_cntdown = 5; lastTime = currentTime; // Checking if it's time for adjusting #if defined (ADJUSTING_IN_10_MIN) if ( 0 == adjust_cntdown ) { need_to_adjust = true; } else adjust_cntdown--; #elif defined(ADJUSTING_HOUR) || defined(ADJUSTING_MIN) || defined(ADJUSTING_SECOND) if ( true #if defined(ADJUSTING_SECOND) && ( ADJUSTING_SECOND == currentTime.getSeconds() ) #endif // defined(ADJUSTING_SECOND) #if defined(ADJUSTING_MIN) && ( ADJUSTING_MIN == currentTime.getMinutes() ) #endif // defined(ADJUSTING_MIN) #if defined(ADJUSTING_HOUR) && ( ADJUSTING_HOUR == currentTime.getHour() ) #endif // defined(ADJUSTING_HOUR) ) { need_to_adjust = true; } #endif // defined(ADJUSTING_HOUR) || defined(ADJUSTING_MIN) || defined(ADJUSTING_SECOND) } else { // Set the blink LED off if (0 == led_on_cntdown) led_on = LOW; else led_on_cntdown --; } // Update the blink LED if (last_led_on != led_on) { digitalWrite(LED_PIN, led_on); last_led_on = led_on; } delay(100); }

赤枠のコード入力部分に貼り付けます。
コード貼り付け

[ファイル] - [名前を付けて保存] を選び、 "R4-WiFi_NtpClock" とでも付けて保存します。

秘密の情報設定

WiFi の SSID や パスワードは、うっかり流出しない様に、別ヘッダーファイルで書く様になっているようです。
先ずはそのヘッダを用意します。右上にある下記赤枠の箇所にある […] を押して

 […]  を押す

[新しいタブ] を選択します。
キャプションを入力できます

ファイル名を求められるので、 "arduino_secrets.h" と入れて [OK] を押します。
ファイル名入力

先ずは以下のプログラムを同じ様にコードエリアに貼り付けます。

arduino_secrets.h

#ifndef arduino_secrets_h #define arduino_secrets_h #define SECRET_SSID "" //network name #define SECRET_PASS "" //network password #endif // arduino_secrets_h

図の赤枠部分に、ご自身の家のWiFiルーターに合わせて、 SSID と パスワード に変更して下さい。

自身の家のWiFiルーターのSSID と パスワード に変更

ライブラリの確認・導入

下の左下赤枠部分でライブラリアイコンをクリックし、そのすぐ左上のライブラリマネージャー のところに "NTPClient" と入れて検索します。

NTPClientを検索

上の赤枠部分に "バージョン名 Installed" が出ていれば、インストールされていますが、下画面の様に何もなければインストールされていません。
(インストール) をクリックしてインストールします。

インストール

プログラムの書き込み

画面左上の方、下の図の赤枠部分に 右向き [→] のアイコンがあるので、押します。
エラーが無ければ、そのまま起動し、時計が表示されるはずです。

書き込み

エラーが内容にプログラムを書いているつもりですが、
それでもエラーが出たら、その内容によって対処は異なるのですが、ネットで検索してみて下さい。

#使いかた

使いかたというより見方でしょうか。
12x8 という極小マトリックスに時計を表示する為、最大限の努力で表現しています。

時分表示

縦方向に1ドット短いのが時です、長い方が分です。

午前・午後の判別方法

24 時間は厳しかったので 12時間表示のみです。そして、午前、午後の見分け方ですが、時の表示は 分より縦方向に1ドット分少ないと上に書きましたが、上寄りになっているのが午前(AM) で 下寄りになっているのが 午後(PM) です。

午前(AM) 表示は上寄り

午後(PM) 表示は下寄り

秒表示

秒は5秒おきに位置が移動するドット表示です。横12ドットなので一番右迄行った後分が繰り上がります。
1秒ごとに点灯・消灯を繰り返します。また移動した直後は点灯になります。
秒の情報は余り重要でないので止まってない事だけが見えればいいとの考えで、小さい所に収める最大の努力をした結果でこうなってます。

時刻取得

時刻取得はネット経由で NTPサーバーから時刻を取得して同期を行うようになっています。PCの時計の同期と同じ仕組みです。
そして、取得タイミングは起動時と午前 4:00 になっています。ですので午前 4:00 前辺りが誤差が最大になるかと思います。
起動時とそれ以降10分毎としています。というのも数分で数秒ずれるほど、RTCの精度が悪いという事が判明したためです。10分でも結構ずれます...

時刻取得中には画面に "ADJ." と表示されます。

時刻取得中は ADJ.表示

参考ソースについて

本プログラムは、下記URL で示す Arduino公式のチュートリアルの Matrix LED の記事と RTC の記事に含まれているサンプルプログラムを参考にさせていただきました。

[Arduino UNO R4 WiFi Real-Time Clock]
https://docs.arduino.cc/tutorials/uno-r4-wifi/rtc/

[Using the Arduino UNO R4 WiFi LED Matrix]
https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix/

おそらく Renesas 様が用意してくれたものなのかな?
この場を借りてお礼申し上げます。

最後に

半日程で作ったので、細部でまだ問題があるかもしれませんが、問題あれば修正します。
その場合コメントで報告いただければありがたいです。また要望等もあれば同じくコメントでお願いします。

使ってみたよという方は "いいねなどのリアクション" いただけれると、とてもうれしいです。

RTC の正確さが判らないので、とりあえず1日1回の時刻同期にしていますが、これから少し長時間動かしてみて足りなければ少し増やそうと思っています。

UNO R4 MINIMA も手軽に出来る何か作りたいなぁ・・・

2
TakSan0のアイコン画像
大阪在住の本業組込み系SEです。ハードに近いところのソフト屋さんです。 電子工作は趣味でやっています。 よろしくお願いします。 ▼こちらにも別の作品を投稿しています。参考まで。 https://protopedia.net/prototyper/taksan
  • TakSan0 さんが 2024/02/03 に 編集 をしました。 (メッセージ: 初版)
  • TakSan0 さんが 2024/02/03 に 編集 をしました。 (メッセージ: RTC精度が悪すぎるので調整周期調整)
  • TakSan0 さんが 2024/02/03 に 編集 をしました。 (メッセージ: 時刻同期の方法を少し変更)
ログインしてコメントを投稿する