編集履歴一覧に戻る
eucalyのアイコン画像

eucaly が 2021年02月17日16時12分03秒 に編集

初版

タイトルの変更

+

NTPな掛け時計を作ってみる

タグの変更

+

LED

+

ESP32

+

秋葉原2021

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

製作品

本文の変更

+

# 正確な時刻を、みんなで共有したいのよ 世はすっかりテレワーク時代、カレンダーだのTV会議だので、より一層「遅刻」が目立っちゃう、そんな時代になりました。 会社に出社しても、まあ人はまばらなのですが、だからこそ時間を忘れてゴニョゴニョしてしまう例もちらほら。 なのに会社の掛け時計、とまってたり盛大にずれていたりで、信用できません。 なので、NTPな掛け時計を作ってみることに。 # LEDパネルとESP32で! ま、表示器は、マトリックスLEDでいいでしょう。 一般的なHUB75な、64x32のP5をチョイス。 Adafruitのだと、このへんです。 https://www.marutsu.co.jp/pc/i/27108615/ 信頼と実績のRaspberry Pi + rpi-rgb-led-matrixでもいいのですが。 まあ単機能なので、今回はESP32を使ってみることに。 ESP32には、「WROOM」という、BTやWIFIが入り且つモジュール化され技適もOKな素敵さんがあるので、それで。 早速入手!。 ![キャプションを入力できます](https://camo.elchika.com/92cd0d3f8c5e12f729ec38581bea93270b65ca71/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666637633237372d646465642d343333632d393736342d6162303436346433326631302f30363532633837312d336231312d343634322d623737652d323265323763333439623234/) ・・・失敗です。 WROOMシリーズには、「ESP-WROOM-02」と「ESP-WROOM-32」があるのですが。 HUB75のような高速I/Fを担保するには、末尾32が必要っぽいです。 秋月だと、このへんです。 https://akizukidenshi.com/catalog/g/gM-11819/ 今回はAmazonでてきとーなの入手して使いました。 ま、詳細は、以下サイトなどを参考にしました、とさ。 https://qiita.com/Yukiya_Ishioka/items/c455f7bfbcb240bb2ba7 一応I/Fは5Vなので、バスバッファ使って5V昇圧しています。 「TC74LCXR163245」を使って、、、双方向バスバッファですが、まあ単方向で使ってますよと。 https://akizukidenshi.com/catalog/g/gM-08250/ 電源は5V4AのACアダプタで、ちゃんとジャック側も高電流対応型を、ね。 https://akizukidenshi.com/catalog/g/gK-06998/ # 下準備 まあまず、「デカい文字フォント」を作ります。 これはむかぁし作った変換プログラムで、BMPからサクっと。 ![キャプションを入力できます](https://camo.elchika.com/56f15603c8e2cbc4f0d20e439be6fec229355192/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666637633237372d646465642d343333632d393736342d6162303436346433326631302f30366138623933652d353635652d343534302d383731642d346638643163383537306534/) # 配線 まあ特に言うことはありません。 ワイヤリングは、上記qiitaを参照しつつ、パパっと作りましたとさ。 ![キャプションを入力できます](https://camo.elchika.com/4830a8789d47503cbbe4b2c617ea20dbe7658c7c/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666637633237372d646465642d343333632d393736342d6162303436346433326631302f65323231343036302d346364342d343137322d383235332d646661393832356166353439/) 強いて言えば、バッファのEN配線忘れてて不安定だったことくらいです!。 # ソフトウェア Arduinoでサクっと。 だいたい半日に1回くらい、時計合わせにいきますって感じで。 ```c:ntpclocl.ino #include <WiFi.h> #include <Adafruit_GFX.h> // Core graphics library #include <P3RGB64x32MatrixPanel.h> #define WIFI_SSID "wifi_no_SSID" #define WIFI_PASSWORD "wifi_no_PASSWORD" #define JST 3600*9 // constructor with default pin wiring P3RGB64x32MatrixPanel matrix; long ntpcounter = 0; time_t tprev = 0; char mprev; const uint8_t moji_9[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0, 0x0f,0xf8,0x1f,0xfc,0x1f,0xfc,0x3e,0x3e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3e,0x3e,0x3f,0xfe,0x1f,0xfe,0x1f,0xde, 0x07,0x1e,0x00,0x1e,0x00,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3e,0x3e,0x1f,0xfc,0x1f,0xfc, 0x0f,0xf8,0x03,0xe0,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_8[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0, 0x0f,0xf8,0x1f,0xfc,0x1f,0xfc,0x3e,0x3e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x1e,0x3c,0x1f,0xfc,0x0f,0xf8, 0x0f,0xf8,0x1f,0xfc,0x1e,0x3c,0x3c,0x1e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3e,0x3e,0x1f,0xfc,0x1f,0xfc, 0x0f,0xf8,0x03,0xe0,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_7[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xfe, 0x3f,0xfe,0x3f,0xfe,0x3f,0xfe,0x00,0x3e, 0x00,0x3c,0x00,0x3c,0x00,0x3c,0x00,0x7c, 0x00,0x78,0x00,0x78,0x00,0x78,0x00,0xf0, 0x00,0xf0,0x00,0xf0,0x01,0xf0,0x01,0xe0, 0x01,0xe0,0x01,0xe0,0x03,0xe0,0x03,0xc0, 0x03,0xc0,0x03,0xc0,0x07,0xc0,0x07,0x80, 0x07,0x80,0x0f,0x80,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_6[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0, 0x0f,0xf8,0x1f,0xfc,0x1f,0xfc,0x3e,0x3e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x00,0x3c,0x00, 0x3c,0x00,0x3c,0x70,0x3d,0xfc,0x3f,0xfc, 0x3f,0xfe,0x3e,0x3e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3e,0x3e,0x1f,0xfc,0x1f,0xfc, 0x0f,0xf8,0x03,0xe0,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_5[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xf8, 0x3f,0xf8,0x3f,0xf8,0x3f,0xf8,0x3c,0x00, 0x3c,0x00,0x3c,0x00,0x3c,0x00,0x3c,0x00, 0x3c,0xe0,0x3f,0xf8,0x3f,0xf8,0x3f,0xfc, 0x3c,0x7c,0x3c,0x3c,0x3c,0x3c,0x00,0x3c, 0x00,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, 0x3c,0x3c,0x3c,0x7c,0x3f,0xf8,0x1f,0xf8, 0x0f,0xf0,0x07,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_4[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0x00,0xf8,0x00,0xf8,0x01,0xf8,0x01,0xf8, 0x03,0xf8,0x03,0xf8,0x03,0xf8,0x07,0xf8, 0x07,0xf8,0x0f,0x78,0x0f,0x78,0x1e,0x78, 0x1e,0x78,0x1c,0x78,0x3c,0x78,0x3c,0x78, 0x78,0x78,0x7f,0xfe,0x7f,0xfe,0x7f,0xfe, 0x7f,0xfe,0x00,0x78,0x00,0x78,0x00,0x78, 0x00,0x78,0x00,0x78,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_3[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0, 0x0f,0xf8,0x1f,0xfc,0x1f,0xfc,0x3e,0x3e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x00,0x1e, 0x00,0x1e,0x00,0x3c,0x03,0xfc,0x03,0xf8, 0x03,0xf8,0x03,0xfc,0x00,0x3c,0x00,0x1e, 0x00,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3e,0x3e,0x1f,0xfc,0x1f,0xfc, 0x0f,0xf8,0x03,0xe0,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_2[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0, 0x0f,0xf8,0x1f,0xfc,0x1f,0xfc,0x3e,0x3e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x00,0x1e,0x00,0x3c,0x00,0x3c,0x00,0x78, 0x00,0xf0,0x01,0xf0,0x03,0xe0,0x07,0xc0, 0x0f,0x80,0x0f,0x00,0x1e,0x00,0x1e,0x00, 0x3c,0x00,0x3c,0x00,0x3f,0xfe,0x3f,0xfe, 0x3f,0xfe,0x3f,0xfe,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_1[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0, 0x00,0xe0,0x01,0xe0,0x03,0xe0,0x0f,0xe0, 0x0f,0xe0,0x0f,0xe0,0x01,0xe0,0x01,0xe0, 0x01,0xe0,0x01,0xe0,0x01,0xe0,0x01,0xe0, 0x01,0xe0,0x01,0xe0,0x01,0xe0,0x01,0xe0, 0x01,0xe0,0x01,0xe0,0x01,0xe0,0x01,0xe0, 0x01,0xe0,0x01,0xe0,0x01,0xe0,0x01,0xe0, 0x01,0xe0,0x01,0xe0,0x00,0x00,0x00,0x00, 0x00,0x00, }; const uint8_t moji_0[] PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0, 0x0f,0xf8,0x1f,0xfc,0x1f,0xfc,0x3e,0x3e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3c,0x1e,0x3c,0x1e,0x3c,0x1e, 0x3c,0x1e,0x3e,0x3e,0x1f,0xfc,0x1f,0xfc, 0x0f,0xf8,0x03,0xe0,0x00,0x00,0x00,0x00, 0x00,0x00, }; void setup() { Serial.begin(9600); tuneNtp(); } void setLEDChibimoji(char datachar,char datachar2){ matrix.setTextSize(1); matrix.setCursor(50, 24); matrix.setTextColor(matrix.color444(0, 15 ,0)); matrix.print(datachar); matrix.print(datachar2); } void setLEDChibimoji2(char datachar,char datachar2,char datachar3,char datachar4,char datachar5,char datachar6,char datachar7,char datachar8){ matrix.setTextSize(1); matrix.setCursor(0, 0); matrix.setTextColor(matrix.color444(15, 0, 0)); // matrix.print(datachar); // matrix.print(datachar2); // matrix.print(datachar3); // matrix.print(datachar4); matrix.print(datachar5); matrix.print(datachar6); matrix.print(datachar7); matrix.print(datachar8); } void setLEDDekamoji(int keta,char datachar){ int data; data = (int) datachar; data = data - 48; keta = keta * 16; if (data == 0){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_0, 16, 32, 0xFFF0,0x0000); } if (data == 1){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_1, 16, 32, 0xFFF0,0x0000); } if (data == 2){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_2, 16, 32, 0xFFF0,0x0000); } if (data == 3){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_3, 16, 32, 0xFFF0,0x0000); } if (data == 4){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_4, 16, 32, 0xFFF0,0x0000); } if (data == 5){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_5, 16, 32, 0xFFF0,0x0000); } if (data == 6){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_6, 16, 32, 0xFFF0,0x0000); } if (data == 7){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_7, 16, 32, 0xFFF0,0x0000); } if (data == 8){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_8, 16, 32, 0xFFF0,0x0000); } if (data == 9){ matrix.drawBitmap(keta, 0, (uint8_t*)moji_9, 16, 32, 0xFFF0,0x0000); } } void tuneNtp() { // wifi_set_sleep_type(NONE_SLEEP_T); matrix.stop(); delay(1000); Serial.printf("set wifi"); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); for(int i=0; i<30; i=i+1) { if (WiFi.status() == WL_CONNECTED) { break; } delay(500); } configTzTime("JST-9", "ntp.nict.jp", "ntp.jst.mfeed.ad.jp"); delay(500); WiFi.disconnect(); delay(1000); matrix.begin(); // wifi_set_sleep_type(LIGHT_SLEEP_T); } void loop() { time_t t; struct tm *tm; static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"}; char datebuffer[16]; t = time(NULL); if (t == tprev){ delay(20); return; } tm = localtime(&t); Serial.printf("%04d/%02d/%02d(%s) %02d:%02d:%02d\n", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, wd[tm->tm_wday], tm->tm_hour, tm->tm_min, tm->tm_sec); sprintf(datebuffer, "%04d%02d%02d%02d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); if (datebuffer[11] != mprev) { // matrix.fillScreen(matrix.color444(0, 0, 0)); int mdata; mdata = (int) datebuffer[8]; if (mdata != 0){ setLEDDekamoji(0,datebuffer[8]); } setLEDDekamoji(1,datebuffer[9]); setLEDDekamoji(2,datebuffer[10]); setLEDDekamoji(3,datebuffer[11]); setLEDChibimoji2(datebuffer[0],datebuffer[1],datebuffer[2],datebuffer[3],datebuffer[4],datebuffer[5],datebuffer[6],datebuffer[7]); setLEDChibimoji(datebuffer[12],datebuffer[13]); } else { setLEDDekamoji(3,datebuffer[11]); setLEDChibimoji(datebuffer[12],datebuffer[13]); } ntpcounter++; if (ntpcounter > 40000){ tuneNtp(); ntpcounter = 0; } tprev = t; mprev = datebuffer[11]; } ``` # できました! 特に事故もなく、無事点灯。 ![キャプションを入力できます](https://camo.elchika.com/32bfb513c414de1c504e3356590620d27486568c/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666637633237372d646465642d343333632d393736342d6162303436346433326631302f31373439636637362d343432352d343436322d396665382d666661353636313236646334/) 遠くからでもクッキリで。 いやあ便利!。 それにしてもまあ、RTCとか何もつけてないのに、勝手に時刻が合うのがちょっとだいぶヘン!。 まあ、NTP時計は、市販もされていますが、結構お高いので。 自作したら、1万以内に納まっちゃうので、結構かなりオススメです!。 以上です。