Clock (Hours and Mins) Project

The clock consists of digits 1 to 12 being lit up (the hours), and 00 to 55 being lit up (the minutes), the board would be controlling 24 relays to turn on a much bigger power supply to control the lights. The relays are latching so I would have to pulse them rather than keep them on.

Using an interrupt and you are done. I wrote the following piece for some other purpose but it can be easily repurposed here:

//unsigned long _timer1_period=0;  //timer period, in seconds
unsigned long _timer1_counter=0;  //timer1 counter
struct {
  unsigned char hour;
  unsigned char minute;
  unsigned char second;
} mytime;

//timer1 isr
ISR(TIMER1_OVF_vect) {
  _timer1_counter+=0x10000ul;   //increment timer_counter
  if (_timer1_counter >=F_CPU) {
    _timer1_counter -= F_CPU;    //reset timer_counter
    mytime.second+=1; //increment the seconds
    if (mytime.second >=60) {
      mytime.second -= 60; //reset seconds
      mytime.minute += 1; //increment the minute
      if (mytime.minute>=60) {
        mytime.minute -= 60;  //reset minute
        mytime.hour += 1;
      }
    }
  }
}

//initialize the timer
//to expire in user-specified period of time
void tmr1_init(void) {
  _timer1_counter = 0;            //reset timer1 counter
  mytime.hour = mytime.minute = mytime.second = 0;//reset mytime
  TCCR1B = 0x00;                //turn off the timer
  TCCR1A = 0x00;                //normal portion operation
  TCNT1 = 0;                    //reset the timer
  TIFR1 |= (1<<TOV1);            //clear the timer flag
  TCCR1B = 0x01;                //turn on the timer, 1:1 prescaler
  TIMSK1 |= (1<<TOIE1);        //enable the timer interrupt
  sei();                      //enable global interrupt
}

In your code, you will just set it up and test it:

void setup(void) {
  ...
  tmr1_init(); //reset the timer and get it started
}

void loop(void) {
  if (mytime is mydesiredtime) {
    //do something
  }
}

The clock consists of digits 1 to 12 being lit up (the hours), and 00 to 55 being lit up (the minutes), the board would be controlling 24 relays to turn on a much bigger power supply to control the lights. The relays are latching so I would have to pulse them rather than keep them on.

Do you really need relays? could the digits be illuminated by LED's. Sounds a bit like a word clock http://arduino.cc/forum/index.php/topic,118338.0.html but using digits.

Thank you for the quick reply PaulS :slight_smile:

So the Arduino would set the start time (by buttons) on the RTC, then the RTC would count the time for the Arduino, and then it sorts out what time to put on?

Thank you for the advice

dhenry - Thank you very much for that code, i'll have a proper read over it, trying to understand all the different parts :slight_smile:

Riva - I was planning on using el wire rather than LEDs, I didn't think the board could supply that much power, or am I completely wrong? But yes it is sort of like a word clock.

Thank you all for the quick replies :slight_smile:

So the Arduino would set the start time (by buttons) on the RTC, then the RTC would count the time for the Arduino, and then it sorts out what time to put on?

If that final it refers to the Arduino, rather than the RTC, then yes.

Yep, thank you Paul, shall be ordering one of them ASAP.

And Riva that word clock looks fantastic!

You might try this code. I have found my crystal equipped duemilanova tracks the time really well.
http://www.time.gov/timezone.cgi?Eastern/d/-5/java
Download this, with the time set a minute or so ahead, then open the serial monitor when the time is about 2-3 seconds ahead of where you set it.
For example, I set mine for 9:26, uploaded to the board, and at 9:25:57 I opened the serial monitor, which reset the board with a time at 9:26.
When I have run this in the past I did not see it drifting at all.

// time display test

unsigned long currentmicros = 0;
unsigned long previousmicros = 0;
unsigned long interval = 10000;

byte tens_hours = 0;  // enter the time here, add in reading some buttons to make it standalone/adjustable
byte ones_hours = 9;
byte tens_minutes = 2;
byte ones_minutes = 6;
byte tens_seconds = 0;
byte ones_seconds = 0;
byte tenths = 0;
byte hundredths= 0;

byte prior_seconds = 0;

