IV-12 Vacuum Fluorescent Display Clock
June 2019

 

The Arduino Sketch

Additional Libraries

RTC lib

IR Remote

/* IV-12 Vacuum Fluorescent Display (VFD) Real Time Clock - (c) vwlowen.co.uk                                        *
 */


#include <Wire.h>
#include "RTClib.h"                // https://github.com/adafruit/RTClib

#include <SPI.h>
#include <IRremote.h>              // https://github.com/z3t0/Arduino-IRremote
#include <EEPROM.h>

// RTC_DS1307 rtc;                    // Choose the RTC clock module here. 
 RTC_DS3231 rtc;                      // In practice, either works.


// These defines are codes from the IR remote, as displayed on the Serial monitor

#define IR_HOURS_UP       0xFD30CF     // 1   set hours+ / day+
#define IR_MINUTES_UP     0xFDB04F     // 2   set mins / month+
#define IR_YEAR_UP        0xFD708F     // 3   Year Up

#define IR_HOURS_DOWN     0xFD08F7     // 4   set hour- / day-
#define IR_MINUTES_DOWN   0xFD8877     // 5   set mins- / month-
#define IR_YEAR_DOWN      0xFD48B7     // 6   Year Down

#define IR_EDIT_TIME      0xFD28D7     // 7   Enter/exit Time edit mode
#define IR_EDIT_ALARM     0xFDA857     // 8   Enter/exit Alarm edit mode
#define IR_EDIT_DATE      0xFD6897     // 9   Enter/exit Date edit mode

#define IR_SHOW_TEMP      0xFD10EF      // 0   Show Temperature

#define IR_ALARM          0xFD20DF     // EQ  Alarm set/reset

#define IR_SHOW_MOOD_LEDS 0xFD00FF     // Play/Pause  - show mood leds.
#define IR_LEDS_OFF       0xFD906F     // Rewind button: edit LEDS Off time
#define IR_LEDS_ON        0xFD50AF     // Fast Forward: edit LEDS On time


const int setHours_pin = 2;            // These three inputs duplicate IR..
const int setMins_pin = 3;             // ... codes so are,therefore...
const int cancel_alarm_pin = 4;        // ... optional.

const int mood_leds_out = 5;           // Output to switch mood LEDs MOSFET
const int alarm_output = 6;            // Output to sound Alarm (if Alalrm is set)

const int blank = 9;                   // Output to HV5812P-G 'BLANK' input.
const int strobe = 10;                 // Output to HV5812P-G 'STROBE' input.

const int IR_pin = A0;                 // Input from TSOP38238 IR receiver.
const int alarm_active = A1;           // Output for 'Alarm is set' LED.
const int LDR_pin = A2;                // Input for LDR voltage measurement.
const int TMP_36 = A3;                 // Optional TMP36 Temperature sensor


#define NUM_DIGITS  6               // Define number of display digits.

#define BLANK_MIN 0                 // Define PWM range day/night to dim VFD.
#define BLANK_MAX 240

#define LDR_MIN 0
#define LDR_MAX 800

#define ALARM_TONE 180              // Define PWM "tone" for Alarm.

#define DISPLAY_TIMEOUT 5000        // Display will revert to showing the Time after this delay if...
                                    // ...set Hours, Minutes or Year key on remote is not pressed.


IRrecv irrecv(IR_pin);

decode_results results;


// Define the bit-pattern for each tube Grid.

const byte grids[6] = {
  B00000001,   // Hx10    or Dx10
  B00000010,   // H       or D
  B00000100,   // M x 10  or Mx10
  B00001000,   // M       or M
  B00010000,   // S x 10  or Yx10
  B00100000    // S       or Y
  }; 


// gfedcba  
const byte numbers[16] = {      // Define the bit-pattern for each chracter and 7-segment number.
  B00111111,    // 0
  B00000110,    // 1                                   
  B01011011,    // 2
  B01001111,    // 3
  B01100110,    // 4
  B01101101,    // 5
  B01111101,    // 6
  B00000111,    // 7
  B01111111,    // 8
  B01101111,    // 9
  B00000000,    // 10 (Blank)
  B01110111,    // 11 (A   Edit Alarm indicator)
  B01100001,    // 12 (c   degrees c indicator)
  B01000000,    // 13 (-   minus indicator)
  B01111000     // 14 (t   Edit Time indicator)
}; 

