problem with stopwatch (timecode) code

Hi,
i want to make timecode led display that run by itself (without external clock or timecode signal)
its fixed framerate (in the arduino code),
i found good simple code that made by dan thomson based on the stopwatch (Dan Thompson: Timecode Based Stopwatch),
in the original code dan used lcd display,
so i tried to convert the code to work with 7 segment 8 digit display (using the MAX7219, "LedControl.h" library)
the code compiled successfully without errors, but the display itself not running well,
only the two first frame digits (FPS) running well,
but the other digits dose not showing the numbers (the digits flickering fast and i cant see the numbers).

due to message length limitation, i can't post the full code,
so i add the lines i have problem with, and i attach the sketch file:

 /////////////////////////////////////////////
   //     Routine to report elapsed time            
   /////////////////////////////////////////////   
   elapsedTime =   millis() - startTime;                // store elapsed time
   elapsedMinutes = (elapsedTime / 60000L);
 elapsedSeconds = (elapsedTime / 1000L);              // divide by 1000 to convert to seconds - then cast to an int to print
   elapsedFrames = (elapsedTime / interval);            // divide by 40 to convert to 1/25 of a second - then cast to an int to print
   fractional = (int)(elapsedFrames % frameRate);       // use modulo operator to get fractional part of 25 Frames
   fractionalSecs = (int)(elapsedSeconds % 60L);        // use modulo operator to get fractional part of 60 Seconds
   fractionalMins = (int)(elapsedMinutes % 60L);        // use modulo operator to get fractional part of 60 Minutes
  lc.clearDisplay(0); //and clear the display 


 if (fractionalMins < 10){                            // pad in leading zeros
digitFive =  0;                         // add a zero
      }
      
if (fractionalMins > 9){
      float fractionalMinsresult = fractionalMins / 10;  //s/b 4.2 fractionalMinsResulting in 4
      digitFive = fractionalMins % 10;  //this gets the remainder of 42/10 or 2
      digitSix = fractionalMinsresult; 
     }
    else
    {
      digitFive = fractionalMins;  
      digitSix = 0;
    }
       
 if (fractionalSecs < 10){                            // pad in leading zeros
      digitThree = 0;                               // add a zero
      }
      
if (fractionalSecs > 9){
      float fractionalSecsresult = fractionalSecs / 10;  //s/b 4.2 fractionalSecsResulting in 4
      digitThree = fractionalSecs % 10;  //this gets the remainder of 42/10 or 2
      digitFour = fractionalSecsresult;  
     }
    else
    {
     digitThree = fractionalSecs;  
      digitFour = 0;
    }


 if (fractional < 10){                                // pad in leading zeros 
      digitOne = 0;                                 // add a zero
      }     
      
 if (fractional > 9){
      float fractionalresult = fractional / 10;  //s/b 4.2 fractionalResulting in 4
      digitOne = fractional % 10;  //this gets the remainder of 42/10 or 2
      digitTwo = fractionalresult; 
      }
    else
    {
      digitOne = fractional % 10;  
      digitTwo = 0;
    }
   }

 else{
      lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
   }

can you please tell me what i did wrong? :~

timecode_prototype2.ino (9.92 KB)

long previousMillis = 0;            // variable to store last time LED was updated
long startTime ;                    // start time for stop watch
long elapsedTime ;                  // elapsed time for stop watch

Are you planning to allow for time to go backwards? If not, time variables should be unsigned long, not long.

  int digitOne,digitTwo,digitThree,digitFour,digitFive,digitSix,digitSeven,digitEight;

Local variables are not initialized. You have no idea what is in these variables. Declaring them far away from where they are used is not a good idea, either.

   if (buttonState == LOW && lastButtonState == HIGH  &&  blinking == false){   
    startTime = millis();                             // store the start time
      blinking = true;                                  // turn on blinking while timing
      delay(5);                                         // short delay to debounce switch
      lastButtonState = buttonState;                    // store buttonState in lastButtonState, to compare next time      
   }

lastButtonState should be set to buttonState on every pass through loop.

