LED clock with different time speed

I am new to this and need some guidance where to start.
I am doing a project for an exhbition where I want to use 4 digit 7 segments LED displays to display time. The time is supposed to be running too fast (double or triple normal time or so) until someone interacts and normal time (and speed) is shown.

I have found some resources how to display time but how do I plan the project so that I get the normal time displayed with the input?

I have an Arduino Duemilanove..

Thankful for any advice.

Reading an input and changing the speed which the time is displayed/counted is easy.

Most of the effort here will be interfacing with the LEDs and counting time properly. Figure this much out and the rest will be obvious.

We need to know a bit more...

Do you need to show the correct time?

What will the speeded up time show, and will the time go back to "correct" when someone interacts?

Do you need the time to be accurate?

Does the Arduino need to automatically know the time at power up, or are you happy to set it every time you turn it on?

What speed are you showing?

Correct time needs to be shown (when in normal speed).
When the time is speeded up you need to notice that it is going too fast so I guess maybe 120 times quicker than normal is okay.
On a second thought, maybe I need 6 digits to include seconds. That way it is easier to see that the clock is going too fast.

Yes, the time needs to go back to correct time when someone interacts.

The time can be reset once a day if needed at startup.

Thanks.

So pretty simple then, you don't need an RTC, just roll your own,

I would organize a 1/nth-second timer and two counters that count modulo 60/60/24. Then every 1/nth of a second update one counter (this is you fast counter) and every n interrupts update the other one (the real time counter).

So now we have two counters running counting H:M:S but one is n times faster than the other.

When someone interacts with the device set a flag (and possibly reset the fast counter with the value from the real time counter, depends on what you want to show)

Write a routine to display a "time", it gets called every nth of a second, it tests the flag and either displays the fast or slow counter.

That's pretty much it I think, plus of course you have to be able to set the time so that will need a few buttons, dip switches or something.

Feels great that you are saying its pretty simple :slight_smile:

I'll give it a try and see how far I manage...
Thanks

This is what I have now. Probably not the best way of making it but it works with the counting...
I tried to follow graynomad's advice but now this is what I have.

I want it to count slower (speed = 1000) when a button is pressed. I have tried to change the code so it would just change the delay to 1000 and also just made a copy of the whole loop more or less with a longer delay but nothing works.

Can somebody help how I can make it work?

*/
int latchpin3 = 8; // connect to pin 12 on the second'595
int clockpin3 = 12; // connect to pin 11 on the second'595
int datapin3 = 11; // connect to pin 14 on the second'595
int latchpin2 = 5; // connect to pin 12 on the minute'595
int clockpin2 = 7; // connect to pin 11 on the minute'595
int datapin2 = 6; // connect to pin 14 on the minute'595
int latchpin1 = 3; // connect to pin 12 on the hour'595
int clockpin1 = 9; // connect to pin 11 on the hour'595
int datapin1 = 4; // connect to pin 14 on the hour'595
float b = 0;
int c = 0;
float d = 0;
int e = 0;
int speed = 10; // used to control speed of counting

int segdisp[10] = {
63,6,91,79,102,109,125,7,127,111 };
void setup()
{
pinMode(latchpin1, OUTPUT);
pinMode(clockpin1, OUTPUT);
pinMode(datapin1, OUTPUT);
pinMode(latchpin2, OUTPUT);
pinMode(clockpin2, OUTPUT);
pinMode(datapin2, OUTPUT);
pinMode(latchpin3, OUTPUT);
pinMode(clockpin3, OUTPUT);
pinMode(datapin3, OUTPUT);
}

