2023年1月、シリコンハウスでVFD(蛍光表示管)が4個入り¥350円で売っていたので購入。春休みの工作としてこのVFDを用いた時計を制作しようと思う。
今回はネットから時刻を取得しそれをVFDで表示させる。ネットへの接続は
ESP32 のWiFi機能を使う。この方法により正確な時計ができるがWiFi環境下でないと動かない。
詳しくはこちら⇒ESP32でネットワーク上から現在時刻を取得する(NTP)
表示方法だが今回ダイナミック点灯を採用した。 すべてのVFDに一斉にデータを送り、高速で一つずつ順番に点灯させることでいい感じに表示できる。 ただ、写真を撮るとすべての桁でなく一部しか光っていないように見える。これは駅や電車の行き先表示をカメラで撮ると一部しか見えないのと同じ原理だろう。
Disp(5, timeInfo.tm_hour / 10 % 10);
Disp(4, timeInfo.tm_hour % 10);
Disp(3, timeInfo.tm_min / 10 % 10);
Disp(2, timeInfo.tm_min % 10);
Disp(1, timeInfo.tm_sec / 10 % 10);
Disp(0, timeInfo.tm_sec % 10);
そして0~9の数字と7個のセグメントの光り方のパターンを関連付ける。 例えば「1」は右側の2つのセグメントが光るのでマイコンが出力するデータは「B11111001」となる。 右から順にabc...に対応している(今回は右から順番にデータを送るので)。 すなわちこの場合bとcが点灯する。 シフトレジスタ74hc595についてはここでは特に触れないがマイコンからの入力信号3本で8本の出力を得るために使用している。 動作原理などはこちら(シフトレジスタ (74HC595) と Arduino を使って複数の LED を制御する方法)の記事がわかりやすいと思う。
図2: LD8035データシートより
オペアンプを使って3.3Vの信号を12Vにレベルシフトしようとしていたが動作が不安定に感じることがある。 オペアンプの出力電圧が足りないのかもしれない。そこで、単純にトランジスタ2SC1815を使い12Vのオンオフ制御に路線変更しようと思う。
図3: オペアンプを使ったレベルシフト回路
#include<WiFi.h>
#include<WiFiServer.h>
const char *ssid = "****";
const char *password = "****";
const byte segment[] = {25, 26, 27, 14, 22, 13}; //各桁カソードピン
const int PIN_CLOCK = 19; //74HC595(SRCLK) → Pin 10
const int PIN_LATCH = 23; //74HC595(RCLK) → Pin 9
const int PIN_DATA = 4; //74HC595(SER) → Pin 8
const byte digit[] = //7セグLED 点灯パターン
{
B11000000, //0
B11111001, //1
B10100100, //2
B10110000, //3
B10011001, //4
B10010010, //5
B10000010, //6
B11111000, //7
B10000000, //8
B10010000 //9
};
void setup ()
{
// WiFi
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (WiFi.begin(ssid, password) != WL_DISCONNECTED)
{
ESP.restart();
}
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
}
Serial.println("Connected to the WiFi network!");
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com");
//7seg
for (int i = 0; i < 6; i++) {
pinMode(segment[i], OUTPUT);
}
pinMode(PIN_LATCH, OUTPUT);
pinMode(PIN_CLOCK, OUTPUT);
pinMode(PIN_DATA, OUTPUT);
}
struct tm timeInfo;
char s[20];
void loop () {
// Time
getLocalTime(&timeInfo);
sprintf(s, "%04d/%02d/%02d %02d:%02d:%02d",
timeInfo.tm_year + 1900, timeInfo.tm_mon + 1,
timeInfo.tm_mday,timeInfo.tm_hour,
timeInfo.tm_min, timeInfo.tm_sec);
Disp(5, timeInfo.tm_hour / 10 % 10);
Disp(4, timeInfo.tm_hour % 10);
Disp(3, timeInfo.tm_min / 10 % 10);
Disp(2, timeInfo.tm_min % 10);
Disp(1, timeInfo.tm_sec / 10 % 10);
Disp(0, timeInfo.tm_sec % 10);
Serial.print("time is ");
}
void Disp(byte keta, byte value) {
for (byte j = 0; j < 6; j++) {
digitalWrite(segment[j], LOW); // 全桁LEDをOFF
}
digitalWrite(segment[keta], HIGH);
digitalWrite(PIN_LATCH, LOW);
shiftOut(PIN_DATA, PIN_CLOCK, MSBFIRST, digit[value]);
digitalWrite(PIN_LATCH, HIGH);
delay(4);
Serial.println(value);
}
3.3Vから12Vへ変換する部分を次ような回路に変更しようと思う。 Bは常に抵抗、キャパシタを介して3.3Vに接続されておりEにLOWが入力されるとB-E間に電流が流れコレクタ電圧は約12Vとなる。 HIGHが入力されるとB-E間に電流が流れないので出力は0Vとなる。 こちら(トランジスタによるレベル変換回路とその高速化) のサイトの回路を使いました。
図4: トランジスタを使ったレベルシフト回路
| 名前 | 個数 | 備考 |
|---|---|---|
| ESP32 | 1 | WiFi付きマイコン |
| 74HC595 | 1 | シフトレジスタ |
| 2SC1815 | 14 | npnトランジスタ |
| LD8035E | 6 | 蛍光表示管 |
| 4.7k | 14 | カーボン抵抗 |
| 1.8k | 14 | カーボン抵抗 |
| 470 | 6 | カーボン抵抗 |
| 0.1uF | 15 | セラミックコンデンサ |
4桁分のはんだ付けが終わった。74hc595が手元にないので点灯試験は後日行う。
74hc595を基板に取り付けて起動してみる。 シリアルのモニタを開くとWiFiに接続し時刻の取得ができていることが確認できたが 時刻表示がうまくできていなかった。(全点灯していたり、一部のセグメントがつきっぱなしだったり、数字の表示順がバラバラだったり…) これはコードのピンの割り当ての順番と実際の配線が異なったり、 ベースと3.3Vの配線がはんだ不良が原因であった。ベースに入力がないとずっとONの状態になりつきっぱなしになるのでうまくダイナミック点灯できない。
コードでピンの割り当てを変更したり、はんだ付け不良の部分を修正することでうまく表示できた。次は秒数の表示もしたい。
最後にケース作りをする。Fusoin360でモデリングし、光造形機で3Dプリントした。 二次硬化し塗装ができたら完成。
図9: 3Dデータ
以上、VFD時計を作ってみたという話でした。 レポート風のブログなのか、ブログっぽいレポートなのかよくわからなくなった。