millis() for displaying duration

I want to display continous duration after you press button2. The code is working correctly, except one thing and I cannot figure out why!!
When it starts the counting for example at ‘00:00:49’ instead of going to the next second it will display ‘00:00:0429’ and then freezes on that number until 11sec past and it goes up to displaying 1minute and seconds starts over again until it get to 49sec and does it again. When I ran the program at different times sometimes it would do the same thing at 53sec.
My seconds code is inside elapsedTime() at very bottom.
Why would it be doing that at random times? I can’t seem to figure it out. Please someone help.

Here’s my full code

#include <SCP1000.h>

#include <LiquidCrystal.h>

#define SlaveSelect 10

int buttonPin1= 18;
int buttonPin2 = 19;
LiquidCrystal lcd(9, 8, 5, 4, 3, 2);
SCP1000 scp(SlaveSelect);

int prevButtonState1;
int prevButtonState2;

unsigned long startTime;
unsigned long elapsedTime;
unsigned long elapsedSec;
unsigned long elapsedMin;
unsigned long elapsedHr;
int flag1;
int flag2, flag3,flag4;
int timeFlag;
int run;
int buttonState1;
int buttonState2;

void setup()
{
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  digitalWrite(buttonPin1, LOW);  // pulldown resistors
  digitalWrite(buttonPin2,LOW);
  scp.init();
  lcd.begin(20, 4);
  lcd.setCursor(2,1);
  lcd.print("Trail Tracker Co.");
  delay(2000);
  lcd.clear();
}




void loop(){
  
  buttonState1 = digitalRead(buttonPin1);  //records current state of button1 and button2
  buttonState2 = digitalRead(buttonPin2);
 // checks first button for press and sets flags to opposite
  if(buttonState1 == HIGH && prevButtonState1 == LOW){
    flag1 = !flag1;
    prevButtonState1 = buttonState1;
  }  
   if(flag1 == true){
    screen2();
    prevButtonState1 = buttonState1;
  }
  if(flag1 == false){
    screen1();
     timeElapsed();
    
    prevButtonState1 = buttonState1;
  }
  if(buttonState2 == HIGH && prevButtonState2 == LOW && flag3 == false){ 
   flag3 = !flag3;
   lcd.clear();
   lcd.setCursor(0,1);
   lcd.print("Logging has been started");
   delay(3000);
   startLog();
   lcd.clear();
   prevButtonState2 = buttonState2;
  } 
  else if(buttonState2 == HIGH && prevButtonState2 == LOW && flag3 == true){
    flag3 = !flag3;
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("Logging has been stopped");
    delay(3000);
    stopLog();
    lcd.clear();
    prevButtonState2 = buttonState2;
  }
  else{
     prevButtonState2 = buttonState2;
  }
  
 
  
}//end loop
double velocity(double acc, double time){

  return acc * time/3600;


}
void screen1(){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Duration:");
    if(timeFlag == true){
      timeElapsed();
    }
    lcd.setCursor(0,1);
    lcd.print("Distance: ");
    lcd.setCursor(0,2);
    lcd.print("Real time:");
    lcd.setCursor(0,3);
    temperature();
    
    delay(100);
  

}
void screen2(){
    
    lcd.clear();
    lcd.setCursor(0,0);  
    lcd.print("Velocity: ");
    double vel = velocity(50,389.5);
    lcd.print(vel);
    lcd.print("mi/hr");
    lcd.setCursor(0,1);
    altitude();
    lcd.setCursor(0,2);
    lcd.print("Coordinates: ");
    delay(100);
  
}
void startLog(){
  //will do the function of starting writing to SD card
  timeFlag = true;
  startTime = millis()/1000;
}
void stopLog(){
 //will do the function of stopping writing to SD memory card
}
void temperature(){
  scp.readSensor();
  lcd.print("Temperature: ");
  lcd.print(1.8*scp.TempC+32);
  lcd.write(223);
  lcd.print("F");
}
void altitude(){
  //Pref = 1013.25; // reference of sea level
  scp.readSensor();
  lcd.print("Altitude: ");
  lcd.print(((1-pow((scp.BaroP/1013.25),0.190284))*145366.45)); //conversion to altitude  
  lcd.print("ft");
}
void timeElapsed(){
  
   
   lcd.setCursor(10,0);
   elapsedTime = millis()/1000; //determine duration current millis - start millis
   
   elapsedSec = elapsedTime;
   elapsedMin = elapsedSec/60;
   elapsedHr = elapsedMin/60;
   //output hour
   if(elapsedHr < 10){
   lcd.print("0");
   lcd.print(elapsedHr);
   lcd.print(":");
 }
   else{
     lcd.print(elapsedHr);
     lcd.print(":");
   }
   //output minutes
   if(elapsedMin < 10){
   lcd.print("0");
   lcd.print(elapsedMin);
   lcd.print(":");
 }
   else{
     lcd.print(elapsedMin);
     lcd.print(":");
   }
   //output sec
     
     elapsedSec = elapsedSec%60;
     if((elapsedSec - startTime)< 10){
      lcd.print("0");
      lcd.print(elapsedSec-startTime);
     }
      else
      lcd.print(elapsedSec-startTime);
     
    
}

if change this:

elapsedSec = (elapsedSec-startTime)%60;
     if((elapsedSec - startTime)< 10){
      lcd.print("0");
      lcd.print(elapsedSec);
     }
      else
      lcd.print(elapsedSec);