void loop()
{
  for (int z=0; z<24; z++)  // count to 24 hours
  for (int x=0; x<60; x++)  // count to 60 minutes
  for (int y=0; y<60; y++)  // count to 60 seconds

// Count

   {
    digitalWrite(latchpin1, LOW);
    shiftOut(datapin1, clockpin1, MSBFIRST, 0); // clears the right display
    shiftOut(datapin1, clockpin1, MSBFIRST, 0); // clears the left display
    digitalWrite(latchpin2, LOW);
    shiftOut(datapin2, clockpin2, MSBFIRST, 0); // clears the right display
    shiftOut(datapin2, clockpin2, MSBFIRST, 0); // clears the left display
    digitalWrite(latchpin3, LOW);
    shiftOut(datapin3, clockpin3, MSBFIRST, 0); // clears the right display
    shiftOut(datapin3, clockpin3, MSBFIRST, 0); // clears the left display
    
    {
      digitalWrite(latchpin1, HIGH);
      if (z<10)
        {
        digitalWrite(latchpin1, LOW);
        shiftOut(datapin1, clockpin1, MSBFIRST, segdisp[z]); // sends the digit down the serial path of hours
        shiftOut(datapin1, clockpin1, MSBFIRST, 63); // sends the digit down the serial path of hours
        digitalWrite(latchpin1, HIGH);  
        }
  
    else if (z>=10)
      {
      d=z%10; // find the remainder of dividing z by 10, this will be the right-hand digit
      c=int(d); // make it an integer, c is the right hand digit
      b=z/10; // divide z by 10 - the whole number value will be the left-hand digit
      e = int(b); // e is the left hand digit
      digitalWrite(latchpin1, LOW); // send the digits down to the shift registers!
      shiftOut(datapin1, clockpin1, MSBFIRST, segdisp[c]);
      shiftOut(datapin1, clockpin1, MSBFIRST, segdisp[e]);
      digitalWrite(latchpin1, HIGH);
      }
    
    }
  if (x<10)
    {
    digitalWrite(latchpin2, LOW); 
    shiftOut(datapin2, clockpin2, MSBFIRST, segdisp[x]); // sends the digit down the serial path of minutes
    shiftOut(datapin2, clockpin2, MSBFIRST, 63); // sends the digit down the serial path of minutes
    digitalWrite(latchpin2, HIGH);
    }

  else if (x>=10)
    {
    d=x%10; // find the remainder of dividing x by 10, this will be the right-hand digit, minutes
    c=int(d); // make it an integer, c is the right hand digit
    b=x/10; // divide x by 10 - the whole number value will be the left-hand digit, minutes
    e = int(b); // e is the left hand digit

    digitalWrite(latchpin2, LOW); // send the digits down to the shift registers!
    shiftOut(datapin2, clockpin2, MSBFIRST, segdisp[c]);
    shiftOut(datapin2, clockpin2, MSBFIRST, segdisp[e]);
    digitalWrite(latchpin2, HIGH);
    }
 
  
    
  digitalWrite(latchpin3, HIGH);
    if (y<10)
      {
       digitalWrite(latchpin3, LOW);
       shiftOut(datapin3, clockpin3, MSBFIRST, segdisp[y]); // sends the digit down the serial path
       shiftOut(datapin3, clockpin3, MSBFIRST, 63); // sends the digit down the serial path
       digitalWrite(latchpin3, HIGH);  
       }
  
    else if (y>=10)
     {
     d=y%10; // find the remainder of dividing y by 10, this will be the right-hand digit
     c=int(d); // make it an integer, c is the right hand digit
     b=y/10; // divide y by 10 - the whole number value will be the left-hand digit
     e = int(b); // e is the left hand digit
     digitalWrite(latchpin3, LOW); // send the digits down to the shift registers!
     shiftOut(datapin3, clockpin3, MSBFIRST, segdisp[c]);
     shiftOut(datapin3, clockpin3, MSBFIRST, segdisp[e]);
     digitalWrite(latchpin3, HIGH);
      }
     
    
   {
  delay (speed);
  }
}
}

Hi sinuslinus,

I'm having trouble following the masses of code but some things to do first I think,

