Race timer over 1 minute with millis

Hi! I built a sprint timer that uses millis to track the time. When you press the button to start the race, the Arduino does some subtraction to figure out the time, and when a light gate is tripped at the finish, the time and place are printed on the serial monitor. Currently, I can have the timer start and stop as many races as I want, and run for as long as I want. That all works properly. My only question is for when the timer goes over one minute, how should I print that on the serial monitor and increment that properly? I don't know if that would work with the way I store the time (current millis - millis = variable TIMER, when light gate is tripped, print TIMER/1000). Any help is much appreciated.

My code:

const int sensorPin = A5;
int sensorValue = 0;
int place = 1;
float timer;
float personTime;
unsigned long currentMillis = 0;
unsigned long prevMillis = millis;
int greenPin = 5;
int note = 1046;
int heat = 1;



const int  buttonPin = 2;      
int buttonPushCounter = 1;   
int buttonState = 0;         
int lastButtonState = 0; 




void setup() {
  
  pinMode(buttonPin, INPUT);
  
  pinMode(greenPin, OUTPUT);
  
  Serial.begin(9600);
}

void flash(){
  digitalWrite(greenPin, HIGH);
  tone(6, note);
  delay(100);
  digitalWrite(greenPin, LOW);
  noTone(6);
}
void playNote(){
  tone(6, note);
  delay(500);
  noTone(6);
}
void startRace(){
  Serial.print("Race ");
    Serial.print(heat);
    Serial.println(" started");
    
    flash();
    heat++;
}
void stopRace(){
  Serial.println("Race ended");
  flash();
}
void runTimer(){
  
  currentMillis = millis();
  timer = currentMillis - prevMillis;
  float personTime = timer/1000;
 
  sensorValue = analogRead(sensorPin);
  //for callibration
  //Serial.println(sensorValue);
  //delay(10);

  if(timer < 100){
    startRace();
  }
  
  
 if(sensorValue < 900){
  Serial.print("Place ");
    Serial.print(place);
    Serial.print(" Time: ");
    Serial.print(personTime, 3);
    Serial.println(" Seconds");
    flash();
    place++;
  }  
}


void stopTimer(){
  timer = 0;
  place = 1;
  prevMillis = millis();
  
}

void loop() {


  
  buttonState = digitalRead(buttonPin);

  
  if (buttonState != lastButtonState) {
    
    if (buttonState == HIGH) {
      
      buttonPushCounter++;
    } else {
      
    }
    
    delay(50);
  }
  
  lastButtonState = buttonState;


  
  if (buttonPushCounter % 2 == 0) {
    //Serial.println("GO!");
runTimer();   
  } else {
    stopTimer();
  }

}

Can you be a bit clearer in the way things need to work ?

Yep: I have a timer set up with millis so that it tracks sprint times down to the millisecond, but if the timer goes over one minute, it obviously would print 60.XXX and on from there. I am wondering if there is a good approach to making it so that it would print something more like 1.23.456.

Is this 1 minute and 23.456 seconds ?

1:23.456

BTW

Commenting your code goes a long way in explaining what is happening :writing_hand:

Yep. I have been tinkering for a while on this program, and 1:23.456 is actually what it (should) print.

    unsigned minutes = (personTime+.0005) / 60;
    personTime -= minutes * 60;
    Serial.print(minutes);
    Serial.print(':');
    Serial.println(personTime, 3);

This works (mostly), any ideas why it might flip to negative and start counting down from 40 once it gets to the minute mark?
Thanks for the help!

Update: I have been tinkering, and got it to start printing the minutes (for testing, I set a "minute" to be 10 seconds). Problem is, it only increments the minutes up by one (as it should), but it doesn't reset the seconds. I changed the variable for seconds to seconds so it is easier to work with. I have had one other problem during testing: the counter doesn't count up every millisecond (as it should), instead a seemingly random amount each time. I commented out all the functions that might be causing a delay, but it hasn't changed.