void setup()

{
  Serial.begin(57600);
}

void loop()

{

  currentmicros = micros(); // read the time.

  while (currentmicros - previousmicros >= interval) // 10 milliseconds have gone by

  {

    hundredths = hundredths +1;

    if (hundredths == 10){
      hundredths = 0;
      tenths = tenths +1;
    }

    if (tenths == 10){
      tenths = 0;
      ones_seconds = ones_seconds +1;
    }

    if (ones_seconds == 10){
      ones_seconds = 0;
      tens_seconds = tens_seconds +1;
    }

    if (tens_seconds == 6){
      tens_seconds = 0;
      ones_minutes = ones_minutes +1;
    }

    if (ones_minutes == 10){
      ones_minutes = 0;
      tens_minutes = tens_minutes +1;
    }

    if (tens_minutes == 6){
      tens_minutes = 0;
      ones_hours = ones_hours +1;
    }

    if (ones_hours == 10){
      ones_hours = 0;
      tens_hours = tens_hours +1;
    }
    if (tens_hours == 3){
      tens_hours = 0;
    }

    previousmicros = previousmicros + interval; // update for the next comparison

  }

  // counters are all updated now,

  if (prior_seconds != ones_seconds){

    Serial.print (tens_hours, DEC);
    Serial.print (" ");
    Serial.print (ones_hours, DEC);
    Serial.print (" : ");

    Serial.print (tens_minutes, DEC);

    Serial.print (" ");

    Serial.print (ones_minutes, DEC);

    Serial.print (" : ");

    Serial.print (tens_seconds, DEC);

    Serial.print (" ");

    Serial.println (ones_seconds, DEC);


    prior_seconds = ones_seconds;
  }

} // end void loop

CrossRoads:
You might try this code. I have found my crystal equipped duemilanova tracks the time really well.

So when you say crystal, is that different to a RTC? Also thank you for the code, is it supposed to run an LCD?

No, the onboard clock source - an actual crystal vs a resonator. Vs an RTC, which is a seperate chip with its own crystal. DS1307 is one chip, I2C interface and uses 32.768KHz crystal. Ohers are DS3231 & DS3234, both are somewhat larger chips but have built-in crystal and supposedly more accurate.

This was just test code, so it only outputs to the serial monitor.
Would be straightforward to output to an LCD, replace the serial print calls with LCD calls.

So the Arduino would set the start time (by buttons) on the RTC

You can use a rtc but it is really not need for your application: the main crystal does an excellent job keeping time, if you code it so.

You can use a rtc but it is really not need for your application: the main crystal does an excellent job keeping time, if you code it so.

On the other hand, if the clock/Arduino ever looses power, you get to reset the time again. An RTC has a battery backup, so it isn't necessary to reset it.

Relays will be noisy, quite expensive (given the number you require and the fact that they will all need drivers) and unreliable in the long term. Why not use opto triacs instead, like this board https://www.sparkfun.com/products/11323 does?

PaulS:
On the other hand, if the clock/Arduino ever looses power, you get to reset the time again. An RTC has a battery backup, so it isn't necessary to reset it.

Going on that I think it's the best choice.

dc42:
Relays will be noisy, quite expensive (given the number you require and the fact that they will all need drivers) and unreliable in the long term. Why not use opto triacs instead, like this board https://www.sparkfun.com/products/11323 does?

Unfortunately I live in the UK, I could only find them for US sale? Plus I already won 50 relays off ebay... so there isn't a problem on price, and they're latching so I don't need to have a current flowing through them, just need to pulse them, so I'm assuming there will be no noise... What do I need the drivers for? Thanks again everyone :slight_smile:

Of course you can buy opto triacs in the UK, see e.g. http://uk.farnell.com/vishay/vo2223a-x001/phototriac-power-dip-6-0-9a/dp/1870799.

How much voltage and current do your latching relays need? The Arduino has a current limit of 40mA per pin, plus a per-chip limit (e.g. 200mA total Vcc or ground current for the Uno).

Thank you very much for pointing me in the right direction, so I'd need 24 of them? And I only just got the relays, they were listed at 4.2V-6V, but didn't mention current and I haven't had a chance to test them... I found some on a website and they said they'd work with Arduino boards though :slight_smile:

