« March 2020 | Main

May 2020

05/21/2020

NodeMCU1.0 or ESP32 Dev Module を使って 8x8 dotmatrix LEDでデジタル時計をつくる

Img_20200522_083257 Esp32doitdevkitv1-8x8led-clock

朝からず~と取り組んで、やっとこさ完成! ハードウェアはここにあるように、CPU1個とLEDデジタル表示器1個を5本のケーブルで繋ぐだけだけどね・・・。 電源はUSB(5V)で動いている。 肝心なのはソフト! 1週間ほど前に似たようなものを、習作で制作したのですが、表示フォントと表示の方法が気に入らなくて、何とか自分のアイデアで纏めたいと思い、今日は表示フォントも作った! ちょっと太目のフォントなので離れていても見やすい! ソフトが動いて、時間が表示できるようになるまで手古摺った~! 時間はWiFiから入力し処理している。

洒落たケースに入れられれば、もう少し格好が良くなるんだけど・・・。このCPUは、WiFiの技適が無いものだから、近々ESP32-WROOM-32に入れ替えよう!

Sketchには、いろいろ試しながら構築したので、不要な所も多々あると思うが、ご覧になる方にはご容赦願いたい。
中央付近に、時間と分表示の区切り「:」を入れると、時間部分の表示と分の表示部分に同じものを使うと、アンバランスな表示になってしまうので、時の表示と分の表示でフォントのデザインを変更した。

《その後、当日ですが・・・》
手元にあった ESP32-WROOM-32 (Espressif) 「技適済」で動作確認したので、Sketchも修正しておく 

使用部品
・NodeMCU
 又は ESP32 Dev Module (ESPRESSIF ESP32-WROOM-32) Amazonで2個2000円くらいです。
・8x8ドットマトリックスLED(MAX7219 ドット LED マトリックス MCU 制御 LED) Amazonで@1200円くらいです。
・5本ジャンパーケーブル
・ブレッドボード(スイッチサイエンス製を使った)

Sketch
// NodeMCU 1.0(ESP12-E Module)  /  ESP32 Dev Module / ESP32 Wrover Module
// Vcc to Vin .................. Vin or 5V or 3V3
// GND to GND
// Din to D7 .................... D27
// CS to D6 .................... D26
// CLK to D5 .................... D25

#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <LedControl.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
const char* ssid = "your SSID";
const char* password = "your Password";
const long utcOffsetInSeconds = 9*3600;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
int month,dayOfMonth,dayOfWeek,hour,minute,s;
int i=0;
int x=0;
int bstflag= 0;
int twelve = 0; //variable for 12 hour hour counter
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}
// set up display - data, clock, cs, numdevices
LedControl lc = LedControl(D7,D5,D6,4); //pins for Din, CLK, CS
//matrix table for display
//first element on each row is the bottom row of the display, then rising up through the display
const int numh[10][8] = {
// ここに用意したフォントは、左側2文字、"Hour"表示用
{0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x1e}, // zero
{0x00,0x3f,0x0c,0x0c,0x0c,0x0c,0x0f,0x0c}, // one
{0x00,0x3f,0x06,0x0c,0x18,0x30,0x33,0x1e}, // two
{0x00,0x1e,0x31,0x30,0x1e,0x30,0x31,0x1e}, // three
{0x00,0x30,0x30,0x7f,0x33,0x32,0x34,0x38}, // four
{0x00,0x1e,0x31,0x30,0x30,0x1f,0x03,0x3f}, // five
{0x00,0x1e,0x33,0x33,0x1f,0x03,0x23,0x1e}, // six
{0x00,0x06,0x06,0x0c,0x18,0x30,0x33,0x3f}, // seven
{0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e}, // eight
{0x00,0x1e,0x33,0x30,0x3e,0x33,0x33,0x1e} // nine
};
const int numm[10][8] = {
// ここに用意したフォントは、右側2文字、"Minute"表示用
{0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0x78}, // zero
{0x00,0xfc,0x30,0x30,0x30,0x30,0x3c,0x30}, // one
{0x00,0xfc,0x18,0x30,0x60,0xc0,0xcc,0x78}, // two
{0x00,0x78,0xc4,0xc0,0x78,0xc0,0xc4,0x78}, // three
{0x00,0x60,0x60,0xfe,0x66,0x64,0x68,0x70}, // four
{0x00,0x78,0xc4,0xc0,0xc0,0x7c,0x0c,0xfc}, // five
{0x00,0x78,0xcc,0xcc,0x7c,0x0c,0x8c,0x78}, // six
{0x00,0x18,0x18,0x30,0x60,0xc0,0xc4,0xfc}, // seven
{0x00,0x78,0xcc,0xcc,0x78,0xcc,0xcc,0x78}, // eight
{0x00,0x78,0xcc,0xc0,0xf8,0xcc,0xcc,0x78} // nine
};
void drawhNum(int number, int display_div)
{ // drawNum は、数値"number"を、デバイス"display_div"に表示させる
lc.setRow(display_div, 7, numh[number][7]); // デバイス display_div の 1行分(x,y)を纏めて表示設定
lc.setRow(display_div, 6, numh[number][6]); // 変数名num [数値] [行目] 表示を示している
lc.setRow(display_div, 5, numh[number][5]);
lc.setRow(display_div, 4, numh[number][4]);
lc.setRow(display_div, 3, numh[number][3]);
lc.setRow(display_div, 2, numh[number][2]);
lc.setRow(display_div, 1, numh[number][1]);
lc.setRow(display_div, 0, numh[number][0]);
}

