Stopwatch with Pause/Lap  6 digit 7 seg LED. HELP!

HELP WANTED... PLEASE.. :slight_smile:

I am attempting to put together a simple 6 digit 7 seg-LED Stop Watch using 74HC595 Shift Registers x 6 (1 for each 7 seg). :stuck_out_tongue:

I have hacked the following code from ... somewhere?? on the internet after searching everywhere without success for even any kind of 3 digit timer that I can maybe hack and adapt.
This code will light up 4 digits but only use the 2 on the right to count up to 59.. I can get it to count to 99 but I have it set to 59. ::slight_smile:
When I tried to get it to count higher, like 2000+ it did it fine but didn't show correctly in the middle digit/s.

I know this is probably the wrong way to go about a timer/stopwach but I have been searching for weeks/days and this is the best I have got. :-/

Project idea is to eventually build a large 6" x 6 digit LED display for motor racing controlled initially by a hand button and in the future I want it to be triggered by a remote signal as the bike/car passes.

When the button is pressed I want it to pause the current time on the display while automatically restarting in the background timing the second lap. When the button is pressed again the display would show the current lap time..i.e, 'lap 2'. :slight_smile:

Memory would also be neat but not essential at the minute.

I am using Arduino Uno with 74HC595 Shift Registers x 6 and single LED 7-segment CC.

Any help or pointers in the right direction would be really well appreciated. Many thanks in advance, Warren :slight_smile:

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595
float b = 0;
int c = 0;
float d = 0;
int e = 0;
float f = 0;
int g = 0;
float h = 0;
int i = 0;