Updated code (sorry for the lack of comments, I don't usually put them in unless I need them later on)

const int sensorPin = A5;
int sensorValue = 0;
int place = 1;
float seconds;
float personTime;
unsigned long currentMillis = 0;
unsigned long prevMillis = millis;
int greenPin = 5;
int note = 1046;
int heat = 1;
unsigned long minutes = 0;
  


const int  buttonPin = 2;      
int buttonPushCounter = 1;   
int buttonState = 0;         
int lastButtonState = 0; 




void setup() {
  
  pinMode(buttonPin, INPUT);
  
  pinMode(greenPin, OUTPUT);
  
  Serial.begin(9600);
}


/*
void flash(){
  digitalWrite(greenPin, HIGH);
  tone(6, note);
  delay(100);
  digitalWrite(greenPin, LOW);
  noTone(6);
}
void playNote(){
  tone(6, note);
  delay(500);
  noTone(6);
}
void startRace(){
  Serial.print("Race ");
    Serial.print(heat);
    Serial.println(" started");
    
   // flash();
    heat++;
}
void stopRace(){
  Serial.println("Race ended");
 // flash();
}
*/
void runTimer(){
  currentMillis = millis();
  seconds = currentMillis - prevMillis;
  float personTime = seconds/1000;
  sensorValue = analogRead(sensorPin);
  //for callibration
  //Serial.println(sensorValue);
  //delay(10);

  /*if(timer < 100){
    startRace();
  }
  */
  if(seconds >= 10000 && seconds <=10020){
    Serial.println("MINUTE");
    minutes++;
    seconds = 0;
    currentMillis = millis();
  seconds = currentMillis - prevMillis;
  float personTime = seconds/1000;
   }
 if(sensorValue < 900){
   
  Serial.print("Place ");
    Serial.print(place);
    Serial.print(" Time: ");
    Serial.print(minutes);
    Serial.print(":");
    Serial.println(personTime, 3);
    //Serial.println(" Seconds");
    //flash();
    place++;
  }  
}


void stopTimer(){
  seconds = 0;
  place = 1;
  minutes = 0;
  prevMillis = millis();
  
}

void loop() {


  
  buttonState = digitalRead(buttonPin);

  
  if (buttonState != lastButtonState) {
    
    if (buttonState == HIGH) {
      
      buttonPushCounter++;
    } else {
      
    }
    
   delay(50);
  }
  
  lastButtonState = buttonState;


  
  if (buttonPushCounter % 2 == 0) {
    //Serial.println("GO!");
runTimer();   
  } else {
    stopTimer();
  }
  


  

}

:sleepy:

Another example:


const byte heartbeatLED     = 13;

unsigned long TIME;
unsigned int MINUTES;
unsigned int SECONDS;
unsigned int milliSeconds;

unsigned long heartbeatMillis;
unsigned long startMillis;


//                            s e t u p ( )
//*********************************************************************
void setup()
{
  Serial.begin(9600);

  pinMode(heartbeatLED, OUTPUT);

  startMillis = millis();

} //END of setup()


//                            l o o p ( )
//*********************************************************************
void loop()
{
  //***********************
  //time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 100)
  {
    //restart the TIMER
    heartbeatMillis = millis();

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));

    TIME = (millis() - startMillis);
    MINUTES = TIME / 60000ul;
    SECONDS = (TIME / 1000ul) % 60;
    milliSeconds = TIME % 1000ul;

    Serial.print(MINUTES);
    Serial.print(":");

    //print a leading zero ?
    if (SECONDS < 10)
    {
      Serial.print("0");
    }
    Serial.print(SECONDS % 60);
    Serial.print(".");
    Serial.println(milliSeconds);

  }

} //END of loop()



1 Like

Works fine for me. (I have added a leading 0 to the seconds field.)

unsigned long prevMillis = 0;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  unsigned long currentMillis = millis();
  float seconds = currentMillis - prevMillis;
  float personTime = seconds / 1000;

  unsigned minutes = (personTime + .0005) / 60;
  personTime -= minutes * 60;
  Serial.print(minutes);
  Serial.print(':');
  if ((personTime + 0.0005) < 10)
    Serial.print('0');
  Serial.println(personTime, 3);

  delay(1307);
}

Output at the roll-over:

0:52.302
0:53.610
0:54.918
0:56.225
0:57.533
0:58.841
1:00.148
1:01.456
1:02.763
1:04.070
1:05.378
1:06.685
1 Like

Just wondering, is there any reason for the delay at the end? That seems to make it rather difficult to stop the timer, and I'm not sure that is the best thing to have in a sprint timer... but otherwise this works great! Thanks so much!

Thanks for the help! I will start putting comments into my code and this snippet works as well!

For testing purposes I did not need multiple reports per millisecond. If you take out the delay you get:

0:59.950
0:59.950
0:59.951
0:59.952
0:59.953
0:59.954
0:59.955
0:59.955
0:59.956
0:59.957
0:59.958
0:59.959
0:59.960
0:59.960
0:59.961
0:59.962
0:59.963
0:59.964
0:59.965
0:59.965
0:59.966
0:59.967
0:59.968
0:59.969
0:59.970
0:59.970
0:59.971
0:59.972
0:59.973
0:59.974
0:59.975
0:59.975
0:59.976
0:59.977
0:59.978
0:59.979
0:59.979
0:59.980
0:59.981
0:59.982
0:59.983
0:59.984
0:59.984
0:59.985
0:59.986
0:59.987
0:59.988
0:59.990
0:59.990
0:59.991
0:59.992
0:59.993
0:59.994
0:59.995
0:59.995
0:59.996
0:59.997
0:59.998
0:59.999
1:00.000
1:00.000
1:00.001
1:00.002
1:00.003
1:00.004
1:00.005
1:00.005
1:00.006
1:00.007
1:00.008
1:00.009
1:00.010
1:00.010
1:00.011
1:00.012
1:00.013
1:00.014
1:00.015
1:00.015
1:00.016
1:00.017
1:00.018
1:00.019
1:00.020
1:00.020
1:00.021
1:00.022
1:00.023
1:00.024
1:00.024
1:00.025
1:00.026
1:00.027
1:00.028
1:00.029
1:00.029
1:00.030
1:00.032
1:00.033
1:00.034
1:00.035
1:00.035
1:00.036
1:00.037
1:00.038
1:00.039
1:00.040
1:00.040
1:00.041
1:00.042
1:00.043
1:00.044
1:00.045
1:00.045
1:00.046
1:00.047
1:00.048
1:00.049
1:00.050
1:00.050

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.