The VFD Clock Software
OpenVFD incorporates a full Arduino® Uno® compatible platform and is built upon the Arduino® environment. The code is largely modular, written in Arduino® C for everyone to understand, to take apart and to participate.
We show you how the OpenVFD software works!
First we are going to take the OpenVFD code apart and see what it does in a usual loop. Then, more importantly we will see convenient functions that you can use to expand the functionality of OpenVFD.
Just like every Arduino® sketch, the firmware of OpenVFD starts with a void setup() initialization. While usual setup things like I/O configs are done, OpenVFD also makes sure to restore the user saved settings and display the welcome message.
OpenVFD jumps into the void loop() routine right after that. Three main procedures update the display, the LEDs and the serial data. So three things you need to know. Let's take it apart!
You will find a complete listing of the OpenVFD firmware below. Also download the OpenVFD firmware .ino file:
OpenVFD Firmware Version 2.01
File Format: Arduino Project File, 63 KB
1. PROCEDURES: INTERFACE ROUTINE (VFD DISPLAY CONTENT SERVICE)
void interfaceRoutine();
The routine interfaces the shift registers that switch the segments of the vacuum tube on and off. It is responsible for every number, every letter you see on the tubes. Assigning a different interface number will change the content displayed on the tubes:
interface == 0: The tubes display the current time. Includes dot mode handler that updates the decimal dot position corresponding to the user-set dot mode.
interface == 1: The tubes display the current date
interface == 2: The tubes display the current temperature sensor reading in either °C or °F
interface == 128: In this interface either the time or the date can be set
interface == 69/70: Additional sensor reading display. Outputs current, min or max value of temperature sensor or microphone (0 to 1024). Remove block comment to enable. Accessible in temperature display mode
When registering a valid button press, void switchInterface(uint8_t input) can switch to another interface. Every switch is correctly executed when void clearInterface() ran correctly.
2. PROCEDURES: LED MODES (LED COLOR ILLUMINATION SERVICE)
void ledRoutine();
The LED routine checks for the current LED illumination mode. Inside a particular mode, it updates the color information and calls further procedures that communicate with the WS2812B LED.
led == 0: Single color preset mode. Smoothly strives for the target color pattern on every update. Does nothing when target color is equal to current color
led == 2: Serial mode reserved. Direct write of target color pattern
led == 3: Serial mode reserved. Smooth strives for the target color pattern on every update. Does nothing when target color is equal to current color
led == 6: Single color fade mode. Smoothly cycles through the color spectrum based on position of HSL wheel. Timer: chUpdater, 60 ms
led == 7: Cross color fade mode. Smoothly cycles through the color spectrum based on position of HSL wheel with linear offset on individual LED. Timer: cfUpdater, 25 ms
led == 8: Chase fade mode. Overwrites color values with new color based on position of HSL wheel in user-set direction when time interval has elapsed. Timer: chUpdater, 60 ms
led == 10: Resistor code. Smoothly strives for the target color pattern on every update. Colors corresponding to ring colors on resistors update with the change of a second
led == 11: Police car mode. Flashes in US police color pattern when time interval has elapsed. Timer: cfUpdater, 25 ms
led == 20: Microphone mode. Overwrites color values with new color based on position of HSL wheel. The number of LEDs turned on correspond to the sound volume. When time interval has elapsed and new volume is less than previous volume, the LEDs turn off from right to left. Timer: vuUpdater, 80 ms
3. PROCEDURES: SERIAL (SERIAL COMMUNICATION SERVICE)
void serialRoutine();
The serial routine checks for availability of serial data. When serial data is present, serialRoutine() executes a command when the command data complies to a 24 byte protocol with start byte == 0x23 and stop byte == 0x24 (command). The command may request a 10 byte reply with the same start and stop byte (response).
Serial Protocol Documentation
File Format: PDF File, 29 KB
4. FUNCTIONS: DISPLAY WRITE COMMAND
void displayWrite(uint8_t renderOption, uint8_t ODDR, int delayOption, char* message)
displayWrite is the final instance called when data is ready for display on the tubes of OpenVFD. It coordinates functions that convert digital numbers, letters, symbols and decimal dot position into seven segment information. There are four arguments required to ensure correct operation.
uint8_t renderOption: Display time, date, temperature or custom message. Time and date information is obtained by requesting data from the RTC directly. Temperature information is taken from the global uint32_t ts variable
uint8_t ODDR: Output dot overlay register. The six least significant bits represent the decimal dot state of each of the six displays. A bit set turns on a corresponding decimal dot
int delayOption: Optional delay on message. Calls delay() if value isn't 0
char* message: Only impacts when uint8_t renderOption is set to message display. Converts incoming 6-byte long char array into seven segment data
5. FUNCTIONS: CONFIGURATION LOAD, SAVE AND RESTORE
void loadConfig(): Load all saved global variables from EEPROM memory, overwriting current variables
void saveConfig(): Save all saved global variables to EEPROM memory. Success message on completion
void firstConfig(): Load default values, overwriting current variables. Note that no save/EEPROM operation is performed!
6. FUNCTIONS: LED
uint32_t ledPhase(uint8_t phase);
The notorious HSL wheel. Input is a value between 0 and 255 (wheel position). Returns wheel position in RGBcolor information. Bits 0-7: blue, bits 8-15: red, bits 16-23: green. Most significant bits unused.Visualize it here!
void render();
Writes data inside rgb_arr[] to the six WS2812B LEDs
7. USEFUL TOOL: TIMER
Known as intervalEvent are timers based on the millis() function and thus not taking up any computation time unless on update call. They are useful for creating finite state machines (FSM) that OpenVFD uses for LED timing and dot overlay.
intervalEvent newiE(long p1): Create a new intervalEvent with the interval specified in p1 as long
void resetiE(intervalEvent &input): Reset the elapsed time to zero
boolean updateIntervalEvent(intervalEvent &input): Check if the interval has elapsed already. Returns 1 if yes
8. USEFUL TOOL: BUTTON STATE CHECKING
This tool is a bit tricky admittedly, but fairly easy to use once you understand how it works.
uint8_t checkOption(int buttonPin): Checks if a long or short press is active. Returns either SHORTPRESS (== 1) or LONGPRESS (== 2) on specified button pin number. OpenVFD uses four global button activity state variables for the four buttons that update in every loop using void cButtonRoutine()
Check the global button activity state variables to see if a short or long press was detected
9. SPECIFIC FUNCTIONS: SENSOR DATA PROCESSING
uint8_t getMicData(uint16_t threshold): Returns microphone sound intensity as 8 bit value by logarithmically scaling calculated amplitude based on 196 (arbitrary value) readings. uint16_t threshold sets the minimum value the mic is sensitive to. Clipping is performed on the values below
uint32_t t_avg(): Returns fixed point temperature sensor mean scaling in celsius or fahrenheit multiplied by 100 for more simple display output.