
I got hold of a Vacuum Fluorescent Display module from Aliexpress. It comes in two versions : one with an SPI interface, one without. I went with the SPI interface version. The display reminded me of a clock radio I had growing up so it was natural to put it to work as a clock. I wired it to an ESP32-CAM module as shown below:

Details about how the display is programmed were found over here. I wanted to use the SPI hardware interface instead of bit-banging the data and so developed the following program using Arduino for ESP32:
#include <SPI.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <HTTPClient.h>
/*
ESP32 based clock.
Uses Vacuum Fluourescent Display (VFD)
Gets time from an NTP server
*/
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
const char* ssid = "***********";
const char* password = "****************";
class VFDisplay
{
public:
VFDisplay() {};
void begin()
{
SPI.begin(SCK,MISO,MOSI,SS);
pinMode(Reset,OUTPUT);
pinMode(CS,OUTPUT);
digitalWrite(Reset, LOW);
delayMicroseconds(5);
digitalWrite(Reset, HIGH);
setDigitCount(8);
setBrightness(127);
Serial.printf("VFD_init\n");
}
void putChar(unsigned char x, char chr)
{
digitalWrite(CS, LOW);
writeDisplay(0x20 + x);
writeDisplay(chr);
digitalWrite(CS, HIGH);
show();
}
void printString(char *str)
{
int x = 0;
while(*str)
{
putChar(x++,*str++);
}
}
private:
void setDigitCount(uint8_t count)
{
digitalWrite(CS, LOW);
writeDisplay(0xe0);
delayMicroseconds(5);
writeDisplay(count-1);
digitalWrite(CS, HIGH);
delayMicroseconds(5);
}
void setBrightness(uint8_t brightness)
{
digitalWrite(CS, LOW);
writeDisplay(0xe4);
delayMicroseconds(5);
writeDisplay(brightness);
digitalWrite(CS, HIGH);
delayMicroseconds(5);
}
void show()
{
digitalWrite(CS, LOW);
writeDisplay(0xe8);
digitalWrite(CS, HIGH);
}
void writeDisplay(uint8_t b)
{
SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0));
SPI.write(b);
SPI.endTransaction();
}
uint8_t Reset=15;
uint8_t CS = 12;
uint8_t SCK = 4;
uint8_t MOSI = 2;
uint8_t MISO = 1;
uint8_t SS = 12; // not actually used - see CS above
};
VFDisplay vfdisplay;
void setup() {
Serial.begin(115200);
vfdisplay.begin();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
vfdisplay.printString("WifiWait");
delay(1000);
}
vfdisplay.printString("WifiDone");
timeClient.begin();
timeClient.setTimeOffset(3600);
timeClient.update();
timeClient.setUpdateInterval(5*60*1000); // update from NTP only every 5 minutes
}
void loop() {
timeClient.update(); // This will only go to the Internat if the update interval has passed (set to 5 minutes above)
String timeString = timeClient.getFormattedTime();
char TimeCharArray[20];
timeString.toCharArray(TimeCharArray,19);
vfdisplay.printString(TimeCharArray);
delay(100);
}
The system appears to work well and could be extended to include a Bluetooth interface to set an alarm time or time zone etc.