Tick Tock Another Binary Clock

Hello world. Right i have been slowly teaching my self through different projects and have hit a bit of a mental break down on the best way to achieve what i want from my project.

I am building a Binary clock using an atmega328p on a breadboard for now, then the hope is to move it forward to a full working pocket watch once i am happy with the prototype.

Now the problem is power consumption of the LEDS and the watch lasting for a reasonable time.

I Know this can be done by making the 328 carry on counting time but to switch off the LEDS say 30 seconds after a switch is activated like a push button or when i open the watch case.

Now my problem is with the best way to go about this with out using 'if' statements too much and slowing the clock down and losing time.

This is the code so far.... and any suggestions would be more than appreciated in solving my problem and even if code is the right way to do this and if not maybe a better hardware solution is out there?

// CSM
// binary clock code V1.2, on atmega328p-pu breadboard.

#include <Time.h> // Using the basic Time library

int hourLEDs[] = {1, 2, 3, 4}; // Hours LED  
int minuteLEDs[] = {10, 9, 8, 7, 6, 5}; // Minutes LED
int secondLEDs[] = {16, 15, 14, 13, 12, 11}; // Seconds LED

int loopLEDs[] = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; // The order in which to spin the LEDS

int switchPin = 17 ; // Used for setting the time, hold to advance time

void setup()       
{
  for (int i = 0; i < 4; i++)
  {
     pinMode(hourLEDs[i], OUTPUT); 
  }
  for (int i = 0; i < 6; i++)
  {
     pinMode(minuteLEDs[i], OUTPUT); 
  }
  for (int i = 0; i < 6; i++)
  {
     pinMode(secondLEDs[i], OUTPUT); 
  }
  setTime(0);
}

void loop()                     
{
  if (digitalRead(switchPin))
  {
     adjustTime(1);
  }
  else if (minute() == 0 && second() == 0)
  {
    spin(hour());
  }
  updateDisplay();
  delay(1);
}

void updateDisplay()
{
  time_t t = now();
  setOutput(hourLEDs, 4, hourFormat12(t));
  setOutput(minuteLEDs, 6, minute(t));
  setOutput(secondLEDs, 6, second(t));
}


void setOutput(int *ledArray, int numLEDs, int value)
{
    for (int i = 0; i < numLEDs; i++)
    {
     digitalWrite(ledArray[i], bitRead(value, i)); 
    }
}


void spin(int count)
{
  for (int i = 0; i < count; i++)
  {
      for (int j = 0; j < 16; j++)
      {
         digitalWrite(loopLEDs[j], HIGH);
         delay(50);
         digitalWrite(loopLEDs[j], LOW);
      }
  } 
}

Many Thanks

monsteryeti:
Now my problem is with the best way to go about this with out using 'if' statements too much and slowing the clock down and losing time.

The time library keeps track of the time using an interrupt. Your code will have very little impact on it losing track of time. You might miss updating the seconds display by a few hundred miliseconds, but us slow humans won't notice.

The most power efficient and accurate way to keep track of time is to use a RTC like the DS1307 or DS3231 (more expensive but much more accurate). That way you can put your 328 to sleep and wake it up every so often.

Using delay() does not save you any power.

Supply the current with external hardware.

Thanks for your quick reply, im looking into the RTC method and putting the 328 to sleep my only problem now is i only have Digital pin 0 (RX) Free after using the last to analog inputs 4-5 for the RTC. Would i be able to make an interrupt to wake with this pin or by moving others around? any suggestions welcome?

According to the datasheets, Pin change interrupts can be used to wake from sleep, which means you can use Digital Pin 0 to wake from power down and sleep modes.
Digital0 is PCINT16 (pin change interrupt source 16). Which means its interrupt can be enabled with:

  PCMSK2 = _BV(0); //set PCINT16 as enabled, others disabled
  PCICR |= _BV(2); //enable pin change interrupt source 2.

And disabled with:

  PCICR &= ~_BV(2); //disable pin change interrupt source 2.

And if needed, the corresponding interrupt routine is:

ISR(PCINT2_vect){
  //code executed on pin change.
}

Cheers Tom for the quick reply and fast response i have a RTC on order now and going to give the sleep on Digital pin 0 a go later tonight. is it just a matter of pulling the pin to GND or do i need to do a bit more research and reading on how to wire up an interrupter on a digital pin?

Thanks again

Basically to trigger the uC to wake up, you have to cause an interrupt. To make a pin change interrupt occur, you need to simply toggle the logic state of the pin.
You can do that in a number of ways:
(1) add an external pullup resistor, then to wake up, simply pull the pin to ground with a switch.
(2) add an external pulldown resistor, then to wake up, simply connect the pin to +5v with a switch.
(3) If you went for a DS1307 based RTC, then you could connect its SQW output to Digital 0, and configure the DS1307 to output 1Hz. That way the microcontroller gets woken up once every second.

The third method would seem to me to be an ideal solution. You can put the arduino to sleep. Then when it is woken back up by the DS1307, you can read in the current time, output it to the clock display, then put the arduino back to sleep.
That way the arduino would sleep saving power for most of the time, but the clock would update once every second. You could probably accomplish reading in the time and updating the clock within a few milliseconds, meaning the arduino would sleep for about 99% of the time.

Edit:

I have just noticed you are trying to have the clock automatically turn off the display, then turn it back on when the user presses a switch or something. In which case use method (1) or (2) of those i mentioned in the last post. If you make the external resistor something like 10k to 100k.

Great i will have a go with ether method one or two and see how it plays out. Thanks again for your help tom, hope i can get this all togethere and running this is my 3-4th project now and would like to get it portable and battery powered maybe so thats the next step after getting this section of it working and i think you have set me in the right direction.

Cheers