Go Down

Topic: LED clock with different time speed (Read 4559 times) previous topic - next topic

sinuslinus

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.

James C4S

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.
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

Graynomad

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?
Rob Gray aka the GRAYnomad www.robgray.com

sinuslinus

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.

Graynomad

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.

Rob Gray aka the GRAYnomad www.robgray.com

sinuslinus

Feels great that you are saying its pretty simple :)

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

sinuslinus

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?

Code: [Select]
*/
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);
 }
}
}

Graynomad

#7
Sep 18, 2010, 05:12 pm Last Edit: Sep 18, 2010, 05:37 pm by graynomad Reason: 1
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.

Code: [Select]

   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,

Code: [Select]
 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

Code: [Select]
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.

Code: [Select]
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);
 



Code: [Select]
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

Rob Gray aka the GRAYnomad www.robgray.com

Graynomad

#8
Sep 18, 2010, 05:36 pm Last Edit: Sep 18, 2010, 05:43 pm by graynomad Reason: 1
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.

Code: [Select]
#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
Rob Gray aka the GRAYnomad www.robgray.com

sinuslinus

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

sinuslinus

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:
Code: [Select]
#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...

sinuslinus

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. :(

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.

Graynomad

#12
Sep 19, 2010, 04:04 am Last Edit: Sep 19, 2010, 11:43 am by graynomad Reason: 1
Quote
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.

Code: [Select]
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      
     };


Quote
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?

Quote
It starts counting on two displays

Do you have all 6 SRs wired in series?

Quote
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.
Rob Gray aka the GRAYnomad www.robgray.com

sinuslinus

#13
Sep 19, 2010, 12:45 pm Last Edit: Sep 19, 2010, 01:13 pm by sinuslinus Reason: 1
The values are correct. It has been working with the old code.
I went back a step and
this is what you wrote:
Code: [Select]
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.


sinuslinus

Quote
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:
http://uk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=483-6645

Go Up