void drawmNum(int number, int display_div)
{ // drawNum は、数値"number"を、デバイス"display_div"に表示させる
lc.setRow(display_div, 7, numm[number][7]); // デバイス display_div の 1行分(x,y)を纏めて表示設定
lc.setRow(display_div, 6, numm[number][6]); // 変数名num [数値] [行目] 表示を示している
lc.setRow(display_div, 5, numm[number][5]);
lc.setRow(display_div, 4, numm[number][4]);
lc.setRow(display_div, 3, numm[number][3]);
lc.setRow(display_div, 2, numm[number][2]);
lc.setRow(display_div, 1, numm[number][1]);
lc.setRow(display_div, 0, numm[number][0]);
}
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid,password);
while (WiFi.status() != WL_CONNECTED ) {
Serial.print(".");
delay(500);
}
timeClient.begin();
// power up led matrices
for (i=0; i<4; i++)
{
lc.shutdown(i,false); // デバイス i をシャットダウンしてモードを切り替え
lc.setIntensity(i,0); // set brightness 0-15 デバイス i の明るさを指定
lc.clearDisplay(i); // デバイス i の表示を全クリア
}
}
void displayTime()
{
//modify brightness
for (i=0; i<4; i++)
}
// print hour to led =======================================================
//first set hours to show just 0 in second module after midnight
if (hour==24)
{
twelve=0; // midnight is 00:00
// drawNum は 数値を、デバイスに表示させる
drawhNum(0,3); //place 0 in second module
}
//change time display for BST/GMT - 'hour' is in 24H format and set for GMT
//first set BST summer time flag for months from April through Septemebr
if ((month>3) && (month<10))
{
bstflag=1;
}
else
{
bstflag=0;
}
// Now set the summer time flag after the last Sunday in March ===============
if ((month==3) && (dayOfMonth>24) && (dayOfWeek==1) && (hour>1))
{
bstflag=1;
}
//and remove the BST flag after the last sunday in October
if ((month==10) && (dayOfMonth>24) && (dayOfWeek==1) && (hour>1))
{
bstflag=0;
}
//from here on use bstflag to increment the displayed hour ====================
//work out display for 12 hour format
hour += bstflag;
/*
if (hour>12)
{ // 下記が有効になると12時間表示になる
hour -= 12;
}
*/
twelve = hour;
if (twelve<10)
{
// drawNum は、数値 numberを、デバイスdisplay_div に表示させる
drawhNum(twelve,2); //and write whole hour in second module
}
if (twelve>9)
{
drawhNum(twelve/10,3); //write first digit in first module
drawhNum(twelve%10,2); //and write whole hour in second module
}
if (minute < 10)
{
// drawNum は数値 numberを、デバイスdisplay_div に表示させる
drawmNum(0,1); //put 0 in module 3
}
else
{
drawmNum(minute/10,1); //or put minutes/10 in mod 3
}
drawmNum(minute%10,0); //and the rest of the minutes/10 in module 4
// 10で分を割っているので、10以下の分の値が求められる
}
void loop()
{
timeClient.update();
Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
Serial.print(timeClient.getHours());
Serial.print(":");
Serial.print(timeClient.getMinutes());
Serial.print(":");
Serial.println(timeClient.getSeconds());
hour = timeClient.getHours();
minute = timeClient.getMinutes();
displayTime(); // display the real-time clock data on the Serial Monitor,
// blinking dot to show we are working
if (x==0)
{
lc.setLed(2, 1, 0, true); // これはデバイス2 の row=1 col=0 を点灯(true)させる
lc.setLed(2, 2, 0, false);
lc.setLed(2, 5, 0, false);
lc.setLed(2, 6, 0, true);
delay(1000); // every second
x=1;
}
else
{
lc.setLed(2, 1, 0, false); // これはデバイス2 のrow=1 col=0 を消灯(false)させる
lc.setLed(2, 2, 0, true);
lc.setLed(2, 5, 0, true);
lc.setLed(2, 6, 0, false);
delay(1000); // every second
x=0;
}
参考にしたのは
 時刻表示用の8x8フォントを制作するに際して、LED Matrix Tool を使わせて戴きました。インストール不要でオンラインで使える!
 それに、HEX Arryの枠には、私が使いたいデータが打ち出されるので、そのままコピーしてSketchに貼り付けることが出来た。

NodeMCUを使った8x8ドットマトリックスLED時計の作り方
  Simple Dot Matrix Clock Using Node MCU
 これは、RTC Clock を使った方法で、WiFiから時間データを読み取る方法は記載されていない。
 そのため、下記のURLを参考にして、NTPサーバーから時間データを読み取るようにした。
 使っている表示フォントは気に入ったので、使わせて戴いた。但し”7”は少し変更を加えた。

NTPサーバーからの時間入力方法
 Getting Date & Time From NTP Server With ESP8266 NodeMCU

ESP32用のLED matrix 接続ピン
 Demo 5: How to use Arduino ESP32 to display information on SPI LED matrix

《更にその後、当日ですが・・・》
Espressif ESP32-Wrover-B  も ESP32 Dev Module と同じようなピン配列なので、D25,D26,D27 ピンに8x8ドットマトリックスを接続して起動を確認してみた ・・・ 問題なく時間を表示出来た!
Esp32wroverb Espressif ESP32 Wrover-B

《その後》
上図にあるEspressif ESP32 Wrover-B で運用しているのですが・・・いくつか問題が見つかりました。未だ直していません。
➀ある時間経過すると表示が消えてしまう。「RST」ボタンで直ぐに復帰します。スリープ状態なのでしょうか?
➁24時を過ぎてもどんどん時間数表示を加算してゆく。例えば27時とか表示する。なにかのトリガーが入ると、正常な表示になる。

05/06/2020

14segment LED を使ってみる

Img_20200506_092159 Img_20200506_092219 Img_20200506_092251
0.54インチスクリーン、14セグメントの4桁LEDディスプレイをArduino NANO制御ロボットの表示用に購入した。
4桁LED は、I2Cコントロール仕様で、6個セットで1832円(Amazonで購入)。1個約300円。

電源を入れて気づいたのは、左2桁が赤で右2桁がオレンジの表示! 寸法、14segmentとI2Cインターフェイスを使用と書いてあったので、それ以上深く考えずに購入。他の項目には注意が及んでいなかった。

4桁LEDディスプレイのドライバ用のピンは5本ある。普通4本でしょ・・・とよく見ると、ピンの配列は次のようになっている。
SCL、SDA、GND、VCC、Vi2C。 Vi2C って何だ! 電源用らしい。

ここに来てから、14segmentディスプレイの使用方法に関する情報を調べたが・・・ほとんど見つからない。「HT16K33」をキーワードにネット上を探し回って、購入したものと同じLEDディスプレイの写真を表示しているブログを発見し、参考にさせて戴いた。
https://draeger-it.blog/arduino-lektion-108-14-segmentanzeige/?cn-reloaded=1&cn-reloaded=1
「7セグLED表示 その8 4文字-HT16K33② (https://www.denshi.club/cookbook/output/led/7seg/7led54-ht16k33.html)」


このLED購入の目的は、arduino NANOを使った超音波センサー付きロボットの状態を表示するため。これまでは、7セグメントのものを使って表示していたが、7セグメントでは文字表示が分かり難い。もう少し分かり易い表示にしたいので、これを買ってみた。

arduino NANOのピン配列で、SCLとSDAのピンを調べてみる。
https://i.pinimg.com/originals/c2/c2/e6/c2c2e68f8dab93647c3a39b04d61fda5.jpg

これを見ると、SCLは A5ピン。 SDAは A4ピンに接続すればいい。

購入した14segmentのLEDにピンを半田付けして、
そして、ブレッドボードに、Arduino NANO とジャンパーピンを接続して・・・ 

このようにジャンパーピンを配置してみた。

さて、sketch であるが・・・
4桁のLEDは、次にように目的別に表示するようにしたい。
左から、
1桁目:超音波センサの向いている方向(L=左方向、F=前方、R=右方向)
2~4桁:超音波センサーで検出した空間距離をcm値で表示
     例えば、 50 ならば、50cmという具合に・・・
     1mを越える場合もあるので、3桁分を用意した。
数値が1桁ならば、数値は右に詰めて表示し、左側の桁部分には、ゼロを表示する。
数値のゼロを置いて表示させたが、見栄えが良くないので、小文字の「o(オー)」を表示する事にした。

数値の文字長さを調べて、「case文」を使い、桁数に合わせ表示を切り替えるようにした。
数値が1桁なら、LEDの右端(4桁目)に数値を表示し、2桁目と3桁目には「o」を入れて表示する。
数値が2桁なら、LEDの3桁目と4桁目を使って数値を表示し、左から2桁目には「o」を入れて表示する。
数値が3桁なら、LEDの2桁目から4桁目を使って数値を表示する。
もしそれ以外の数値が入力されたら、defaultで、2桁目から4桁目には「*」を表示させる。

Sketch は、表示テスト用として使ったものなので、少し長めのdelay(3000)を入れて確認を容易にした。

Sketch の後半部分は、robot の判断内容を表示するもので、「Back(後退)」「Stop(停止)」「FWD(前進)」という内容を表示させようとした。

《Sketch》

#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
int jgo;
Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4();
void setup() {
alpha4.begin(0x70); // pass in the address
alpha4.setBrightness(1);
// -------------------------------------------------------------
alpha4.clear();
alpha4.writeDisplay();
int inum = 2;
jgo=String(inum).length();
switch(jgo)
{ case 1:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, String(inum).charAt(0) );
break;
case 2:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, String(inum).charAt(0) );
alpha4.writeDigitAscii(3, String(inum).charAt(1) );
break;
case 3:
alpha4.writeDigitAscii(1, String(inum).charAt(0) );
alpha4.writeDigitAscii(2, String(inum).charAt(1) );
alpha4.writeDigitAscii(3, String(inum).charAt(2) );
break;
default:
alpha4.writeDigitAscii(1, '*' );
alpha4.writeDigitAscii(2, '*' );
alpha4.writeDigitAscii(3, '*' );
}
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
alpha4.clear();
alpha4.writeDisplay();
inum = 15;
jgo=String(inum).length();
switch(jgo)
{ case 1:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, String(inum).charAt(0) );
break;
case 2:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, String(inum).charAt(0) );
alpha4.writeDigitAscii(3, String(inum).charAt(1) );
break;
case 3:
alpha4.writeDigitAscii(1, String(inum).charAt(0) );
alpha4.writeDigitAscii(2, String(inum).charAt(1) );
alpha4.writeDigitAscii(3, String(inum).charAt(2) );
break;
default:
alpha4.writeDigitAscii(1, '*' );
alpha4.writeDigitAscii(2, '*' );
alpha4.writeDigitAscii(3, '*' );
}
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
alpha4.clear();
alpha4.writeDisplay();
inum = 123;
jgo=String(inum).length();
switch(jgo)
{ case 1:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, String(inum).charAt(0) );
break;
case 2:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, String(inum).charAt(0) );
alpha4.writeDigitAscii(3, String(inum).charAt(1) );
break;
case 3:
alpha4.writeDigitAscii(1, String(inum).charAt(0) );
alpha4.writeDigitAscii(2, String(inum).charAt(1) );
alpha4.writeDigitAscii(3, String(inum).charAt(2) );
break;
default:
alpha4.writeDigitAscii(1, '*' );
alpha4.writeDigitAscii(2, '*' );
alpha4.writeDigitAscii(3, '*' );
}
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text Back
alpha4.writeDigitAscii(0, 'B');
alpha4.writeDigitAscii(1, 'a');
alpha4.writeDigitAscii(2, 'c');
alpha4.writeDigitAscii(3, 'k');
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text Stop
alpha4.writeDigitAscii(0, 'S');
alpha4.writeDigitAscii(1, 't');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, 'p');
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text Stop
alpha4.writeDigitAscii(0, 'F');
alpha4.writeDigitAscii(1, 'W');
alpha4.writeDigitAscii(2, 'D');
alpha4.writeDigitAscii(3, '*');
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text May
alpha4.writeDigitAscii(0, '*');
alpha4.writeDigitAscii(1, 'M');
alpha4.writeDigitAscii(2, 'A');
alpha4.writeDigitAscii(3, 'Y');
alpha4.writeDisplay();
delay(3000);
}
void loop() {
}

« March 2020 | Main

July 2020
Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Recent Trackbacks

無料ブログはココログ