DIY clock from old VFD display - Thu, Mar 3, 2022
Arduino driven vfd clock
Found this old vfd display in a box a recovered old components, a Noritake FG520A1. The back view shows most of the wiring to the segments.
Probing around it was easy to find which was the cathode, while putting 3v to this and grounding the opposite pin, probing the other pins with around 12v enabled me to build up a map of the pins and segments. Not having used one of these before, I thought it might be a simple mapping of segments to pins to switch them on/off. It seems these displays can only address one digit at a time, so it would need some kind of multiplexing and persistence of vision to make them all look to be on at the same time.
I had a couple of Arduino Nanos already, so this was an easy choice of what to use to drive the display. The pins on this work at 5v, so I would need some way of switching the 12v (or more) to the segments. I don't have much electronics experience, but I though some kind of transistor might work for this. A quick search of the net finds lots of similar projects and an idea of transistor type that might work, a BC547. On writing some simple code to switch on all segments from the arduino, nothing displayed. Just cycling through each digit and enabling the segments as fast as possible in sequence did not work. I found that displaying each digit in turn but leaving each lit for a short time worked best. This caused the brightness to drop off a lot. Increasing the anode voltage to around 30v solved the brightness issue when multiplexing the display. It was simply a matter of finding a sweet spot between flickering and brightness. A pause of around 4ms while displaying each digit seemed to work quite well, but I settled on 2ms to make sure there was no flicker, brightness was fine too.
While this worked fine, I came across the ULN2803 darlington transistor array which looked like it might fit nicely with this build, halving the resistor count and making the wiring a little simpler. I have since found there there are also dedicated vfd drivers which make the whole thing far easier, but that's not always the point of these projects.
A DS3231 was used for the realtime clock. I quickly realised I was running out of pins on the arduino. I have used pins 2-15 to address each segment pin on the display, the rtc would have to use pins 18 & 19 (SCA/SCL). Buttons to set the time used pins 2, 16 and 17.
There are quite a few ways to attack the code for displaying the segments and keeping the clock up to date, I opted for just a simple main loop that had the required delays after displaying each digit with an additional check as to whether the clock set button has been pressed, the time spent in this section is short enough not to have an effect on the display. The first button just puts the clock in or out of 'setting' mode. The second increments the current digit, the third button moves to the next digit.
Arduino code to drive the display:
#include#include int up_button=16; // pin used for the 'up' button int next_button=1; // pin used for the 'next' button int ok_button=17; // pin used for the 'ok' button bool up_pressed=false; bool next_pressed=false; bool ok_pressed=false; unsigned long time_pressed=0; unsigned long db_delay=400000; int update_digit=1; bool time_setting_mode=false; int left2=2; int left3=3; int left4=4; int left5=5; int left6=6; int left7=7; int left8=8; int right1=9; int right2=10; int right3=11; int right4=12; int right5=13; int right6=14; int right7=15; //Output masks for characters 0-9 int number[10][14]={{LOW,HIGH,LOW,LOW,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, {HIGH,HIGH,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,HIGH,HIGH}, {HIGH,LOW,LOW,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, {HIGH,LOW,HIGH,LOW,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, {LOW,LOW,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,HIGH,HIGH}, {LOW,LOW,HIGH,LOW,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,HIGH}, {LOW,LOW,LOW,LOW,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,HIGH}, {HIGH,HIGH,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, {LOW,LOW,LOW,LOW,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, {LOW,LOW,HIGH,LOW,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}}; int dots[14]={LOW,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH}; int hours=12; int minutes=45; unsigned long update_time=0; int count=0; int digit=0; bool flashing_dots=false; int wait_time=2; void setup() { pinMode(left2, OUTPUT); pinMode(left3, OUTPUT); pinMode(left4, OUTPUT); pinMode(left5, OUTPUT); pinMode(left6, OUTPUT); pinMode(left7, OUTPUT); pinMode(left8, OUTPUT); pinMode(right1, OUTPUT); pinMode(right2, OUTPUT); pinMode(right3, OUTPUT); pinMode(right4, OUTPUT); pinMode(right5, OUTPUT); pinMode(right6, OUTPUT); pinMode(right7, OUTPUT); pinMode(up_button, INPUT); // configure 'up_button' as an input attachPCINT(digitalPinToPCINT(up_button), up_button_pressed, HIGH); pinMode(next_button, INPUT); // configure 'next_button' as an input attachPCINT(digitalPinToPCINT(next_button), next_button_pressed, HIGH); pinMode(ok_button, INPUT); // configure 'ok_button' as an input attachPCINT(digitalPinToPCINT(ok_button), ok_button_pressed, HIGH); //Serial.begin(9600); setSyncProvider(RTC.get); // the function to get the time from the RTC if(timeStatus() != timeSet) { setTime(0,0,0,13,2,2019); // if no time has been set/stored make it 00:00 and a random date } } void loop() { // Show the first digit digit=hour()/10; if(hour()>9) // only show digit1 if the hour >9 { for(count=0;count<14;count++) if( (count+1)==6 ) // is this the first digit? digitalWrite(count+2, LOW); else if( time_setting_mode==true && ( (count+1)==11 || (count+1)==14 ) && update_digit==1 ) // if we're in time setting mode, show the line above and below the selected digit digitalWrite(count+2, LOW); else digitalWrite(count+2, number[digit][count]); delay(wait_time); } // Show the second digit digit=hour()%10; for(count=0;count<14;count++) if( (count+1)==7 ) // is this the second digit? digitalWrite(count+2, LOW); else if( time_setting_mode==true && ( (count+1)==11 || (count+1)==14 ) && update_digit==1 ) // if we're in time setting mode, show the line above and below the selected digit digitalWrite(count+2, LOW); else digitalWrite(count+2, number[digit][count]); delay(wait_time); // Show the third digit digit=minute()/10; for(count=0;count<14;count++) if( (count+1)==9 ) // is this the third digit? digitalWrite(count+2, LOW); else if( time_setting_mode==true && ( (count+1)==11 || (count+1)==14 ) && update_digit==2 ) // if we're in time setting mode, show the line above and below the selected digit digitalWrite(count+2, LOW); else digitalWrite(count+2, number[digit][count]); delay(wait_time); // Show the fourth digit digit=minute()%10; for(count=0;count<14;count++) if( (count+1)==10 ) // is this the fourth digit? digitalWrite(count+2, LOW); else if( time_setting_mode==true && ( (count+1)==11 || (count+1)==14 ) && update_digit==2 ) // if we're in time setting mode, show the line above and below the selected digit digitalWrite(count+2, LOW); else digitalWrite(count+2, number[digit][count]); delay(wait_time); // Show the middle flashing dots if (micros()-update_time>2000000) // toggle the middle flashing dots every 2 seconds { flashing_dots=!flashing_dots; update_time=micros(); // remember time of dots display update } for(count=0;count<14;count++) if( flashing_dots==true ) digitalWrite(count+2, HIGH); else digitalWrite(count+2, dots[count]); delay(wait_time); if(ok_pressed==true && time_setting_mode==false) { time_setting_mode=true; update_digit=1; ok_pressed=false; } if(time_setting_mode==true) change_time(); } void change_time() { if(up_pressed==true) { up_pressed=false; switch(update_digit) { case 1: { digit=hour(); digit++; if(digit>23) digit=0; setTime(digit,minute(),0,0,0,0); break; } case 2: { digit=minute(); digit++; if(digit>59) digit=0; setTime(hour(),digit,0,0,0,0); break; } default: break; } } if(next_pressed==true) { next_pressed=false; update_digit++; if(update_digit>2) update_digit=1; } if(ok_pressed==true && (micros()-time_pressed)>db_delay) { RTC.set(now()); time_setting_mode=false; ok_pressed=false; } } void up_button_pressed() { if(up_pressed==false && (micros()-time_pressed)>db_delay) { time_pressed=micros(); up_pressed=true; next_pressed=false; ok_pressed=false; } } void next_button_pressed() { if(next_pressed==false && (micros()-time_pressed)>db_delay) { time_pressed=micros(); next_pressed=true; up_pressed=false; ok_pressed=false; } } void ok_button_pressed() { if(ok_pressed==false && (micros()-time_pressed)>db_delay) { time_pressed=micros(); ok_pressed=true; up_pressed=false; next_pressed=false; } }
The pcb finally arrived, built up the board only to find I had made a mistake with the pinout of the realtime clock module. I had used a different footprint on the pcb to that used on the schematic as it was different to the one I had, I renumbered the pins but forgot to do the same on the other part. Easily fixed by removing the module, using the pinout on the other side of the module and flipping it around. A little filing of the edge so that it fits next to the voltage regulator and it's up an running.
Just need to adjust the voltages to the vfd a little to remove what looks to be a some brightness on a couple of adjacent segments.
Designed a simple enclosure and 3d printed.
...