You don't need all those latch/clock/data pins, you can connect all 3 shift registers in series and only have a single latch, clock and data pin. Then for example your clearing code would be something as simple as this.

    digitalWrite(latchpin, LOW);
    // clear all displays
    for (int x=0, x < 3; x++)
        shiftOut(datapin, clockpin, MSBFIRST, 0); 
     digitalWrite(latchpin, HIGH);

Which will write 3 null bytes into the 3 SRs thus clearing them. Not that you need to clear them every loop, the new values will be written over the old values, clearing as you have will only cause flicker.

Next thing,

  for (int z=0; z<24; z++)  // count to 24 hours
  for (int x=0; x<60; x++)  // count to 60 minutes
  for (int y=0; y<60; y++)  // count to 60 seconds

Firstly, what does this do? From what I can see

z = 23;
x = 59;
y = 59;

Would do the same thing, so you don't actually have any counters. Also use meaningful variable names (yes I know I didn't above but that was a tight loop that could viewed all at once, your x,y,z get used elsewhere, for example what does "if (z<10)" do, rather "if (hours<10)".

Next thing, you are mixing up the calculations with the IO, do one then the other.

loop() {
   int digits[3];

   // calc_all_digits_and_put_in_digits_array

   digitalWrite(latchpin, LOW);
    for (int x=0, x < 3; x++)
        shiftOut(datapin, clockpin, MSBFIRST, digits[x]); 
     digitalWrite(latchpin, HIGH);
float b = 0;
int c = 0;
float d = 0;

Why do you need floats to calc the time? Then you have to change them back to ints anyway.

It's late here, but if you can clean up some of that we can have another look at it.

Rob

It's way after my bed time but I thought I'd give you a start. I think something like this will have a chance of working.

#define SECONDS 0;
#define MINUTES 2;
#define HOURS   4;

uint_8 latchpin = 8;  // connect to pin 12 on the '595
uint_8 clockpin = 12; // connect to pin 11 on the '595
uint_8 datapin  = 11; // connect to pin 14 on the '595

uint_8 speed = 10;    // used to control speed of counting

uint_8 seconds = 0;
uint_8 minutes = 0;
uint_8 hours = 0;
uint_8 digits[6];

uint_8 segdisp[10] = {63,6,91,79,102,109,125,7,127,111};

void setup() {

   pinMode(latchpin, OUTPUT);
   pinMode(clockpin, OUTPUT);
   pinMode(datapin, OUTPUT);
 
}

void loop() {

   if (++seconds > 59) {
      seconds = 0;
      minutes++;
   }
   
   if (minutes > 59) {
      minutes = 0;
      hours++;
   }
   
   if (hours > 23) {
     hours = 0;
   }

   digits[SECONDS]   = seconds / 10;
   digits[SECONDS+1] = seconds % 10;
   digits[MINUTES]   = minutes / 10;
   digits[MINUTES+1] = minutes % 10;
   digits[HOURS]     = hours   / 10;
   digits[HOURS+1]   = hours   % 10;

   digitalWrite(latchpin, LOW);
   for (int x=0, x < 6; x++)
        shiftOut(datapin, clockpin, MSBFIRST, segdisp(digits[x]));
   digitalWrite(latchpin, HIGH);
 
   delay (speed);
}

It's still doesn't handle your original problem of a fast and slow clock, and I think the digits will be reversed, but it's a start.

Rob

I based it on this:
http://tronixstuff.wordpress.com/2010/05/06/getting-started-with-arduino-chapter-five/

and to be honest I don't really now how this works, it just works :-). First I just used 3 pins and all shift registers in series but I didn't manage to get all the displays working properly and just seconds counting.
And I have no answer why I am using floats.
I have 6 SRs in pairs, thats the way I got all displays working.
I have a look at this and see what happens. Thanks a lot.

/ Linus

I understand the idea of simplifying the code but I don't get everything.

Is uint_8 unsigned int ? Arduino doesn't compile uint_8

It didn't want to compile several other things but this works:

#define SECONDS 0
#define MINUTES 2
#define HOURS   4


unsigned int latchpin = 8;  // connect to pin 12 on the '595
unsigned int clockpin = 12; // connect to pin 11 on the '595
unsigned int datapin  = 11; // connect to pin 14 on the '595

unsigned int speed = 10;    // used to control speed of counting
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;
unsigned int digits[6];

unsigned int segdisp[10] = {63,6,91,79,102,109,125,7,127,111};

void setup() {

   pinMode(latchpin, OUTPUT);
   pinMode(clockpin, OUTPUT);
   pinMode(datapin, OUTPUT);

}

void loop() {

   if (++seconds > 59) 
   {
      seconds = 0;
      minutes++;
   }
  
   if (minutes > 59) {
      minutes = 0;
      hours++;
   }
  
   if (hours > 23) {
     hours = 0;
   }
{
   digits[SECONDS] = seconds / 1  ;
   digits[SECONDS+1] = seconds % 10;
   digits[MINUTES]   = minutes / 10;
   digits[MINUTES+1] = minutes % 10;
   digits[HOURS]     = hours   / 10;
   digits[HOURS+1]   = hours   % 10;
   }
   digitalWrite(latchpin, LOW);
   for (int x = 0; x < 6; x++)
        shiftOut(datapin, clockpin, MSBFIRST, digits[x]);
   digitalWrite(latchpin, HIGH);
   

   delay (speed);
}

I'll wire it up and see what happens..

But how can I get the change of speed and preferably a way to set the start "time"? O yes, when you press the button it should go back to the fast speed again after 10 seconds.

Okay really, I realized today that want all six displays to just flicker in the fast mode. Hmm that is, like the are all just rolling numbers quickly.
And at best show normal time for 10 seconds when the button is pressed.
Otherwise it looks like a bomb and not a spinning clock...

I did a quick wiring but the segments are all wrong.
Number 1 is shown as the top horizontal segment for instance.

And it doesn't shift down to the next display either. :frowning:

It starts counting on two displays (if I set speed to 1000 it shows seconds on two displays) but when reaches 10 they show differently.

I did a quick wiring but the segments are all wrong.
Number 1 is shown as the top horizontal segment for instance.

That implies that either your wiring is wrong OR the values in segdisp are wrong, like this

FWIW I find with these type of bit pattern lookup tables it's better to use hex or binary and lay it out to be easy to read.

short LED_data [] = {                 // abcdefg.
            0xfc,      //       0       %11111100
            0x60,      //       1      %01100000
            0xda,      //       2      %11011010
            0xf2,      //      3      %11110010
            0x66,      //      4      %01100110
            0xb6,      //      5      %10110110
            0xbe,      //      6      %10111110
            0xe0,      //      7      %11100000
            0xfe,      //      8      %11111110
            0xf6,      //      9      %11110110
            0xee,      //      A      %11101110
            0x3e,      //      b      %00111110
            0x9c,      //      C      %10011100
            0x7a,      //      d      %01111010
            0x9e,      //      E      %10011110
            0x8e      //      F      %10001110      
      };

And it doesn't shift down to the next display either.

It starts counting on two displays (if I set speed to 1000 it shows seconds on two displays) but when reaches 10 they show differently.

That all points to wiring, can you post the exact circuit you have?

It starts counting on two displays

Do you have all 6 SRs wired in series?

uint_8

Sorry about that, it was late after all, firstly it should have been uint8_t, and secondly your unsigned int is the same.

The values are correct. It has been working with the old code.
I went back a step and
this is what you wrote:

shiftOut(datapin, clockpin, MSBFIRST, segdisplay(digits[x]));

Arduino wont accept this:
"In function 'void loop()':
error: 'segdisplay' cannot be used as a function"

I changed that part to be able to compile it last night as posted but I think this is where the problem is, since your original code didn't. Can you have a look at this?

All 6 SRs are daisychained.

That all points to wiring, can you post the exact circuit you have?

Sorry, a picture or the specs?

Its pretty much the same as Excerise 5.1 here:
http://tronixstuff.wordpress.com/2010/05/06/getting-started-with-arduino-chapter-five/
His displays have the same pins as mine but on the SRs his pins are different.
I use these:

Oops, should have been

shiftOut(datapin, clockpin, MSBFIRST, segdisplay[digits[x]]);

Note the segdisplay[] instead of segdisplay(), the compiler thought segdisplay was a function not an array. I think that will work.

Sorry I can't work from fuzzy photos and youtube clips, did I miss something on those links because I don't see enough info there to build this, just some vague descriptions. Anyway an actual correct schematic is needed.

I know it's frustrating, welcome to the embedded programming world.

Rob

Sorry I can't work from fuzzy photos and youtube clips, did I miss something on those links because I don't see enough info there to build this, just some vague descriptions. Anyway an actual correct schematic is needed.

The last two are wired the same. And there are resistors on all segments.

I tried changing as below and now the seconds are counting alright but at 24 it stops counting. So solved one problem, but created another.

void loop()

{
    seconds++;                      // counting
   if (seconds > 59){
      seconds = 0;
      minutes++;
   if (minutes > 59) {
      minutes = 0;
      hours++;
   if (hours > 23) {
     hours = 0;
   }
   if(hours == 0) hours = 24;
   if(hours > 24) hours -= 24;
{

Hi linus,

The circuit looks good.

You've removed half of the braces, if you properly indent the result you get this

   seconds++;                      // counting
   if (seconds > 59) [glow]{[/glow]
      seconds = 0;
      minutes++;
      if (minutes > 59) {
         minutes = 0;
         hours++;
         if (hours > 23) {
           hours = 0;
         }
         if(hours == 0) hours = 24;
         if(hours > 24) hours -= 24;
      }

Note the highlighted }, how on earth did it compile with the unmatched braces, or is there one further down in the code, in which case anything could be happening.

This I don't think you need

if(hours == 0) hours = 24;
         if(hours > 24) hours -= 24;

If it works it's just covering up another fault somewhere.

Try your modified version with correct braces

   if (seconds > 59) {
      seconds = 0;
      minutes++;
      if (minutes > 59) {
         minutes = 0;
         hours++;
         if (hours > 23) {
           hours = 0;
         }
       }
    }

And if you get a compiler error remove any extra braces below this.

This is what I am running now. It counts seconds from 00 to 23 and then starts again from 00. No shiftdown on the other displays.
I don't get why it counts to 24.

#define SECONDS 4
#define MINUTES 2
#define HOURS   0


unsigned int latchpin = 8;  // connect to pin 12 on the '595
unsigned int clockpin = 12; // connect to pin 11 on the '595
unsigned int datapin  = 11; // connect to pin 14 on the '595

unsigned int speed = 1000;    // used to control speed of counting
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;
unsigned int digits[6];

unsigned int segdisp[10] = {63,6,91,79,102,109,125,7,127,111};

void setup() {

   pinMode(latchpin, OUTPUT);
   pinMode(clockpin, OUTPUT);
   pinMode(datapin, OUTPUT);

}

void loop(){
    seconds++;                      // counting
   if (seconds > 59){
      seconds = 0;
      minutes++;
   if (minutes > 59) {
      minutes = 0;
      hours++;
   if (hours > 23) {
     hours = 0;
   }
   digits[SECONDS] = seconds / 1  ;
   digits[SECONDS+1] = seconds % 10;
   digits[MINUTES]   = minutes / 10;
   digits[MINUTES+1] = minutes % 10;
   digits[HOURS]     = hours   / 10;
   digits[HOURS+1]   = hours   % 10;
   
   digitalWrite(latchpin, LOW);
   for (int x = 0; x < 6; x++)
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[digits[x]]); 
   digitalWrite(latchpin, HIGH);
 

   delay (speed);
}
 }
 }

If I move up the brachets above

 digits[SECONDS] = seconds / 1  ;

it mishaves as before.