byte theTemps[6];

byte theTime[6];                       // Each read of the RTC is stored here. Hx10 ... sec. 
byte theAlarm[6];                      // The Alarm time is stored here.
byte theDate[6];                       // The date is stored here

byte ledsOff[6];                       // Mood LEDs OFF time stored here
byte ledsOn[6];                        // Mood LEDs ON time stored here

byte years, months, days, hours, mins, secs;  // Time and Date values read from the RTC.

byte alarmAddressHr = 0;               // EEPROM addresses to save/restore Alarm Hours.
byte alarmAddressMin = 1;
byte moodAddress = 2;                  // EEPROM address to save if mood LEDs are off or on.
byte ledsAddressOffHr = 3;             // EEPROM addresses for timed mood LEDs
byte ledsAddressOffMin = 4;
byte ledsAddressOnHr = 5;
byte ledsAddressOnMin = 6;

byte alarmHours, alarmMins;            // Variables to hold various hours and minutes.
byte ledsOffHours, ledsOffMins;
byte ledsOnHours, ledsOnMins;


unsigned long settingTimer = 0;               // Timer for incrementing hours & minutes at 250ms intervals. 
unsigned long displayTempTimer = 0;
unsigned long displayTimeTimer = 0;           // Timer for displaying time during edit.
unsigned long displayDateTimer = 0;           // Timer for displaying date from IR remote 
unsigned long displayAlarmTimer = 0;          // Timer for displaying temperature from remote
unsigned long cancelAlarm = 0;                // Timer to de-bounce Cancel Alarm button;
unsigned long displayLedsOffTimer = 0;
unsigned long displayLedsOnTimer = 0;

bool alarm_is_set = false;
bool alarm_is_sounding = false;

bool editTime = false;                        // Flags set when appropriate IR code is received.
bool editAlarm = false;
bool editDate = false;
bool showTemp = false;
bool editLedsOff = false;
bool editLedsOn = false;
bool tempReadOnce = false;
bool thisFlag = false;

byte moodLeds = 0;                       // Mood LEDs default is OFF.

int grid = 0;                           // Define first grid to be activated/updated (grid 0 is Hours x 10).


void resetAll() {
 editTime = false;                        // Clear all previous IR flags when a new one is received.
 editAlarm = false;
 editDate = false;
 showTemp = false;
 editLedsOff = false;
 editLedsOn = false;
 tempReadOnce = false; 
}

void setup() {
  
  TCCR1B = (TCCR1B & 0b11111000) | 0x1;          // Set Fast PWM frequency on pin 9 [and 10] (for dimming display)

  Serial.begin(115200);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Enabled IRin");

  SPI.begin();
  
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }  

  pinMode(alarm_active, OUTPUT);
  pinMode(alarm_output, OUTPUT);
  pinMode(mood_leds_out, OUTPUT);
  
  pinMode(setHours_pin, INPUT_PULLUP);
  pinMode(setMins_pin, INPUT_PULLUP);
  pinMode(cancel_alarm_pin, INPUT_PULLUP);
  
  pinMode(strobe, OUTPUT);
  pinMode(blank, OUTPUT);

  analogWrite(blank, BLANK_MIN);                          // Set maximum VFD display brightness

  EEPROM.get(moodAddress, moodLeds);
  digitalWrite(mood_leds_out, moodLeds);
}

