help fine-tuning LED binary clock

OK, so this is my first real project. It's a binary clock -- not BCD, mind you, but "true" binary. So, the first bit is half days, the second bit is quarter days, then eighths, etc. Here's an example: Abulsme True Binary Time
I set this up on a breadboard with 10 LEDs but would like eventually to expand it to a 4x4 matrix with a demuxer.
I thought that this would be pretty straight-forward, but the clock seems to be gaining about 6min/day. I've poked around on the forums here and heard a that this is normal because the Uno uses a ceramic rather than a crystal resonator. So, there are two ways to go about fixing it: Hardware -- get a RTC with a crystal resonator ; or Software -- measure the inaccuracy and compensate for it in the code.

Which route should I take? Would I even be able to use a RTC with this thing since it doesn't use HH:MM:SS? Or if I go the software route, ??? Could someone talk me through that? And maybe dumb it down a little for a novice?

Here's my code. Thanks!

const int LED1 = 4;
const int LED2 = 5;
const int LED3 = 6;
const int LED4 = 7;
const int LED5 = 8;
const int LED6 = 9;
const int LED7 = 10;
const int LED8 = 11;
const int LED9 = 12;
const int LED10 = 13;

int LEDState1 = LOW;
int LEDState2 = LOW;
int LEDState3 = LOW;
int LEDState4 = LOW;
int LEDState5 = LOW;
int LEDState6 = LOW;
int LEDState7 = LOW;
int LEDState8 = LOW;
int LEDState9 = LOW;
int LEDState10 = LOW;

long previousMillis1 = 0;
long previousMillis2 = 0;
long previousMillis3 = 0;
long previousMillis4 = 0;
long previousMillis5 = 0;
long previousMillis6 = 0;
long previousMillis7 = 0;
long previousMillis8 = 0;
long previousMillis9 = 0;
long previousMillis10 = 0;

long interval1 = 43200000;
long interval2 = 21600000;
long interval3 = 10800000;
long interval4 = 5400000;
long interval5 = 2700000;
long interval6 = 1350000;
long interval7 = 675000;
long interval8 = 337500;
long interval9 = 168750;
long interval10 = 84375;

void setup() {
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(LED7, OUTPUT);
  pinMode(LED8, OUTPUT);
  pinMode(LED9, OUTPUT);
  pinMode(LED10, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis1 > interval1) {
    previousMillis1 = currentMillis;
    
    if (LEDState1 == LOW)
      LEDState1 = HIGH;
    else
      LEDState1 = LOW;
      
    digitalWrite(LED1, LEDState1);
  }
  
  if(currentMillis - previousMillis2 > interval2) {
    previousMillis2 = currentMillis;
    
    if (LEDState2 == LOW)
      LEDState2 = HIGH;
    else
      LEDState2 = LOW;
      
    digitalWrite(LED2, LEDState2);
  }
  
  if(currentMillis - previousMillis3 > interval3) {
    previousMillis3 = currentMillis;
    
    if (LEDState3 == LOW)
      LEDState3 = HIGH;
    else
      LEDState3 = LOW;
      
    digitalWrite(LED3, LEDState3);
  }
  
  if(currentMillis - previousMillis4 > interval4) {
    previousMillis4 = currentMillis;
    
    if (LEDState4 == LOW)
      LEDState4 = HIGH;
    else
      LEDState4 = LOW;
      
    digitalWrite(LED4, LEDState4);
  }
  
  if(currentMillis - previousMillis5 > interval5) {
    previousMillis5 = currentMillis;
    
    if (LEDState5 == LOW)
      LEDState5 = HIGH;
    else
      LEDState5 = LOW;
      
    digitalWrite(LED5, LEDState5);
  }
  
  if(currentMillis - previousMillis6 > interval6) {
    previousMillis6 = currentMillis;
    
    if (LEDState6 == LOW)
      LEDState6 = HIGH;
    else
      LEDState6 = LOW;
      
    digitalWrite(LED6, LEDState6);
  }
  
  if(currentMillis - previousMillis7 > interval7) {
    previousMillis7 = currentMillis;
    
    if (LEDState7 == LOW)
      LEDState7 = HIGH;
    else
      LEDState7 = LOW;
      
    digitalWrite(LED7, LEDState7);
  }
  
  if(currentMillis - previousMillis8 > interval8) {
    previousMillis8 = currentMillis;
    
    if (LEDState8 == LOW)
      LEDState8 = HIGH;
    else
      LEDState8 = LOW;
      
    digitalWrite(LED8, LEDState8);
  }
  
  if(currentMillis - previousMillis9 > interval9) {
    previousMillis9 = currentMillis;
    
    if (LEDState9 == LOW)
      LEDState9 = HIGH;
    else
      LEDState9 = LOW;
      
    digitalWrite(LED9, LEDState9);
  }
  
  if(currentMillis - previousMillis10 > interval10) {
    previousMillis10 = currentMillis;
    
    if (LEDState10 == LOW)
      LEDState10 = HIGH;
    else
      LEDState10 = LOW;
      
    digitalWrite(LED10, LEDState10);
  }
}

RTC will be far, far simpler since you'll otherwise need a reference clock of some form to work against. You can estimate based on the time on the RTC, and it looks like at 16 bits, each bit is about 1.32s. Most RTCs will give you at least 10ms precision.

Or you could resync with a GPS every day.

Use a RTC and make your life simple.

The DS1307 is popular. I hate it, when used on battery. While powered it'll gain or lose 1-2 seconds per day. While on battery it'll lose minutes per day (and never gain).

The DS3231, on the other hand, is one of the most rock solid RTCs I've ever used. Little more expensive, but well worth it in my opinion.

I second the ds3231 suggestion. RTCs give you the time in BCD, but converting back to binary is easy.

Your sketch is not bad but has scope for improvement. How will this 4x4 matrix display the time?

Paul

RTCs like the DS1307 and DS3231 output a square wave at 1 Hz, which you could count on an input pin instead of milliseconds. That would require changing only a few timing constants in your code -- even fewer if you defined just one timing constant and calculated all the rest from it.

Indeed the DS3231 is a vast improvement over the DS1307.