Putting the { on lines by themselves, and using
Tools + Auto Format makes
it much easier
to read the code.
Code that jerks all
over the
place is hard to read.

   fractional = (int)(elapsedFrames % frameRate);       // use modulo operator to get fractional part of 25 Frames
   fractionalSecs = (int)(elapsedSeconds % 60L);        // use modulo operator to get fractional part of 60 Seconds
   fractionalMins = (int)(elapsedMinutes % 60L);        // use modulo operator to get fractional part of 60 Minutes

These comments are useless. We can see that the modulo operator is being used. But why?

      float fractionalMinsresult = fractionalMins / 10;  //s/b 4.2 fractionalMinsResulting in 4

The comment is right. Storing the resulting int in a float is wrong.

That code looks like it's getting the value for the ones column and for the tens column for minutes, seconds, etc. The names used should reflect that. fractionalMins doesn't mean squat.

Not a Serial.print() statement in the code. Why not?

unsigned long elapsedTime = millis() - startTime;
// now we know how much time, in milliseconds
// next, we initialize variables for the digits
byte hours = 0;
byte minTens = 0; byte minOnes = 0;
byte secTens = 0; byte secOnes = 0;
byte frameTens = 0; byte frameOnes = 0;
// now, let's do some math
unsigned long leftover = elapsedTime;
while (leftover >= 3600000) { leftover -= 3600000; hours++; }
while (leftover >=  600000) { leftover -=  600000; minTens++; }
while (leftover >=   60000) { leftover -=   60000; minOnes++; }
while (leftover >=   10000) { leftover -=   10000; secTens++; }
while (leftover >=    1000) { leftover -=    1000; secOnes++; }
// the code below assumes 25 frames per second (1 frame = 40 ms)
// if you want something different, you will have to change it
while (leftover >= 400) { leftover -= 400; frameTens++; }
while (leftover >=  40) { leftover -=  40; frameOnes++; }

Now you have your digits in the variables hours, minTens, minOnes, etc., down to frameOnes.
All the math has been done for you, now all you have to do is put those digits on the display.

Thank you very much PualS for your help,

time variables and local variables fixed, Serial.print() removed (i forgot to remove),
and unnecessary comments removed.
Thanks for the code organisation tips,
i used the auto-format and the code now is easier to read.
i didnt understand what you mean about the "lastButtonState".

Thank you very much odometer,
For the calculations for the display, i will add it in my code.

Edit:
thanks again, Its working, the digits runs smoothly. (sketch Attached)
i got problem with the button, when i press the button its sometimes reset and sometimes pause,

  //////////////////////////////
  //   Check for button press
  //////////////////////////////
  buttonState = digitalRead(buttonPin);                // read the button state and store

  // check for a high to low transition if true then found a new button press while clock is not running - start the clock    
  if (buttonState == LOW && lastButtonState == HIGH  &&  blinking == false)
  {   
    startTime = millis();                             // store the start time
    blinking = true;                                  // turn on blinking while timing
    delay(5);                                         // short delay to debounce switch
    lastButtonState = buttonState;                    // store buttonState in lastButtonState, to compare next time      
  }

  // check for a high to low transition if true then found a new button press while clock is running - stop the clock and report
  else if (buttonState == LOW && lastButtonState == HIGH && blinking == true)
  {   
    blinking = false;                                    // turn off blinking, all done timing
    lastButtonState = buttonState;                       // store buttonState in lastButtonState, to compare next time

      /////////////////////////////////////////////
    //     Routine to report elapsed time            
    /////////////////////////////////////////////   
    unsigned long elapsedTime = millis() - startTime;
    // now we know how much time, in milliseconds
    // next, we initialize variables for the digits
    byte hours = 0;
    byte minTens = 0; 
    byte minOnes = 0;
    byte secTens = 0; 
    byte secOnes = 0;
    byte frameTens = 0; 
    byte frameOnes = 0;
    // now, let's do some math
    unsigned long leftover = elapsedTime;
    while (leftover >= 3600000) 
    { 
      leftover -= 3600000; 
      hours++; 
    }
    while (leftover >=  600000) 
    { 
      leftover -=  600000; 
      minTens++; 
    }
    while (leftover >=   60000) 
    { 
      leftover -=   60000; 
      minOnes++; 
    }
    while (leftover >=   10000) 
    { 
      leftover -=   10000; 
      secTens++; 
    }
    while (leftover >=    1000) 
    { 
      leftover -=    1000; 
      secOnes++; 
    }
    // the code below assumes 25 frames per second (1 frame = 40 ms)
    // if you want something different, you will have to change it
    while (leftover >= 400) 
    { 
      leftover -= 400; 
      frameTens++; 
    }
    while (leftover >=  40) 
    { 
      leftover -=  40; 
      frameOnes++; 
    }

    lc.setDigit(0,0,frameOnes,false);  
    lc.setDigit(0,1,frameTens,false);
    lc.setDigit(0,2,secOnes,true);
    lc.setDigit(0,3,secTens,false);
    lc.setDigit(0,4,minOnes,true);
    lc.setDigit(0,5,minTens,false);
    lc.setDigit(0,6,hours,true);
    //    lc.setDigit(0,7,hourstens,false);  
  }

  else
  {
    lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
  }

i want it to pause after i press once, and to reset after i press again.
i want the display show two hours digits (for example if its run 10 hours, etc.), how i do that?

timecode_prototype3.ino (7.51 KB)

As for two digits for the hours: let me make some modifications:

unsigned long elapsedTime = millis() - startTime;
// now we know how much time, in milliseconds
// next, we initialize variables for the digits
byte hourTens = 0; byte hourOnes = 0;
byte minTens = 0; byte minOnes = 0;
byte secTens = 0; byte secOnes = 0;
byte frameTens = 0; byte frameOnes = 0;
// now, let's do some math
unsigned long leftover = elapsedTime;
while (leftover >= 36000000) { leftover -= 36000000; hourTens++; }
while (leftover >=  3600000) { leftover -=  3600000; hourOnes++; }
while (leftover >=   600000) { leftover -=   600000; minTens++; }
while (leftover >=    60000) { leftover -=    60000; minOnes++; }
while (leftover >=    10000) { leftover -=    10000; secTens++; }
while (leftover >=     1000) { leftover -=     1000; secOnes++; }
// the code below assumes 25 frames per second (1 frame = 40 ms)
// if you want something different, you will have to change it
while (leftover >= 400) { leftover -= 400; frameTens++; }
while (leftover >=  40) { leftover -=  40; frameOnes++; }

I hope you see the changes I made as regards the variables.
Also: do you see what I did? Do you know what a while loop is?
Do you understand what's special about the number 36000000, etc.? (Why did I write 36000000, for example, and not 24000000 or something?)

As for your problems with the button:
Think of what happens when you let go of the button. When you are taking your finger off of the button, what happens if the switch bounces then? Won't it register as off-on-off-on-off-on or some such?

I would recommend that you check for a change in position of the switch. Something like this:

if (lastButtonState != buttonState) {
  // do whatever you need to
  // start or stop the timer, change the display, etc.
  // and then, make sure you do this:
  delay(12); // lazy programmer's debounce 
}

If you don't know what the != symbol means, I strongly suggest you look it up.

thank you odometer for your help,
i saw the changes in the code and i have add it, it's working great.
i saw what you did, i didnt know what the while doing, but now and i'm understand how while loop works:
its looping again and again the code you put inside the brackets {}, until the term (expression) in the while Parentheses? () is become false, so for example

    while (leftover >= 36000000)
    { 
      leftover -= 36000000; 
      hourTens++; 
    }

in this code, if the time (in milliseconds) didnt reach to 36000000 (10 hours), the tens-hour digit will do nothing (keep in 0)
if its reach that its will add 1 in the tens-hour digit and subtract the leftover number in 36000000 so its wont keep it counting,
(its act Like "reset" for the leftover counter).
i know why you wrote the number 36000000 and not 24000000 or something else,
first, this number is the time in milliseconds the express 10 hours, and if you put other number like 24000000 its will count each 6.67 hours.
the calculation for that is
100060=60000
60000
60=3600000
3600000*10=36000000

your code help me understan how while works, and what -= means, thanks :slight_smile:

about the button problem,
i added the lines to the code, and its looks like this:

  // check for a high to low transition if true then found a new button press while clock is not running - start the clock    
  if (lastButtonState != buttonState &&  blinking == false)
  {   
    startTime = millis();                             // store the start time
    blinking = true;                                  // turn on blinking while timing
    delay(12);                                         // short delay to debounce switch
    lastButtonState = buttonState;                    // store buttonState in lastButtonState, to compare next time      
  }

  // check for a high to low transition if true then found a new button press while clock is running - stop the clock and report
  else if (lastButtonState = buttonState && blinking == true)
  {   
    blinking = false;                                    // turn off blinking, all done timing
    lastButtonState = buttonState;                       // store buttonState in lastButtonState, to compare next time

      /////////////////////////////////////////////
    //     Routine to report elapsed time            
    /////////////////////////////////////////////   
    unsigned long elapsedTime = millis() - startTime;
    // now we know how much time, in milliseconds
    // next, we initialize variables for the digits
    byte hourTens = 0; 
    byte hourOnes = 0;
    byte minTens = 0; 
    byte minOnes = 0;
    byte secTens = 0; 
    byte secOnes = 0;
    byte frameTens = 0; 
    byte frameOnes = 0;
    // now, let's do some math
    unsigned long leftover = elapsedTime;
    while (leftover >= 36000000)
    { 
      leftover -= 36000000; 
      hourTens++; 
    }
    while (leftover >=  3600000) 
    { 
      leftover -=  3600000; 
      hourOnes++; 
    }
    while (leftover >=  600000) 
    { 
      leftover -=  600000; 
      minTens++; 
    }
    while (leftover >=   60000) 
    { 
      leftover -=   60000; 
      minOnes++; 
    }
    while (leftover >=   10000) 
    { 
      leftover -=   10000; 
      secTens++; 
    }
    while (leftover >=    1000) 
    { 
      leftover -=    1000; 
      secOnes++; 
    }
    // the code below assumes 25 frames per second (1 frame = 40 ms)
    // if you want something different, you will have to change it
    while (leftover >= 400) 
    { 
      leftover -= 400; 
      frameTens++; 
    }
    while (leftover >=  40) 
    { 
      leftover -=  40; 
      frameOnes++; 
    }

    lc.setDigit(0,0,frameOnes,false);  
    lc.setDigit(0,1,frameTens,false);
    lc.setDigit(0,2,secOnes,true);
    lc.setDigit(0,3,secTens,false);
    lc.setDigit(0,4,minOnes,true);
    lc.setDigit(0,5,minTens,false);
    lc.setDigit(0,6,hourOnes,true);
    lc.setDigit(0,7,hourTens,false);  
  }

  else
  {
    lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
  }

now its only count when the i keep the button pressed, i want it start the clock in first press, and pause in second press and reset it after another press.

sketch is attached

timecode_prototype4.ino (7.76 KB)

now its only count when the i keep the button pressed, i want it start the clock in first press, and pause in second press and reset it after another press.

Then, you need to restructure your code. You need to separate the counting of the switch presses from the use of the switch press count.

There should be completely independent blocks of code to count the presses and to use the count.

PaulS:

now its only count when the i keep the button pressed, i want it start the clock in first press, and pause in second press and reset it after another press.

Then, you need to restructure your code. You need to separate the counting of the switch presses from the use of the switch press count.

There should be completely independent blocks of code to count the presses and to use the count.

ok, i will try to separate it

i notice that if i remove the clock code from the stop and report section its still running:
Before:

  // check for a high to low transition if true then found a new button press while clock is running - stop the clock and report
  else if (lastButtonState = buttonState && blinking == true)
  {   
    blinking = false;                                    // turn off blinking, all done timing
    lastButtonState = buttonState;                       // store buttonState in lastButtonState, to compare next time

      /////////////////////////////////////////////
    //     Routine to report elapsed time            
    /////////////////////////////////////////////   
    unsigned long elapsedTime = millis() - startTime;
    // now we know how much time, in milliseconds
    // next, we initialize variables for the digits
    byte hourTens = 0; 
    byte hourOnes = 0;
    byte minTens = 0; 
    byte minOnes = 0;
    byte secTens = 0; 
    byte secOnes = 0;
    byte frameTens = 0; 
    byte frameOnes = 0;
    // now, let's do some math
    unsigned long leftover = elapsedTime;
    while (leftover >= 36000000)
    { 
      leftover -= 36000000; 
      hourTens++; 
    }
    while (leftover >=  3600000) 
    { 
      leftover -=  3600000; 
      hourOnes++; 
    }
    while (leftover >=  600000) 
    { 
      leftover -=  600000; 
      minTens++; 
    }
    while (leftover >=   60000) 
    { 
      leftover -=   60000; 
      minOnes++; 
    }
    while (leftover >=   10000) 
    { 
      leftover -=   10000; 
      secTens++; 
    }
    while (leftover >=    1000) 
    { 
      leftover -=    1000; 
      secOnes++; 
    }
    // the code below assumes 25 frames per second (1 frame = 40 ms)
    // if you want something different, you will have to change it
    while (leftover >= 400) 
    { 
      leftover -= 400; 
      frameTens++; 
    }
    while (leftover >=  40) 
    { 
      leftover -=  40; 
      frameOnes++; 
    }

    lc.setDigit(0,0,frameOnes,false);  
    lc.setDigit(0,1,frameTens,false);
    lc.setDigit(0,2,secOnes,true);
    lc.setDigit(0,3,secTens,false);
    lc.setDigit(0,4,minOnes,true);
    lc.setDigit(0,5,minTens,false);
    lc.setDigit(0,6,hourOnes,true);
    lc.setDigit(0,7,hourTens,false);  
  }

  else
  {
    lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
  }

After:

  // check for a high to low transition if true then found a new button press while clock is running - stop the clock and report
  else if (lastButtonState = buttonState && blinking == true)
  {   
    blinking = false;                                    // turn off blinking, all done timing
    lastButtonState = buttonState;                       // store buttonState in lastButtonState, to compare next time
  }

  else
  {
    lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
  }

its running because the code also in the run commands section,
i want to know if its ok to run it like this,
and what is the difference if the code is in the report section or not

i will also attach the files:

timecode_prototype4.ino - without changes

timecode_prototype5.ino -with changes

thanks

timecode_prototype4.ino (8.06 KB)

timecode_prototype5.ino (6.37 KB)

else if (lastButtonState = buttonState && blinking == true)

I see you've found an Arduino-code gotcha.
You need to write == there, not just =.

odometer:

else if (lastButtonState = buttonState && blinking == true)

I see you've found an Arduino-code gotcha.
You need to write == there, not just =.

I changed it to == , i complied it
and its not working when i press the button,
its keep the display on 00000000

When you remove your finger from the button, the switch might bounce.
From your description, it sounds like that is what your switch does.

Whenever the button changes state, you need to do debouncing. That is:
When the button goes from HIGH to LOW, you need to debounce.
When the button goes from LOW to HIGH, you also need to debounce.

Also: you say you want this behavior when you press the button:
1st press: START
2nd press: STOP
3rd press: RESET
It sounds like you will only be using one button. Is this correct?
I have a mechanical stopwatch with only one button, and this is exactly how it works: first press is START, second press is STOP, third press is RESET.
This means you will have to count to 3. I suggest having a variable that counts button presses, but only up to 3. So if it gets bigger than 3, you will need to go back to 1. Something like this:

byte pressCount = 0; // define your variable
const byte pressMax = 3; // we're only going up to 3


// do this when the button is pressed
pressCount++;
if (pressCount > pressMax) pressCount = 1;

so pressCount will start from 0 and then go 1, 2, 3, 1, 2, 3, 1, 2, 3, ...