int speed = 100; // used to control speed of counting
int segdisp[10] = {
63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers


void setup()
{
pinMode(latchpin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(datapin, OUTPUT);



  
}
void loop()
 {  
// Counts up to 59 only!
for (int z=0; z<59; z++)
{
digitalWrite(latchpin, LOW);

shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
digitalWrite(latchpin, HIGH);
if (z<1)
{
digitalWrite(latchpin, LOW);

//****************************************************************************************************//
// I have left the following 2 lines as they were although I found no diference if I removed them?? **//
//****************************************************************************************************//

shiftOut(datapin, clockpin, MSBFIRST, segdisp[z]); // sends the digit down the serial path
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
digitalWrite(latchpin, HIGH);
}
else if (z>=1)
{
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

f=z/100; // divide z by 100 - 
g = int(f); //  

h=z/1000; // divide z by 1000 -
i = int(h); //




digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
shiftOut(datapin, clockpin, MSBFIRST, segdisp[c]);
shiftOut(datapin, clockpin, MSBFIRST, segdisp[e]);
shiftOut(datapin, clockpin, MSBFIRST, segdisp[g]);
shiftOut(datapin, clockpin, MSBFIRST, segdisp[i]);


digitalWrite(latchpin, HIGH);


  }


delay(speed);
}}

Bump.. :-/

Take a look at what I did here, using millis() to track when 1 second updates need to be displayed.
This decrements time from 10:00, 3:00, or 1:00, you could easily adapt it to count up instead.
I have 'interval' set so that the colon flashes on-off-on-off every second to easily see that time is running.
If you needed 6 digits you could change 'interval' to be the fastest incrementing digit, and let things roll / increment from there as it increments.
I had the code take care of rolling over the digits at the time boundaries vs straight counting and then dividing & dealing with the remainder, etc.

Take out the stuff I have for fencing references, add in your code to read the button and disable updating the display while still maintaining the time running. (I have another section that follows this one - if update_time gets set to 1, the updated digits are written into a MAX7221 to be displayed as part of 8 digits that display stuff - at the end of that section, it resets update_time to 0).

Also, look into tpic6b595 shift registers if you want to stay with that vs a chip that multiplexes the segments/digits, then you can create your own multi-LED segment digits (like 6-8 LEDs in series per segment) running from a higher voltage (say 24Vif you use eight 3V LEDs) while still drawing just 20mA/segment.

These variables have to be data type 'long': currentMillis, previousMillis, interval

// ***********************************************************************************************
// Loop here endlessly, checking if time or score needs updating, if wireless message came in, 
// if touch lights are on
// ***********************************************************************************************
void loop()
{
  // check if time needs updating
  if ((time_running == 1) || (time_running == 2))  // fencing time is counting down or delay time is counting down
  {
    unsigned long currentMillis = millis();  // see how long its been

    if (currentMillis - previousMillis >= interval) // more than our quarter second interval?
    {
      // save the last time we okayed time updates 
      previousMillis = currentMillis; 
      quarter_interval = quarter_interval+1;
      // cycle the colon state
      if (colon == 0x80)
      {
        colon = 0x00;
      }
      else
      {
        colon = 0x80;
      }
      update_time = 1;   //  enable time display to be updated

      if (quarter_interval == 4) // we hit the one second update time
      {
        quarter_interval = 0;
        // update the time digits
        // cases: 
        // 0:01, final second - stop time, disable touch lights, sound buzzer
        // Tens of seconds rollover: time = x:50, x:40, x:30, x:20, x:10: decrement tens of seconds, rollover seconds to 9
        // Minutes rollover: time = 9:00, 8:00, etc. 2:00, 1:00: decrement ones of minutes, rollover tens of 
        // seconds to 5, ones of seconds to 9
          // 10:00: Roll all the digits over
        // otherwise: just roll over the seconds

        // Case: Final Second
        if ((minutes_ones == 0) && (seconds_tens == 0) && (seconds_ones == 1)) // don't need minutes_tens, can't have 10:01
        {
          touchlight_enable = 0;          // score touches are locked out
          time_running = 0;  // stop time running
          seconds_ones = 0;  // clear the last second
          updated = 1;  // fake a Case complete flag
          buzzer = 1;                     // add a buzzer for this: end of time buzzer sounds       

          if ((time_running == 1) && (period>0) && (period<9)) { //  update period counter if was fencing time, not 1:00 or 10:00 break
            period = period +1;
            update_period=1;  // enable period display to be updated
          }
        }  // end of  if final second

        // Case: x:50, x:40, x:30, x:20, x:10
        if ((seconds_tens >0) && (seconds_ones == 0))  // case for the last tens of seconds 
        {
          seconds_tens = seconds_tens - 1;  // decrement the tens
          seconds_ones = 9;  // rollover the ones
          updated = 1;
        }  // end of if 10 of seconds rollover

        // Case: 9:00, 8:00, etc 2:00, 1:00
        if ((minutes_ones > 0) && (seconds_tens == 0) && (seconds_ones == 0)) // case for the last ones of minutes
        { 
          minutes_tens = 0x00;  //
          minutes_ones = minutes_ones - 1;  // decrement the minutes
          seconds_tens = 5;  // rollover the tens of seconds;
          seconds_ones = 9;  // rollover the ones of seconds;
          updated = 1;
        } // end of if minutes rollover

        // Case: starting from 10:00
        if (minutes_tens == 0x01)  // roll over all digits
        {
          minutes_tens = 0x00;  // rollover the tens of minutes
          minutes_ones = 9;  // rollover the ones of mints;
          seconds_tens = 5;  // rollover the tens of seconds;
          seconds_ones = 9;  // rollover the ones of seconds; 
          updated = 1;
        } // end of if 10:00 rollover

        // General Case: just decrement the seconds
        if (updated == 0)  // nothing else updated - but don't decrement if = 0.
        {
          seconds_ones = seconds_ones - 1;
        }
        updated = 0;  // reset for next pass thru
      } // end of if quarter_interval
    } // end of reaching our interval
  } // end of if time_running
  else
  {
    update_time = 0;   // no time update this time around - probably don't need this
  }

Crossroads, thank you very much for your reply.. I have been trying to implement it all day.. well for the last lot of hours anyway. :stuck_out_tongue:
I maybe should have mentioned I am a total novice when it comes to all this programming but very eager to learn. I have had my Aruino Uno for a few weeks now and have enjoyed hacking and copying codes to get it to count up and down. I really appreciate your help but don't know how to use it. :-[

Basically, I have searched for weeks for a working counter/stopwatch or something that uses 595's to run more than 3 x 7 seg digit's so that I can use it as a starting block and haven't found anything other than a 99 counter.

Even this example: Arduino Playground - Stopwatch doesn't help me as I don't know how to tell it to output to 7 segment display?? :-?

I will play around with what you have given me a bit longer and see if I can do any more with it.

Regards
Warren

I am basically doing what the example you linked to does.

Think of it this way, quasi coded:
void loop
{
read start/stop button
if (start/stop indicates time is running)
{
currenttime= millis(); // read the time
if (currenttime -previoustime >=100) // 0.1seconds, make this 10 for 0.01 seconds
{ previoustime = currenttime //store it
then update all your digits, and roll them over as needed
hundreths = hundreths+1;
if hundredths = 10, set hundredths to 0 and increment tenths;
if tenths = 10, set 10ths to and increment seconds
if seconds = 10, set seconds to 0 and increments tens_of_seconds
if tens_of_seconds = 6, set tens_of_seconds to 0 and increment minutes
if minutes = 10, set minutes to 0 and increment tens_of_minutes
if tens_of_minutes = 6, set tens_of_minutes to 0.
}
// check if the lap time display button is pushed - if it is, do not update the displays
// if not, shift out the updated time
/*Then shiftout the 6 bytes for each digit out to your display.
You have the 595 driving the segments directly? Then you'll habe to do some mapping also.
0 = segments a,b,c,d,e,f on
1 = segmens b,con
2 =segments a,b,d,e,g on
3 = segments a,d,e,f,g on
4 = segments f,g,b,c on
etc.
*/
}// and repeat!

Hi Crossroads, thanks again for the speedy reply although I have to say as much as I understand what the code is 'saying/doing' I don't know how to use it or what with? :cry:
I am learning lessons everyday but this is too much and with it being pieces I don't know how to use them.
I really do apologise for being new-comer pain in the butt and I know your looking at the code and thinking... "Why can't he see it!!!".
What I will do is search a bit more to find a sample and then if you don't mind I can ask you to look at how I can adapt it further for my project. I think I need to learn allot more before bothering you or anyone else on the forum.

Many thanks for your help so far and I will be in touch after Xmas sometime.

PS. Happy Xmas to you and yours! :slight_smile:

No problem Warren.
I think the idea is straightforward.
You have six digits, representing
Tens of Minutes, Minutes, Tens of Seconds, Seconds, Tenths of Seconds, Hundreths of Seconds.

These digits can be, in the order above, 0-5, 0-9, 0-5, 0-9, 0-9, 0-9. 00:00.00 to 59:59.99
See if you can get those working first, just counting up from 0.
So make a loop that reads the time from millis(), and whenever 0.01 (10 milliseconds) goes by, update the lowest digit. When that digit goes out of range, from 9 to 10 say for Hundreths of seconds, reset it to 0 and increment the next digit up.
Or even simpler to start - just a void loop with a delay(1000) at the end, get all your digits working updating ~1 second at a time, then reduce the delay to speed it up.
Whenever a digit changes, shift out the new value to the shift register/display (I assume you are planning all digits chained together to reduce pin usage?)
When you can get all the digits increment properly, then start adding stuff like reading push buttons, holding the display off, etc.
Eventually replace delay with reading the millis() for more accuracy.

I'll draw up a quick schematic with an idea of how to wire this up, and with a display idea.
Robert

So I imagine you have something like this going already, with more digits in the chain and some buttons to start/sotp time, etc. This shift register is nice because it can handle higher voltages for the bigger display in your future.
tpic6b595 open drain shift register

HI Robert,
Wow.. thank you again so much for your help. this time I return with some good news!!
I was reading a section of your text that for some reason inspired me to do my research in a different way?? :stuck_out_tongue: ::):P. the following piece;

0-5, 0-9, 0-5, 0-9, 0-9, 0-9. 00:00.00 to 59:59.99
See if you can get those working first, just counting up from 0.

Long story short, I now have 4 numbers counting. the 2 rightmost are counting to 99 and the next right counts to 9 and to 5 for the next right.
This is a small insert of the code I used;

if( f == 10) {
     f = 0;
     g = int(f);
  
     h++;
    i = int(h);
 } 
if( h == 6) {
     h = 0;
i = int(h);
}

I'm sure you know what I mean. :slight_smile:
So my next plan is to add the other 2 digits tonight n get them wired up and then add more of the same code above to include them on the counter.
I have added a 'Blink' to pin 13 and temporarily have it connected to a decimal point.
After that I will need to add a button to start and stop and another to start/pause/restart new lap.
I will try and get some pics up soon. Not sure how much I will get done over the next few days tho with Xmas.
Thanks again and I will update you soon,
Warren

Just out of curiosity, I am running the count speed like this;

int speed = 9; // used to control speed of counting

This controls the speed of the 100ths which increment the other numbers.
Is there a more accurate way to do this?
Cheers
Warren

Awesome Warren! Sounds like you are making good progress. Please write in when you have more done :slight_smile:

Now it's your turn to educate me a little:

I'm a digital hardware engineer, not really a programmer, so my code can look rather bumbly at times and I have some difficulty following the C shortcuts. I am getting better at keeping my ()s & {}s straightened out as I go.

So, I'm interested in what you have going on.

What are you doing with these parts? You don't seem to use g & i:

g = int(f);
i = int(h);

Do you have f & h declared as type byte? Why do g & i need to be type int?

h++; would seem to increment h from your following if statement.
Yet the arduino reference sections shows:

x++; // increment x by one and returns the old value of x
++x; // increment x by one and returns the new value of x

so it doesn't seem to me that h would be changed by h++;.
Maybe if used like this: z=h++; then z would be equal to h+1.
I could see ++h changing it. That seems to be the same as h=h+1;
(I like to see what really happens so when I'm up too late debugging it sticks out more - I think the compiler makes them come out the same in the end.)

But that h++ is working for you?

"speed = 9"
You are using this as delay(speed)?

What you want to do is wrap your whole counting & updating inside a loop that lets it increment based on the millis() time, this is the # of milliseconds that have gone by since your sketch started.
unsigned long is 32 bits, so it will take millis() something like 49 days to count from 0 to 2^32-1 before going back to 0 (and even when it does, 0x0000 0005 - 0xFFFF FFFE will still yield the correct result: 7.

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10;

something like this, within your void loop(){

currentmillis = millis(); // read the time.
if (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
{ previousmillis = currentmillis; // save the time for the next comparison
hundredths = hundreths +1;
if (hundredths = 10){
hundredths = 0;
tenths = tenths +1;}
} etc, like you have now

} // end void loop

If you want it run slower so you can see the .01s & 0.1s incrementing properly, just make interval bigger until you are satisfied.

Robert

Hi Robert, sorry it's been a couple of nights without an update.. we've had a power cut, my computer got a virus and wouldn't load the internet!! then my battery in the van failed and on top of all that the code I thought worked.. didn't really. :frowning:
I had it changing when.. for example, it reached 5 in the tens of seconds but that just added a minute at 50 seconds instead of 59/60.. anyway, I worked on that for ages and have now finally came up with a counter that goes up 99 hundredths and then adds 1 second as it shows "00".. the seconds now count to 59 before adding "1" minute as they also show "00" and start re-counting. Same with the minutes, they go up to 59 before showing "00". :slight_smile:
Really, really chuffed with how it works but I'm not sure how to implement the millis() time thing??

What you want to do is wrap your whole counting & updating inside a loop that lets it increment based on the millis() time

I just don't know what to take out and where to put each piece of your code? I did try messing with it the other day but didn't get anywhere, I even tried looking for other examples but without luck.

What are you doing with these parts? You don't seem to use g & i:

g = int(f);
i = int(h);

G & I are the last 2 digits.. see full code at the bottom. :slight_smile:

h++; would seem to increment h from your following if statement.
Yet the arduino reference sections shows:

x++; // increment x by one and returns the old value of x
++x; // increment x by one and returns the new value of x

so it doesn't seem to me that h would be changed by h++;.
Maybe if used like this: z=h++; then z would be equal to h+1.
I could see ++h changing it. That seems to be the same as h=h+1;
(I like to see what really happens so when I'm up too late debugging it sticks out more - I think the compiler makes them come out the same in the end.)

But that h++ is working for you?

.. again, I don't really know what most of it means?? What I do know is that everything is relevant to "z". My "z" I have counting to 101. I then take '%10' and '/10' for the hundredths of seconds which in turn increment everything else. So if I need anything to be accurate it would be the "z" in my code.
Any help would be great on how to do this.

Here is my "59:59:99" counter full incrementing code; (which is not accurate to time.)

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595
float b = 0;
int c = 0;
float d = 0;
int e = 0;
float f = 0;
int g = 0;
float h = 0;
int i = 0;
float j = 0;
int k = 0;
float l = 0;
int m = 0;


int seconds;
int minutes;
int speed = 10; // used to control speed of counting
int segdisp[10] = {
63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers


void setup()
{
pinMode(latchpin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(datapin, OUTPUT);



  
}
void loop()
 {  
// Counts up to 59 only!
for (int z=0; z<101; z++)
 
{
digitalWrite(latchpin, LOW);

shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
digitalWrite(latchpin, HIGH);
if (z<1)
{
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, segdisp[z]); // sends the digit down the serial path
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
digitalWrite(latchpin, HIGH);
}
else if (z>=1)
//------------------------------ Hundredths below
{
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
//------------------------------ Ten of Seconds (60) below

if( z == 100) {
     c=0; // clear the hundredths digit
     e=0; // clear the hundredths digit
     z=0; // reset the timer
     seconds++; // add 1 second to "seconds"
      f=seconds%10; // float the %
      g=int (f); // print the % first "seconds" digit

h=seconds/10; // divid the seconds by 10 to get the tens of seconds
i = int (h); // print the tens of seconds digit
}

//------------------------------ Minutes (60) below

if( seconds == 60) {
     g=0; // clear the "seconds" digit
     i=0; // clear the "tens" of seconds digit
    
 seconds=0; // reset the seconds
 minutes++; // add 1 minute to "minutes"
      j=minutes%10; // float the %
      k=int (j); // print the % first "minute" digit

l=minutes/10; // divid the minutes by 10 to get the tens of minutes
m = int (l); // print the tens of minutes digit

} 
//------------------------------ 

if( minutes == 60) {
     k=0; // clear the "minutes" digit
     m=0; // clear the "tens" of minutes digit
   minutes=0; // reset the minutes
} 


digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
shiftOut(datapin, clockpin, MSBFIRST, segdisp[c]); // print the % first "hundredths" digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[e]); // print the tens of hundredths digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[g]); // print the % first "seconds" digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[i]); // print the tens of seconds digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[k]); // print the % first "minute" digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[m]); // print the tens of minutes digit
digitalWrite(latchpin, HIGH);


  }


delay(speed);
}}

Hope it all makes sense.. I've tried my best to label it as much as I can.
Regards
Warren

Hi Warren,
I saw that post and all the math, then we went out & I forgot about it until just now.

Anyway,
To use millis, what you want to do is increment z here
for (int z=0; z<101; z++)

only when your lowest time increment has occurred.
Thus

if (time_running == 1) // because you've told it to based on a button push or something
  {
    unsigned long currentMillis = millis();  // see how long its been

    if (currentMillis - previousMillis >= interval) // reached 10mS interval?
    {
      // save the last time we okayed time updates 
      previousMillis = currentMillis; 
     count_update_flag = 1;}

and roll your increments thru from there.
I was thinking more along these lines instead of all the math:
AB:CD.EF
Start at the top, you've reached the time interval:

if (count_update_flag == 1){
count_update_flag = 0; // reset for next pass thru
if (time == 59:59.99) {reset all to 0, set time_update flag to 1}
// which is really: if (A==5 && B==9 && C==5 && D==9 && E==9 && F==9)
if (A<5 and rest == 9:59.99){increment A, reset the lower digits, set time_update flag to 1}
if (B<9 and rest == 59.99){increment B, reset the lower digits, set time_update flag to 1}
if (C<5 and rest == 9.99){increment C, reset the lower digits, set time_update flag to 1}
if (D<9 and rest == 99){increment D, reset the lower digits, set time_update flag to 1}
if (E<5 and F==9){increment E, reset F, set time_update flag to 1}
if (F<9){all that's remaing, eh? increment F, set time_update flag to 1}
}// end of counting update

if (time_update == 1){
time_upate = 0; // reset for next pass thru
shift out the digits that were updated above}
} // end of  interval check

then you can get away from all the floats and converting to ints & stuff.
You've got (0.01S/62.5nS) = 160,000 clock cycles for the 5-6 comparisons and the resets and the 6 shiftouts, which all be done well before the next 10mS comparison is due.

Hi Robert, I'm stuck on the time/millis. I still can't get the timer to count accurately and I know I haven't put the code in right??
I have tried numerous ways and looked at other codes but can't figure out what I'm doing wrong.
Here's what I have;

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10;

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595
float b = 0;
int c = 0;
float d = 0;
int e = 0;
float f = 0;
int g = 0;
float h = 0;
int i = 0;
float j = 0;
int k = 0;
float l = 0;
int m = 0;
int hundredths1;

int seconds;
int minutes;
int hundredths;

int segdisp[10] = {
63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers


void setup()
{
pinMode(latchpin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(datapin, OUTPUT);



}
void loop()
  {
   currentmillis = millis();  // read the time.
if (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
{ previousmillis  = currentmillis;  // save the time for the next comparison
hundredths = hundredths +1;

}


{

  // Counts up to 101 only!
for (int hundredths=0; hundredths<101; hundredths++)


{
digitalWrite(latchpin, LOW);

shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
digitalWrite(latchpin, HIGH);
if (hundredths<1)
{
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, segdisp[hundredths]); // sends the digit down the serial path
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
digitalWrite(latchpin, HIGH);
}
else if (hundredths>=1)
//------------------------------ Hundredths below
{
d=hundredths%10; // find the remainder of dividing hundredths by 10, this will be the right-hand digit
c=int(d); // make it an integer, c is the right hand digit

b=hundredths/10; // divide hundredths by 10 - the whole number value will be the left-hand digit
e = int(b); // e is the left hand digit
//------------------------------ Ten of Seconds (60) below

if( hundredths == 100) {
     c=0; // clear the hundredths digit
     e=0; // clear the hundredths digit
     hundredths=0; // reset the timer
     seconds++; // add 1 second to "seconds"
      f=seconds%10; // float the %
      g=int (f); // print the % first "seconds" digit

h=seconds/10; // divid the seconds by 10 to get the tens of seconds
i = int (h); // print the tens of seconds digit
}

//------------------------------ Minutes (60) below

if( seconds == 60) {
     g=0; // clear the "seconds" digit
     i=0; // clear the "tens" of seconds digit
    
 seconds=0; // reset the seconds
 minutes++; // add 1 minute to "minutes"
      j=minutes%10; // float the %
      k=int (j); // print the % first "minute" digit

l=minutes/10; // divid the minutes by 10 to get the tens of minutes
m = int (l); // print the tens of minutes digit

} 
//------------------------------ 

if( minutes == 60) {
     k=0; // clear the "minutes" digit
     m=0; // clear the "tens" of minutes digit
   minutes=0; // reset the minutes
} 


digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
shiftOut(datapin, clockpin, MSBFIRST, segdisp[c]); // print the % first "hundredths" digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[e]); // print the tens of hundredths digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[g]); // print the % first "seconds" digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[i]); // print the tens of seconds digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[k]); // print the % first "minute" digit
shiftOut(datapin, clockpin, MSBFIRST, segdisp[m]); // print the tens of minutes digit
digitalWrite(latchpin, HIGH);


}
delay(10);
}}}

Can you see what is wrong?? I just want to get it counting accurately before adding buttons etc. It's roughly 2 seconds per minute out.
Cheers
Warren

I tweaked it a little, try this.
You had a couple of } in the wrong place, think it was messing the logic up a little, thats why I think you had 4 at the end.
Next edit, use the Tools:Autoformat key, it can help you spot things like that, while the compiler may not necessarily complain.
You are shifting out 3 times, that may be slowing things down a little as well. Try taking the first 2 sets out.

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10;

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595
float b = 0;
int c = 0;
float d = 0;
int e = 0;
float f = 0;
int g = 0;
float h = 0;
int i = 0;
float j = 0;
int k = 0;
float l = 0;
int m = 0;
int hundredths1;
int seconds;
int minutes;
int hundredths;

[glow]int segdisp[10] = {
  63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers
// not really sure what this is, I did not mess with it[/glow]

[glow]int time_update = 0;// added new flag[/glow]
void setup()
{
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  pinMode(datapin, OUTPUT);
}

void loop()
{
  currentmillis = millis();  // read the time.
  if (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
  { 
    previousmillis  = currentmillis;  // save the time for the next comparison
    hundredths = hundredths +1;
    [glow][glow]time_update = 1;[/glow]  }  // set flag to upate & shift out[/glow]

[glow]  if (time_update == 1){  // no updating if not at 10ms interval, skip this whole section
    // increment the counters, roll as needed, shift the digits out
    time_update = 0; // reset for next pass thru[/glow]
      digitalWrite(latchpin, LOW);

[glow]// why do this? I would think it would just make the display look flickery, 
// going between 0 & a real number each update. Maybe put a copy of this in void setup() to clear the displays to start the program[/glow]
      shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
      shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
      shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
      shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
      shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
      shiftOut(datapin, clockpin, MSBFIRST, 0); // clears the left display
      digitalWrite(latchpin, HIGH);
      if (hundredths<1)
      {
        digitalWrite(latchpin, LOW);

[glow]// why do this again? I would think it would just make the display look flickery, 
// going between 0 & a real number each update[/glow]

        shiftOut(datapin, clockpin, MSBFIRST, segdisp[hundredths]); // sends the digit down the serial path
        shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
        shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
        shiftOut(datapin, clockpin, MSBFIRST, 0); // sends a blank down the serial path to push the digit to the right
        digitalWrite(latchpin, HIGH);
      }
      else if (hundredths>=1)
        //------------------------------ Hundredths below
      {
        d=hundredths%10; // find the remainder of dividing hundredths by 10, this will be the right-hand digit
        c=int(d); // make it an integer, c is the right hand digit

        b=hundredths/10; // divide hundredths by 10 - the whole number value will be the left-hand digit
        e = int(b); // e is the left hand digit
      }
        //------------------------------ Ten of Seconds (60) below

        if( hundredths == 100) {
          c=0; // clear the hundredths digit
          e=0; // clear the hundredths digit
          hundredths=0; // reset the timer
          seconds++; // add 1 second to "seconds"
          f=seconds%10; // float the %
          g=int (f); // print the % first "seconds" digit

          h=seconds/10; // divide the seconds by 10 to get the tens of seconds
          i = int (h); // print the tens of seconds digit
        }

        //------------------------------ Minutes (60) below

        if( seconds == 60) {
          g=0; // clear the "seconds" digit
          i=0; // clear the "tens" of seconds digit

          seconds=0; // reset the seconds
          minutes++; // add 1 minute to "minutes"
          j=minutes%10; // float the %
          k=int (j); // print the % first "minute" digit

          l=minutes/10; // divid the minutes by 10 to get the tens of minutes
          m = int (l); // print the tens of minutes digit

        }
        //------------------------------

        if( minutes == 60) {
          k=0; // clear the "minutes" digit
          m=0; // clear the "tens" of minutes digit
          minutes=0; // reset the minutes
        }
[glow]// counters are all updated now, just do the shiftout one time here:[/glow]
        digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[c]); // print the % first "hundredths" digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[e]); // print the tens of hundredths digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[g]); // print the % first "seconds" digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[i]); // print the tens of seconds digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[k]); // print the % first "minute" digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[m]); // print the tens of minutes digit
        digitalWrite(latchpin, HIGH);

  } // end if time to be updated

} // end void loop

Hi Robert.. your a star!! I have it all working and took out alot of that code that wasn't needed. It is now running almost accurately.. I have highlighted in the code if( hundredths == 100) because I can make the time go faster or slower by entering 99 or 100. 99 is too fast and 100 is too slow?? How can this be edited?
After 11mins 30secs it's almost 5 seconds slow.

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10;

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595

int c = 0;
int e = 0;
int g = 0;
int i = 0;
int k = 0;
int m = 0;

int seconds;
int minutes;
int hundredths;

int segdisp[10] = {
  63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers
//The above numbers light up different segments of a digit

int time_update = 0;// added new flag
void setup()
{
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  pinMode(datapin, OUTPUT);
}

void loop()
{
  currentmillis = millis();  // read the time.
  if (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
  {
    previousmillis  = currentmillis;  // save the time for the next comparison
    hundredths = hundredths +1;
  
 time_update = 1;  }  // set flag to upate & shift out 

  if (time_update == 1){  // no updating if not at 10ms interval, skip this whole section
    // increment the counters, roll as needed, shift the digits out
    time_update = 0; // reset for next pass thru
      


        //------------------------------ Hundredths below
      {
        c=hundredths%10; // find the remainder of dividing hundredths by 10, this will be the right-hand digit
        e=hundredths/10; // divide hundredths by 10 - the whole number value will be the left-hand digit
      
      }
        //------------------------------ Ten of Seconds (60) below

        [glow]if( hundredths == 100) [/glow]{
         
          hundredths=0; // reset the timer
          seconds++; // add 1 second to "seconds"
         
            g=seconds%10; // 
          i=seconds/10; // divide the seconds by 10 to get the tens of seconds
         
        }

        //------------------------------ Minutes (60) below

        if( seconds == 60) {
          g=0; // clear the "seconds" digit
          i=0; // clear the "tens" of seconds digit

          seconds=0; // reset the seconds
          minutes++; // add 1 minute to "minutes"
          k=minutes%10; // 
          m=minutes/10; // divid the minutes by 10 to get the tens of minutes
        
        }
        //------------------------------

        if( minutes == 60) {
          k=0; // clear the "minutes" digit
          m=0; // clear the "tens" of minutes digit
          minutes=0; // reset the minutes
        }
// counters are all updated now, just do the shiftout one time here:
        digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[c]); // print the % first "hundredths" digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[e]); // print the tens of hundredths digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[g]); // print the % first "seconds" digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[i]); // print the tens of seconds digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[k]); // print the % first "minute" digit
        shiftOut(datapin, clockpin, MSBFIRST, segdisp[m]); // print the tens of minutes digit
        digitalWrite(latchpin, HIGH);

  } // end if time to be updated

} // end void loop

Try simplifying it - maybe the divisions & ints & floats is introducing some roundover type errors?

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10;

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595

int ones_seconds = 0;
int tens_seconds = 0;
int ones_minutes = 0;
int tens_minutes = 0;
int tenths = 0;
int hundredths= 0;

int segdisp[10] = {
  63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers
//The above numbers light up different segments of a digit

int time_update = 0;// added new flag
void setup()
{
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  pinMode(datapin, OUTPUT);
}

void loop()
{
  currentmillis = millis();  // read the time.
  if (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
  {
    previousmillis  = currentmillis;  // save the time for the next comparison

    time_update = 1;  
  }  // set flag to upate & shift out

  if (time_update == 1){  // no updating if not at 10ms interval, skip this whole section
    // increment the counters, roll as needed, shift the digits out
    time_update = 0; // reset for next pass thru

    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;
    }

    // counters are all updated now, just do the shiftout one time here:
    digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[hundredths]); // print the % first "hundredths" digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[tenths]); // print the tens of hundredths digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[ones_seconds]); // print the % first "seconds" digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[tens_seconds]); // print the tens of seconds digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[ones_minutes]); // print the % first "minute" digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[tens_minutes]); // print the tens of minutes digit
    digitalWrite(latchpin, HIGH);

  } // end if time to be updated

} // end void loop

Cheers Robert.. I will try this now. :slight_smile:


That code works fine.. although after 5 minutes it still looses around 2 seconds??

This is what I have now;

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10;

int latchpin = 8; // connect to pin 12 on the 74HC595
int clockpin = 12; // connect to pin 11 on the 74HC595
int datapin = 11; // connect to pin 14 on the 74HC595

int ones_seconds = 0;
int tens_seconds = 0;
int ones_minutes = 0;
int tens_minutes = 0;
int tenths = 0;
int hundredths= 0;


int segdisp[10] = {
  63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers
//The above numbers light up different segments of a digit

int time_update = 0;// added new flag
void setup()
{
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  pinMode(datapin, OUTPUT);
}

void loop()
{
  currentmillis = millis();  // read the time.
  if (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
  {
    previousmillis  = currentmillis;  // save the time for the next comparison
  
  
 time_update = 1;  }  // set flag to upate & shift out 

  if (time_update == 1){  // no updating if not at 10ms interval, skip this whole section
    // increment the counters, roll as needed, shift the digits out
    time_update = 0; // reset for next pass thru
      

  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;
    }

    // counters are all updated now, just do the shiftout one time here:
    digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[hundredths]); // print the % first "hundredths" digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[tenths]); // print the tens of hundredths digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[ones_seconds]); // print the % first "seconds" digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[tens_seconds]); // print the tens of seconds digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[ones_minutes]); // print the % first "minute" digit
    shiftOut(datapin, clockpin, MSBFIRST, segdisp[tens_minutes]); // print the tens of minutes digit
    digitalWrite(latchpin, HIGH);



  } // end if time to be updated

} // end void loop

Is this way supposed to be as in-accurate as this or would I have to fit a RTC clock or something?? As a stopwatch/lap time it is going to need to be accurate for at least 5 minutes for short circuit and road race events.

Hi Robert,
Just a quick note to let you know I have applied a fix to the timer. (see code below)
I added 7 x 100ths to the 'hundredths' each loop. Now it's almost accurate to an hour.. just got to tweak it a little more. :slight_smile:
Really pleased with the whole thing and can't thank you enough for your help with the code.
I am now trying to work with the buttons.. start, stop, lap/pause with background restart.. then resume.
Using de-bounce I should be able to work something out?? I will of course keep you updated.

 if (ones_seconds == 10){
      ones_seconds = 0;
      [glow]hundredths = hundredths +7;[/glow]
tens_seconds = tens_seconds +1;
    }