now the seconds are right, displaying 60sec cycle
BUT the minutes are messed up now… when it turns to 53sec the minutes are updated instead of 60sec. I fix one thing and then something else gets messed up :-[

The timeElapsed function may be called many, many times per second. You probably do not want to be updating the LCD screen more than once a second. So, keep track of the last second displayed on the LCD, and only update the time when that seconds value has changed.

Suppose the Arduino has been running for an hour and 15 minutes. The millis() function will return a value like 4,500,000. This you divide by 1000, and store in elapsedTime, as 4500.

You then store this in elapsedSec. You divide the value in elaspsedSec by 60 to store in elapsedMin, resulting in elapsedMin containing 75.

You then divide elapsedMin by 60, and store the result (1) in elapsedHr. The elapsedHr, elapsedMin, and elapsedSec variables are all declared unsigned long, which is really overkill for a variable that is supposed to store a value from 0 to 59 (in some cases).

You never adjust elapsedMin to subtract whole hours that have elapsed.

You do adjust elapsedSec, but incorrectly. The value in elapsedSec should be the current value % 3600, not 60.

All the values should be adjusted before any are printed.

I suspect, though, that the problem you are having is caused by trying to write to the LCD too often.

Suppose the Arduino has been running for an hour and 15 minutes. The millis() function will return a value like 4,500,000. This you divide by 1000, and store in elapsedTime, as 4500.

You then store this in elapsedSec. You divide the value in elaspsedSec by 60 to store in elapsedMin, resulting in elapsedMin containing 75.

You then divide elapsedMin by 60, and store the result (1) in elapsedHr. The elapsedHr, elapsedMin, and elapsedSec variables are all declared unsigned long, which is really overkill for a variable that is supposed to store a value from 0 to 59 (in some cases).

My program is doing that exactly. The reason I declared it as unsigned long because that's what millis(); are in, and I didnt want to worry about casting. Is it bad?

You do adjust elapsedSec, but incorrectly. The value in elapsedSec should be the current value % 3600, not 60

Not sure what you mean by this? It outputs the seconds correctly. If i do put in %3600 its not working.

Thanks for response.

I have an idea of what my problem is…

code below is my previous code, it perfectly displays time count with all sec and min working. But I want it to start count when I press button2. In this code it starts to count as soon as the board starts

void timeElapsed(){
   lcd.setCursor(10,0);
   //startTime = millis(); //store millis as its start time
   elapsedTime = millis()/1000;// - startTime; //determine duration current millis - start millis
   elapsedSec = elapsedTime;
   elapsedMin = elapsedSec/60;
   elapsedHr = elapsedMin/60;
   //output hour
   if(elapsedHr < 10){
   lcd.print("0");
   lcd.print(elapsedHr);
   lcd.print(":");
 }
   else{
     lcd.print(elapsedHr);
     lcd.print(":");
   }
   //output minutes
   if(elapsedMin < 10){
   lcd.print("0");
   lcd.print(elapsedMin);
   lcd.print(":");
 }
   else{
     lcd.print(elapsedMin);
     lcd.print(":");
   }
   //output sec
   if(elapsedSec < 10){
   lcd.print("0");
   lcd.print(elapsedSec);
 }
   else if(elapsedSec > 60){
     
     elapsedSec = elapsedSec%60;
     if(elapsedSec < 10){
      lcd.print("0");
     }
     lcd.print(elapsedSec);
   }
   else{
     lcd.print(elapsedSec);
   }

This is why I added variable startTime. That’s what been messing up. Now it does start count on the button2 press but doesnt display it correctly…

Print the values of elapsedHr, elapsedMin, and elapsedSec on the LCD or to the serial port, and open the Serial Monitor window.

I think that you will see that as elapsedMin increases over 59, it will continue increasing. You need an elapsedMin = elapsedMin%60 in the code, too.

Never mind what I said about the %60 vs %3600. You had it right. I spaced.

I still suspect that the problem is related to updating the LCD too often. Since writing 00:00:03 to the screen 500 times doesn’t make sense, try recording the value in elapsedSec the last time you wrote to the LCD, and don’t write again unless elapsedSec is different.

You're right about the min I will have to do it later, I wasnt worried about it I just wanted to get seconds to work.

I will try not to write to lcd that often. Even though I don't see why it was working before I added startTime. I found this site below, the guys does similar thing and it works for him. I don't want to copy somebody else's code I want mine to work and understand what's going on. I wish I could be better though :'( http://danthompsonsblog.blogspot.com/2008/11/timecode-based-stopwatch.html

At the risk of repeating myself, you are able to use Serial.print to write stuff to the Serial Monitor. Make use of that feature to write elapsedSec to the Serial Monitor each time that it is updated. You might need to add a delay (that you will later remove) of 500 milliseconds in order to reduce the amount of data being written to the Serial Monitor.

I’m sure that a review of the data being written to the serial monitor will quickly reveal the problem.

I got it to work through trying different things.

void timeElapsed(){


  lcd.setCursor(10,0);
  elapsedSec =millis()/1000 - startTime;
  elapsedMin = elapsedSec/60;
  elapsedHr = elapsedMin/60;
  //output hour
  if(elapsedHr < 10){
    lcd.print("0");
    lcd.print(elapsedHr);
    lcd.print(":");
  }
  else{
    lcd.print(elapsedHr);
    lcd.print(":");
  }
  //output minutes
  if(elapsedMin < 10){
    lcd.print("0");
    lcd.print(elapsedMin%60);
    lcd.print(":");

  }
  else{
    lcd.print(elapsedMin%60);
    lcd.print(":");
  }
  //output sec

  elapsedSec = elapsedSec%60;
  if(elapsedSec < 10){
    lcd.print("0");
    lcd.print(elapsedSec);
  }
  else
    lcd.print(elapsedSec);


}

At the first glance it seems that a line like

elapsedMin = elapsedMin%60;

is missing....

Hmm... weird. Its in my code. Must have added it after I posted the code. Thanks though, good eye :)