void loop() {

 if (showTemp & !tempReadOnce) {
    int reading =  analogRead(TMP_36);
    float voltage = (reading / 1023.0) * 5000;
    int temperature = (int) (voltage - 500) * 0.1;      

    theTemps[0] = 10; // blank
    temperature < 0 ? theTemps[1] = 13 : theTemps[1] = 10;   // minus or blank
    
    theTemps[2] = temperature / 10 % 10;
    theTemps[3] = temperature / 1 % 10;
    
    theTemps[4] = 12; // 'c'
    theTemps[5] = 10; // blank

    tempReadOnce = true;
 }
 
 static int raw;
 static int count;
 int displayBlanking;

 raw = raw + analogRead(LDR_pin);     // Measure ambient light;
 count++;

 if (count >= 20) {
   raw = raw / 20;
   count = 0;
 
   if (moodLeds == 1) {
     displayBlanking = BLANK_MIN;
   } else {
     displayBlanking = constrain(map(raw, LDR_MIN, LDR_MAX, BLANK_MAX, BLANK_MIN), BLANK_MIN, BLANK_MAX);
     raw = 0;
   }
 }

  results.value = 0;                                // Clear last IR Remote code.

  if (irrecv.decode(&results)) {                    // Get IR Remote code, if any.
    Serial.println(results.value, HEX);             // Print value on Serial monitor for use in #defines above.
    irrecv.resume();                                // Get ready to receive the next value.
  } 

  // Enumerate Infrared results and set appropriate flag.

  switch (results.value) {
    case IR_SHOW_MOOD_LEDS:  moodLeds == 0? moodLeds = 1 : moodLeds = 0;
                             digitalWrite(mood_leds_out, moodLeds);
                             EEPROM.put(moodAddress, moodLeds);
                             break;
                             
    case IR_LEDS_OFF:        thisFlag = editLedsOff;                    // Save value of this IR flag
                             resetAll();                                // Reset all flags to 'false'
                             editLedsOff = !thisFlag;                   // Restore value of this flag.
                             displayLedsOffTimer = millis();            // Start display timer.
                             break;
    case IR_LEDS_ON:         thisFlag = editLedsOn;
                             resetAll();
                             editLedsOn = !thisFlag;
                             displayLedsOnTimer = millis();
                             break;
    case IR_ALARM:           alarm_is_set = !alarm_is_set;
                             results.value = 0;
                             break;
    case IR_EDIT_TIME:       thisFlag = editTime;
                             resetAll();
                             editTime = !thisFlag;
                             displayTimeTimer = millis(); 
                             break;
    case IR_EDIT_ALARM:      thisFlag = editAlarm;
                             resetAll();
                             editAlarm = !thisFlag;
                             displayAlarmTimer = millis();
                             break;
    case IR_EDIT_DATE:       thisFlag = editDate;
                             resetAll();
                             editDate = !thisFlag;
                             displayDateTimer = millis();  
                             break;
    case IR_SHOW_TEMP:       thisFlag = showTemp;
                             resetAll();
                             showTemp = !thisFlag;
                             tempReadOnce = false;
                             displayTempTimer = millis();
                             break;
 }
 

 // Enumerate display Timers and reset flag if timed out.

  if (millis() > (displayLedsOffTimer + DISPLAY_TIMEOUT)) {          // Reset IR flag id display timer has timed out.
   editLedsOff = false;
  }  

  if (millis() > (displayLedsOnTimer + DISPLAY_TIMEOUT)) {
    editLedsOn = false;
  }    

  if (millis() > (displayTimeTimer + DISPLAY_TIMEOUT)) {
    editTime = false;
  }

  
  if (millis() > (displayAlarmTimer + DISPLAY_TIMEOUT)) {      
    editAlarm = false;
  } 

  if (millis() > (displayDateTimer + DISPLAY_TIMEOUT)) {      
    editDate = false;
  }

  if (millis() > (displayTempTimer + DISPLAY_TIMEOUT)) {
    showTemp = false;
  }


  if ((digitalRead(cancel_alarm_pin) == LOW) && (millis() > (cancelAlarm + 2000))) {     
    alarm_is_set = !alarm_is_set;
    cancelAlarm = millis();                   
  }

  
  if (alarm_is_set) {
    analogWrite(alarm_active, 255);       // Light LED if alarm is active. 
  }
  else
    analogWrite(alarm_active, 0);

    
  // Get date and time from RTC and Alarm time & Mood LEDs on/off times from EEPROM  

  DateTime now = rtc.now();               // Get time from RTC.
  
  years = now.year() - 2000;
  months = now.month();
  days = now.day();
  hours = now.hour();
  mins = now.minute();
  secs = now.second(); 

  EEPROM.get(alarmAddressHr, alarmHours);          // Get Alarm time from EEPROM.
  EEPROM.get(alarmAddressMin, alarmMins);    
  EEPROM.get(ledsAddressOffHr, ledsOffHours);
  EEPROM.get(ledsAddressOffMin, ledsOffMins); 
  EEPROM.get(ledsAddressOnHr, ledsOnHours);
  EEPROM.get(ledsAddressOnMin, ledsOnMins);   
 
  if (editLedsOff) {
    ledsOff[0] = ledsOffHours / 10;            // Split the hours and minutes into separate
    ledsOff[1] = ledsOffHours % 10;            // digits for displaying on the IV-12 tubes.
    ledsOff[2] = ledsOffMins / 10;
    ledsOff[3] = ledsOffMins % 10;
    ledsOff[4] = 10;
    ledsOff[5] = 10;
  }

  if (editLedsOn) {
    ledsOn[0] = ledsOnHours / 10;
    ledsOn[1] = ledsOnHours % 10;
    ledsOn[2] = ledsOnMins / 10;
    ledsOn[3] = ledsOnMins % 10;
    ledsOn[4] = 10;
    ledsOn[5] = 10;
  }

  if (editAlarm) {
    theAlarm[0] = alarmHours / 10;
    theAlarm[1] = alarmHours % 10;
    theAlarm[2] = alarmMins / 10;
    theAlarm[3] = alarmMins % 10;
    theAlarm[4] = 10;                   //'Blank' (All Segments Off)
    theAlarm[5] = 11;                   //'A'  (Alarm Time)
  }


  theTime[0] =  hours / 10;               
  theTime[1] =  hours % 10;             
  theTime[2] =  mins / 10;
  theTime[3] =  mins % 10; 

  if (editTime) {
    theTime[4] = 10;  // 'Blank'
    theTime[5] = 14;  // 't'           // If editing the time, show a 't'...
  } else {                             // ... instead of seconds.
    theTime[4] = secs / 10;
    theTime[5] = secs % 10;
  } 

  if (editDate) {
    theDate[0] = days / 10;
    theDate[1] = days % 10;
    theDate[2] = months / 10;
    theDate[3] = months % 10;
    theDate[4] = years / 10;
    theDate[5] = years % 10;
  }

  // If leds Off time and leds On time are different, check if either matches
  // the current hours and minutes and, if they match, set mood LEDs accordingly!

  if ((ledsOffHours != ledsOnHours) || (ledsOffMins != ledsOnMins)) {

    if ((hours == ledsOffHours) && (mins == ledsOffMins) & (secs < 2)) {
      moodLeds = 0;
      digitalWrite(mood_leds_out, moodLeds);
    }
    if ((hours == ledsOnHours) && (mins == ledsOnMins) & (secs < 2)) {
      moodLeds = 1;
      digitalWrite(mood_leds_out, moodLeds);
    }
    
  }
  

  // Sound the Alarm if times match

  if (((hours == alarmHours) && (mins == alarmMins) && (secs < 2) & alarm_is_set) || alarm_is_sounding) {
    analogWrite(alarm_output, ALARM_TONE);
    alarm_is_sounding = true;
  };

  if (!alarm_is_set) {
    analogWrite(alarm_output, 0);
    alarm_is_sounding = false;
  }

  // Enumerate all the IR flags. If set to 'true', test IR results for hours and minutes up and down

 if (editLedsOff) {
    if (results.value == IR_HOURS_UP) {    //Set Hour
      ledsOffHours++;
      if (ledsOffHours >= 24) ledsOffHours = 0;
      ledsOff[0] = ledsOffHours / 10;
      ledsOff[1] = ledsOffHours % 10;

      EEPROM.put(ledsAddressOffHr, ledsOffHours);
      displayLedsOffTimer = millis();
    }

    if (results.value == IR_HOURS_DOWN) {    //Set Hour
      ledsOffHours--;
      if (ledsOffHours < 0) ledsOffHours = 23;
      ledsOff[0] = ledsOffHours / 10;
      ledsOff[1] = ledsOffHours % 10;

      EEPROM.put(ledsAddressOffHr, ledsOffHours);
      displayLedsOffTimer = millis();
    }    

    if (results.value == IR_MINUTES_UP) {   // Set Minute
      ledsOffMins++;
      if (ledsOffMins >= 60) ledsOffMins = 0;
      ledsOff[2] = ledsOffMins / 10;
      ledsOff[3] = ledsOffMins % 10;
 
      EEPROM.put(ledsAddressOffMin, ledsOffMins);
      displayLedsOffTimer = millis(); 
    }

    if (results.value == IR_MINUTES_DOWN) {   // Set Minute
      ledsOffMins--;
      if (ledsOffMins < 0) ledsOffMins = 23;
      ledsOff[2] = ledsOffMins / 10;
      ledsOff[3] = ledsOffMins % 10;
 
      EEPROM.put(ledsAddressOffMin, ledsOffMins);
      displayLedsOffTimer = millis(); 
    }    
  }

  else if (editLedsOn) {
    if (results.value == IR_HOURS_UP) {    //Set Hour
      ledsOnHours++;
      if (ledsOnHours >= 24) ledsOnHours = 0;
      ledsOn[0] = ledsOnHours / 10;
      ledsOn[1] = ledsOnHours % 10;

      EEPROM.put(ledsAddressOnHr, ledsOnHours);
      displayLedsOnTimer = millis();
    }

    if (results.value == IR_HOURS_DOWN) {    //Set Hour
      ledsOnHours--;
      if (ledsOnHours < 0) ledsOnHours = 23;
      ledsOn[0] = ledsOnHours / 10;
      ledsOn[1] = ledsOnHours % 10;

      EEPROM.put(ledsAddressOnHr, ledsOnHours);
      displayLedsOnTimer = millis();
    }    

    if (results.value == IR_MINUTES_UP) {   // Set Minute
      ledsOnMins++;
      if (ledsOnMins >= 60) ledsOnMins = 0;
      ledsOn[2] = ledsOnMins / 10;
      ledsOn[3] = ledsOnMins % 10;
 
      EEPROM.put(ledsAddressOnMin, ledsOnMins);
      displayLedsOnTimer = millis(); 
    }

    if (results.value == IR_MINUTES_DOWN) {   // Set Minute
      ledsOnMins--;
      if (ledsOnMins < 0) ledsOnMins = 23;
      ledsOn[2] = ledsOnMins / 10;
      ledsOn[3] = ledsOnMins % 10;
 
      EEPROM.put(ledsAddressOnMin, ledsOnMins);
      displayLedsOnTimer = millis(); 
    }    
  }  

  else if (editAlarm) {
    if (results.value == IR_HOURS_UP) {    //Set Hour
      alarmHours++;
      if (alarmHours >= 24) alarmHours = 0;
      theAlarm[0] = alarmHours / 10;
      theAlarm[1] = alarmHours % 10;

      EEPROM.put(alarmAddressHr, alarmHours);
      displayAlarmTimer = millis();
    }

    if (results.value == IR_HOURS_DOWN) {    //Set Hour
      alarmHours--;
      if (alarmHours < 0) alarmHours = 23;
      theAlarm[0] = alarmHours / 10;
      theAlarm[1] = alarmHours % 10;

      EEPROM.put(alarmAddressHr, alarmHours);
      displayAlarmTimer = millis();
    }    

    if (results.value == IR_MINUTES_UP) {   // Set Minute
      alarmMins++;
      if (alarmMins >= 60) alarmMins = 0;
      theAlarm[2] = alarmMins / 10;
      theAlarm[3] = alarmMins % 10;
 
      EEPROM.put(alarmAddressMin, alarmMins);
      displayAlarmTimer = millis(); 
    }

    if (results.value == IR_MINUTES_DOWN) {   // Set Minute
      alarmMins--;
      if (alarmMins < 0) alarmMins = 23;
      theAlarm[2] = alarmMins / 10;
      theAlarm[3] = alarmMins % 10;
 
      EEPROM.put(alarmAddressMin, alarmMins);
      displayAlarmTimer = millis(); 
    }    
  }

  else if (editDate) {       // If date/timeflag is set, set the date.
    if  (results.value == IR_HOURS_UP){    //Set Day
      days++;
      if (days > 31) days = 1;
      theDate[0] = days / 10;
      theDate[1] = days % 10;

      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, secs));   // Retain existing seconds value.
      displayDateTimer = millis();
    }

    if  (results.value == IR_HOURS_DOWN){    //Set Day
      days--;
      if (days < 1) days = 31;
      theDate[0] = days / 10;
      theDate[1] = days % 10;

      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, secs));   // Retain existing seconds value.
      displayDateTimer = millis();
    }
  
    if  (results.value == IR_MINUTES_UP) {    // Set Month
      months++;
      if (months >= 13) months = 1;
      theDate[2] = months / 10;
      theDate[3] = months % 10;
 
      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, 0));  // Reset seconds to zero when minutes are set.
      displayDateTimer = millis();
    }
    if  (results.value == IR_MINUTES_DOWN) {    // Set Month
      months--;
      if (months < 1) months = 12;
      theDate[2] = months / 10;
      theDate[3] = months % 10;
 
      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, 0));  // Reset seconds to zero when minutes are set.
      displayDateTimer = millis();
    }
    

    if (results.value == IR_YEAR_UP) {                        // 
      years++;
      if (years > 99) years = 0;
      theDate[4] = years / 10;
      theDate[5] = years % 10;
      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, 0));
      displayDateTimer = millis();
    }
    if (results.value == IR_YEAR_DOWN) {
      years--;
      if (years < 0) years = 99;
      theDate[4] = years / 10;
      theDate[5] = years % 10;
      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, 0));
      displayDateTimer = millis();
    }
  }                              

  else if ((editTime) ||                              // If Edit Time flag (from IR) is set, set the Time.
          (digitalRead(setHours_pin) == LOW) ||       // Manual buttons can set the time without setting IR edit mode.
          (digitalRead(setMins_pin) == LOW)) {                            
    if ((results.value == IR_HOURS_UP) ||
       ((digitalRead(setHours_pin) == LOW) && (millis() > (settingTimer + 250)))){
      hours++;
      if (hours >= 24) hours = 0;
      theTime[0] = hours / 10;
      theTime[1] = hours % 10;

      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, secs));   // Retain existing seconds value.
      displayTimeTimer = millis();  
      settingTimer = millis();  
    }

    if  (results.value == IR_HOURS_DOWN) {
      hours--;
      if (hours < 0) hours = 23;
      theTime[0] = hours / 10;
      theTime[1] = hours % 10;

      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, secs));   // Retain existing seconds value.
      displayTimeTimer = millis();  
      settingTimer = millis();  
    }
    

    if ((results.value == IR_MINUTES_UP) ||
       ((digitalRead(setMins_pin) == LOW) && (millis() > (settingTimer + 250)))) {
      mins++;
      if (mins >= 60) mins = 0;
      theTime[2] = mins / 10;
      theTime[3] = mins % 10;

      secs = 0;                                           // Reset seconds to zero when minutes are set.
      theTime[4] = secs / 10;
      theTime[5] = secs % 10;

      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, secs));  
      displayTimeTimer = millis();
      settingTimer = millis();
    }

    if (results.value == IR_MINUTES_DOWN) {
      mins--;
      if (mins < 0) mins = 59;
      theTime[2] = mins / 10;
      theTime[3] = mins % 10;

      secs = 0;                                           // Reset seconds to zero when minutes are set.
      theTime[4] = secs / 10;
      theTime[5] = secs % 10;

      rtc.adjust(DateTime(years + 2000, months, days, hours, mins, secs));  
      displayTimeTimer = millis();
      settingTimer = millis();
    }
  }

  // Depending on which IR flag is set (if any) display appropriate values on IV-12 tubes.

  analogWrite(blank, 255);                              // Blank display while updating registers

  if (editLedsOff) {
    show(ledsOff);
  }
  else if (editLedsOn) {
    show(ledsOn);
  }
  else if (showTemp)  {
    show(theTemps);
  }
  else if (editAlarm) {
    show(theAlarm);
  }
  else if (editDate) {
    show(theDate);
  }
  else
    show(theTime);

 analogWrite(blank, displayBlanking);                     // Set display brightness according to LDR value.
   
   
  grid++;                                                 // Advance to the next grid (ie next tube) next time around.
  if (grid > (NUM_DIGITS - 1)) grid = 0;                  // Grids  are 0 to 5.
  
}

void show(byte theDisplay[]) {
  digitalWrite(strobe, LOW);
  SPI.transfer(grids[grid]);
  SPI.transfer(numbers[theDisplay[grid]]);
  digitalWrite(strobe, HIGH);   
}



 

Back to Index | Page 1 | Page 2 | Page 3 | Page 5 | Page 5