If you have a multimeter, measure the resistance of a relay coil, then you can work out the current @ 5V (Ohms's Law). If it's less than 40mA then you can drive it directly from an Arduino pin - although you must connect a diode in parallel with the coil to absorb the back emf when you turn it off.

I've got my clock code fixed. It actually tracks time correctly now - was 6 hours off this morning! Finally realized I reset the hours when time rolled over at 30:00 instead of 24:00 - oops!

Running again now, made it past midnight okay. Running in sync since I reset it around 7:00pm.

unsigned long currentmicros = 0;
unsigned long nextmicros = 0;
unsigned long interval = 10000;

byte tens_hours = 1;
byte ones_hours = 8;
byte tens_minutes = 5;
byte ones_minutes = 4;
byte tens_seconds = 3;
byte ones_seconds = 0;
byte tenths = 0;
byte hundredths= 0;

byte prior_seconds = 0;

void setup()

{
  Serial.begin(57600);
  nextmicros = micros();
}

void loop()

{

  currentmicros = micros(); // read the time.

  if ((currentmicros - nextmicros) >= interval) // 10 milliseconds have gone by

  {

    hundredths = hundredths +1;

    if (hundredths == 10){
      hundredths = 0;
      tenths = tenths +1;
    }

    if (tenths == 10){
      tenths = 0;
      ones_seconds = ones_seconds +1;
    }

    if (ones_seconds == 10){
      ones_seconds = 0;
      tens_seconds = tens_seconds +1;
    }

    if (tens_seconds == 6){
      tens_seconds = 0;
      ones_minutes = ones_minutes +1;
    }

    if (ones_minutes == 10){
      ones_minutes = 0;
      tens_minutes = tens_minutes +1;
    }

    if (tens_minutes == 6){
      tens_minutes = 0;
      ones_hours = ones_hours +1;
    }

    if (ones_hours == 10){
      ones_hours = 0;
      tens_hours = tens_hours +1;
    }
    if ((tens_hours == 2) && (ones_hours == 4)){
      ones_hours = 0;
      tens_hours = 0;
    }

    nextmicros = nextmicros + interval; // update for the next comparison

  }  // end time interval check

  // counters are all updated now, send to display

  if (prior_seconds != ones_seconds){

    Serial.print (tens_hours, DEC);
    Serial.print (" ");
    Serial.print (ones_hours, DEC);
    Serial.print (" : ");
    Serial.print (tens_minutes, DEC);
    Serial.print (" ");
    Serial.print (ones_minutes, DEC);
    Serial.print (" : ");
    Serial.print (tens_seconds, DEC);
    Serial.print (" ");
    Serial.println (ones_seconds, DEC);

    prior_seconds = ones_seconds;   // show time update once/second
  }  // end one second passing check
  
  // do other stuff in the meantime ...

} // end void loop

Sorry for the slow reply, been away and didn't have an internet connection...

dc42:
If you have a multimeter, measure the resistance of a relay coil

Tried it and got a value of 1, which can't be right... So I'm not sure what to do about that. Should I be checking while it's switching? Or is just putting a multimeter across it okay? Sorry for my poor knowledge on this...

Thanks again CrossRoads, I am trying my hardest to understand what is going on, fear I may have jumped in at the deep end...

I understand all the if's apart from the last two

if (ones_hours == 10){
ones_hours = 0;
tens_hours = tens_hours +1;

why can't it equal 12? And then for turning all my relays on would I just write something like,

if 10< x <15 turn led10 on...

I know that's not how you'd code it but is that what replace the serial.print?

Thanks again :slight_smile:

Tried it and got a value of 1, which can't be right... So I'm not sure what to do about that. Should I be checking while it's switching? Or is just putting a multimeter across it okay? Sorry for my poor knowledge on this...

You have to measure the relay coil resistance 'out of circuit', meaning no other wires (or diode) attached to the relay coil, just the multimeter leads across the relay coil terminals.

Lefty

I didn't test for 12 because I track the value of each digit seperately so they can be each be displayed on their own 7-segment display.
You will have a digit for 10, 11, and 12? Then test for those and rollover when you hit 13.