Double timer

I'm looking to do a double timer with 4 buttons one start and one stop for each side is this possible I have it set up now with one start button and two stop but I want to be able to have the timers start separate any help on coding this would be very appreciated.

Can you make a single timer with millis()? If not, look at the Blink Without Delay Example.

The "trick" with multiple timers is to use multiple durations and multiple previousMillis, such as duration1, duration2, previousMillis1, previousMillis2. Of course you may want to use more meaningful variable names, and of course there is only one currentMillis().

What have you tried already? What did you look up and learn?

Here is a good, simple and complete explanation for coding multiple things to happen together:

excerpt:

But what if you want to blink the two LEDs at different rates? Like, once a second for LED 1 and twice a second for LED 2?

This is where the delay function doesn't really help.

Let's look at an analogy. Say you want to cook breakfast. You need to cook:

Coffee - takes 1 minute
Bacon - takes 2 minutes
Eggs - takes 3 minutes

Now a seasoned cook would NOT do this:

Put coffee on. Stare at watch until 1 minute has elapsed. Pour coffee.
Cook bacon. Stare at watch until 2 minutes have elapsed. Serve bacon.
Fry eggs. Stare at watch until 3 minutes have elapsed. Serve eggs.

The flaw in this is that whichever way you do it, something is going to be cooked too early (and get cold).

In computer terminology this is blocking. That is, you don't do anything else until the one task at hand is over.

What you are likely to do is this:

Start frying eggs. Look at watch and note the time.
Glance at watch from time to time. When one minute is up then ...
Start cooking bacon. Look at watch and note the time.
Glance at watch from time to time. When another minute is up then ...
Put coffee on. Look at watch and note the time.
When 3 minutes are up, everything is cooked. Serve it all up.

In computer terminology this is non-blocking. That is, keep doing other things while you wait for time to be up.

I am doing a drag timing system or a low budget group with some kids right now I have it up and going using switch states when the light turns green the timer starts and ends with the car crossing a senor at the end but I need to change it to where the timer starts when the car moves out of the starting sensor on each side instead of both sides starting when the green light comes on to a true et time.

This is the code I am currently using just with out all my light commands if someone could even help me add a stop point I'm between my start and stop points on my left and right I'm using now I could program in the math to do what I want

// Dual stop watch with state machine
// output on serial monitor
// blinking led while running

const byte startPin     = 8;
const byte stopLeftPin  = 9;
const byte stopRightPin = 10;
const byte ledPin       = 13;

boolean buttonStartState     = HIGH;
boolean buttonStopLeftState  = HIGH;
boolean buttonStopRightState = HIGH;
boolean leftIsIn             = false;
boolean rightIsIn            = false;

byte state = 0;     // state machine states: 0 ... 3

unsigned long startTime;
unsigned long stopLeft;
unsigned long stopRight;
unsigned long raceTimeLeft;
unsigned long raceTimeRight;


void setup() {
  Serial.begin(9600);

  pinMode(startPin, INPUT_PULLUP);
  pinMode(stopLeftPin, INPUT_PULLUP);
  pinMode(stopRightPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}


void loop() {
  // read input pins:
  buttonStartState     = digitalRead(startPin);
  buttonStopLeftState  = digitalRead(stopLeftPin);
  buttonStopRightState = digitalRead(stopRightPin);

  switch (state) {
    case 0:        // make ready for start
      Serial.println("press start button");
      state++;
      break;

    case 1:       // waiting for start button press
      if (buttonStartState == LOW) {
        startTime = millis();
        Serial.println("START");
        state++;
      }
      break;

    case 2:      // running - waiting for left and/or right stop button press
      digitalWrite(ledPin, millis() / 128 % 2); // blink the led
      if ( (buttonStopLeftState == LOW) && (leftIsIn == false) ) {
        stopLeft = millis();
        raceTimeLeft = stopLeft - startTime;
        Serial.print("Left is in:  ");
        Serial.println(raceTimeLeft);
        leftIsIn = true;
      }
      if ( (buttonStopRightState == LOW) && (rightIsIn == false) ) {
        stopRight = millis();
        raceTimeRight = stopRight - startTime;
        Serial.print("Right is in: ");
        Serial.println(raceTimeRight);
        rightIsIn = true;
      }
      if ( (leftIsIn == true) && (rightIsIn == true) ) {
        digitalWrite(ledPin, LOW);
        leftIsIn  = false;
        rightIsIn = false;
        state++;
      }
      break;

    case 3:    // print the winner
      if (raceTimeLeft < raceTimeRight) {
        Serial.println("LEFT was first!");
      }
      else {
        Serial.println("RIGHT was first!");
      }
      state = 0;
      break;
  }

}

Each timer needs a start time of its own.

Put them in an array of 2 and the sensors likewise, you can process each as a set in alternating passes through loop() just by changing the index-to-run at start. The same code does for both sides and this loop() can run over 60KHz (implement a loop counter and see, it needs a start time too) so don't worry about ties, if they're less than X (where X > 0) millis apart call it a tie and time with micros instead of millis.

The millis count skips 6 values in the low 8 bits to make 0-256 fit 250 ms, you will never see the low 8 bits of millis == 255 (0xFF). When you subtract start from end, either may be either side of a skipped value giving an off by 1 result so when/where it matters and the timing is hour or less, use micros() that returns a continuous count since startup.

Buttons? Do you actually use contact switches?

Edit: Have you thought about putting accelerometers in the cars? You could sell those.

My original setup was Laser and receiver at start and finish now I have have retoreflective sensors at the end start lasers turn on my staging lights and indicates if the car has left before the green. I have no clue on how to even start to code the way you are talking about I am new to this and learn as I go. Would both cars still be able to leave at same time or would that have to run separate.

LarryD's State machine & timer tutorial may give you a starting point.

You don't know what an array is? Where did you get the code you have? It doesn't use arrays but it has a state machine.

I had some help from someone on here to do the state machine I was having trouble with doing the timer for two cars I never could get it right I have made some changes to what I posted here by adding my lights, sensor and lcd

You can use 2-3 state machines, one for Left and one for Right, and eventually one for the Race itself.

Give the states meaningful names, e.g. Waiting, Started, Stopped.
The race machine issues the start message and proceeds to Started.
The left and right machines wait for their start buttons, upon which they remember the start time and proceed to Started.
What shall happen if a Start button is pressed before the race machine announced the start, that's up to you. E.g. the race machine can wait for neither Start button pressed, before starting the next race.

In Started state the Left/Right machines wait for their stop buttons, do what's required and proceed to Stopped.
When both are Stopped, the race machine prints the race result and enters Stopped or Waiting state, just as you like.

Mikeh23:
I had some help from someone on here to do the state machine I was having trouble with doing the timer for two cars I never could get it right I have made some changes to what I posted here by adding my lights, sensor and lcd

An array is a way to group variables under one name.

const byte raceLanes = 8;
unsigned long timerStart[ raceLanes ]; // 8 UL's accessed as timerStart[ 0 ] through timerStart[ 7 ]

It could be 2 as easily as 8

Now each timer can be accessed by a number/variable value 0-7. The same code can work with any of them.

Same goes for the pin numbers. Pin # 3 should relate to timerStart[ 3 ] and any other values like raceState[ x ] for that lane.
The code to watch one lane would use pin[ whichLane ], timerStart[ whichLane ] and raceState[ whichLane ] to handle any one lane and whichLane would change from 0 to 7 over and over displaying messages based on each lanes state and results.

If all the lanes are to start at the same greenlight time then have a state that gives them all the same start time and let each run normally after that, the first to finish should print finished and time first.

So read about the arays last night I understand how to use them as outputs but didn't really find anything about inputs so if I go this route I can have a fixed start time for both lanes the read a time when both cars leave out of my start sensors and then stop both cars when they go through the finish sensor do I just right my complete code lites start button as normal then do a timing for just one lane and add the arays to do multiple lanes

does this look right for the main array code

  // read input pins:
    buttonStartState     = digitalRead(startPin);
    buttonStopReationState  = digitalRead(stopReactionPin);
    buttonStopFinishState = digitalRead(stopFinishPin);



    switch (state)
    {
      case 0:       // waiting for start button press

        if (buttonStartState == LOW)
        {
          digitalWrite(ledPin, millis() / 128 % 2); // blink the led
          Serial.println("START TIMER");
          startTime = millis();
          state++;
        }
        break;

          case 1:      // running - waiting for reaction & finish button press
       
        if ( (buttonStopReactionState == HIGH) && (Reaction == false) )
        {
          stopReaction = millis();
          reactionTime = (stopReaction - startTime);
          Serial.print("Reaction");
          Serial.println(reactionTime / 1000.0, 2);
          Reaction = true;
          state++;
        }
        break;
        
          case 2:      // running - waiting for finish button press
        if ( (buttonStopFinishState == LOW) && (Finish == false) )
        {
          stopFinish = millis();
          etTime = (stopFinish - stopReaction);
          raceTime = (stopFinish - startTime);
          Serial.print("Finish");
          Serial.println(reactionTime / 1000.0, 2);
          Serial.println(etTime / 1000.0, 2);
          Serial.println(raceTime / 1000.0, 2);
          lcd.setCursor(0, 1);
          lcd.print(etTime / 1000.0, 2);
          Finish = true;
        }

        if ( (Reaction == true) && (Finish == true) )
        {
          digitalWrite(ledPin, LOW);
          Reaction  = false;
          Finish    = false;
          
          state = 0;
        }
        break;

I don't think that you understand arrays and maybe mixed some other code up in what you got.

Array is just a group of variables that share the same name while each goes by a number.

const byte senseStart[ 2 ] = { 7, 8 }; // left start pin is senseStart[ 0 ], right start pin is senseStart[ 1 ]
const byte senseStop[ 2 ] = { 9, 10 };

byte raceState[ 2 ]; // because each lane must track its own progress

unsigned long startTime[ 2 ]; // left lane is startTime[ 0 ], right lane is startTime[ 1 ]
unsigned long stopTime[ 2 ];

byte whichLane; // default is 0

......

void loop()
{

switch( raceState[ whichLane ] )
{
// so in here you sense pins by [ whichLane ] to see only that side of the track
// you only need to check the start in case 0 and the stop in case 1 so do the needed read in the case that needs it.
// put the times in startTime[ whichLane ] and stopTime[ whichLane ] ... same code works for both lanes.
// this loop() will run so fast it will check both lanes > 10x per milli, it's effectively "at the same time".
}

if ( whichLane == 0 ) // set up whichLane for next run through loop()
{
whichLane = 1;
}
else
{
whichLane = 0;
}
}

I gotta go for now but will be back later. See what you can here and if you're not sure about anything shown (will get to both start at the same time later) then come up with good questions to fill the holes before you write the code.

Edit: IMO the best way to do this is start with code that works for 1 lane and walk you through 2 lanes and 2 start options.

i done this by making some changes to my original code i complied it and it passed but havent tested. The last post i was just tring to do the main code to be repeated i wasnt sure how to run my lights then the array with the inputs for 2 lanes ill work on the array some more it would simplify my project alot but not sure how to do it yet

// Dual stop watch with state machine
// output on serial monitor
// blinking led while running
#include <LiquidCrystal.h>
#include <IRremote.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

const byte startPin     = 26;
const byte stopRightPin = 11;
const byte stopLeftPin  = 10;
const byte ledPin       = 13;
int irstartPin = 23;
const int RECV_PIN = 22;
int prestagelPin = 8;
int prestageledlPin = 48;
int prestagerPin = 9;
int prestageledrPin = 46;
int stagestartPin = 24;
int stagelPin = 49;
int stagerPin = 45;
int yellow1Pin = 50;
int yellow2Pin = 51;
int yellow3Pin = 44;
int greenlPin = 52;
int greenrPin = 43;
int redlPin = 53;
int redrPin = 42;
int startinPin = 27;
int buttonstagel = 0;
int buttonstager = 0;
IRrecv irrecv(RECV_PIN);
decode_results results;

boolean buttonStartState     = HIGH;
boolean buttonStopLeftState  = HIGH;
boolean buttonStopRightState = HIGH;
boolean leftIsIn             = false;
boolean rightIsIn            = false;
boolean ljump = false;
boolean rjump = false;
boolean leftReaction = false;
boolean rightReaction = false;


byte state = 0;     // state machine states: 0 ... 3

unsigned long startTime;
unsigned long stopLeft;
unsigned long stopRight;
unsigned long stopLeftReaction;
unsigned long stopRightReaction;
unsigned long RightReactionTime;
unsigned long LeftReactionTime;
unsigned long LeftET;
unsigned long RightET;
unsigned long raceTimeLeft;
unsigned long raceTimeRight;



void setup()
{
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Left");
  lcd.setCursor(11, 0);
  lcd.print("Right");

  pinMode(prestageledlPin, OUTPUT);
  pinMode(prestageledrPin, OUTPUT);
  pinMode(stagelPin, OUTPUT); 
  pinMode(stagerPin, OUTPUT);
  pinMode(yellow1Pin, OUTPUT);
  pinMode(yellow2Pin, OUTPUT);
  pinMode(yellow3Pin, OUTPUT);
  pinMode(greenlPin, OUTPUT);
  pinMode(greenrPin, OUTPUT);
  pinMode(redlPin, OUTPUT);
  pinMode(redrPin, OUTPUT);
  pinMode(prestagelPin, INPUT_PULLUP);
  pinMode(prestagerPin, INPUT_PULLUP);
  pinMode(stagestartPin, INPUT_PULLUP);//Button to start
  pinMode(startPin, INPUT);
  pinMode(startinPin, OUTPUT);
  pinMode(stopLeftPin, INPUT_PULLUP);
  pinMode(stopRightPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  pinMode(irstartPin, OUTPUT);

  Serial.begin (9600);
  Serial.println("press start");
  irrecv.enableIRIn();
}

void loop()
{
  {
    buttonstagel = digitalRead(prestagelPin);
    buttonstager = digitalRead(prestagerPin);
    digitalWrite(irstartPin, LOW);
    digitalWrite(startinPin, HIGH);
  }
  if  (irrecv.decode(&results))
  {
    if (results.value == 0xFF22DD)
    {
      digitalWrite(irstartPin, HIGH);
    }
    irrecv.resume();
  }
  if (buttonstagel == LOW)
    digitalWrite(prestageledlPin, LOW);
  else
    digitalWrite(prestageledlPin, HIGH);
    
  if (buttonstager == LOW)
    digitalWrite(prestageledrPin, LOW);
  else
    digitalWrite(prestageledrPin, HIGH);
    
  if (digitalRead(stagestartPin) == HIGH)
  { digitalWrite(stagelPin, LOW);
    digitalWrite(stagerPin, LOW);
    delay(1000);
  
    digitalWrite(yellow1Pin, HIGH);
    digitalWrite(yellow2Pin, HIGH);
    digitalWrite(yellow3Pin, HIGH);
    digitalWrite(startinPin, LOW);


    
    if (digitalRead(prestagelPin) == LOW) //car must be staged till green
    {
      digitalWrite(greenlPin, LOW);
      Serial.println("Go left!");

    } else {
      digitalWrite(redlPin, LOW);
      ljump == true;
      Serial.println("Left Too early!");
    }
    if (digitalRead(prestagerPin) == LOW) //car must be staged till green
    { //car must be staged till green
      digitalWrite(greenrPin, LOW);
      Serial.println("Go right!");
    }
    else
    {
      digitalWrite(redrPin, LOW);
      ljump == true;
      Serial.println("Right Too early!");
    }
  }
  {
    // read input pins:
    buttonStartState     = digitalRead(startPin);
    buttonStopLeftState  = digitalRead(stopLeftPin);
    buttonStopRightState = digitalRead(stopRightPin);
    buttonstagel = digitalRead(prestagelPin);
    buttonstager = digitalRead(prestagerPin);


    switch (state)
    {
      case 0:       // waiting for start button press

        if (buttonStartState == LOW) 
        digitalWrite(ledPin, millis() / 128 % 2); // blink the led
        {
          Serial.println("START TIMER");
          startTime = millis();
          state++;
        }
        break;

      case 1:      // running - waiting for left and/or right Reaction button press
  
        if ( (buttonstagel == LOW) && (leftReaction == false) )
        {
          stopLeftReaction = millis();
          LeftReactionTime = (stopLeftReaction - startTime);
          Serial.print("Left Reaction  ");
          Serial.println(LeftReactionTime / 1000.0, 2);
          leftReaction = true;
        }

        if ( (buttonstager == LOW) && (rightReaction == false) )
        {
          stopRightReaction = millis();
          RightReactionTime = (stopRightReaction - startTime);
          Serial.print("Right Reaction  ");
          Serial.println(RightReactionTime / 1000.0, 2);
          rightReaction = true;
        }

          state++;
        
        break;
        
        case 2:      // running - waiting for left and/or right stop button press
        
        if ( (buttonStopLeftState == LOW) && (leftIsIn == false) )
        {
          stopLeft = millis();
          LeftET = (stopLeft - LeftReactionTime);
          raceTimeLeft = (stopLeft - startTime);
          Serial.print("Left Finished:  ");
          Serial.println(LeftReactionTime / 1000.0, 2);
          Serial.println(LeftET / 1000.0, 2);
          Serial.println(raceTimeLeft / 1000.0, 2);
          lcd.setCursor(0, 1);
          lcd.print(LeftET / 1000.0, 2);
          leftIsIn = true;
        }

        if ( (buttonStopRightState == LOW) && (rightIsIn == false) )
        {
          stopRight = millis();
          RightET = (stopRight - RightReactionTime);
          raceTimeRight = (stopRight - startTime);
          Serial.print("Right Finished: ");
          Serial.println(RightET / 1000.0, 2);
          Serial.println(RightReactionTime / 1000.0, 2);
          Serial.println(raceTimeRight / 1000.0, 2);
          lcd.setCursor(12, 1);
          lcd.print(RightET / 1000.0, 2);
          rightIsIn = true;
        }
        if ( (leftIsIn == true) && (rightIsIn == true) )
        {
          digitalWrite(ledPin, LOW);
          leftReaction = false;
          rightReaction = false;
          leftIsIn  = false;
          rightIsIn = false;

          state++;
        }
        break;


      case 3:    // print the winner
        if ( (raceTimeLeft < raceTimeRight) && (ljump == false))
        {
          Serial.println("LEFT WIN");
          lcd.setCursor(6, 2);
          lcd.print("<---");
          delay(9000);
          digitalWrite(greenlPin, HIGH);
          digitalWrite(greenrPin, HIGH);
          digitalWrite(redlPin, HIGH);
          digitalWrite(redrPin, HIGH);
          digitalWrite(stagelPin, HIGH);
          digitalWrite(stagerPin, HIGH);
        }
        if ( (raceTimeRight < raceTimeLeft) && (rjump == false))
        {
          Serial.println("RIGHT WIN");
          lcd.setCursor(6, 2);
          lcd.print("--->");
          delay(9000);
          digitalWrite(greenlPin, HIGH);
          digitalWrite(greenrPin, HIGH);
          digitalWrite(redlPin, HIGH);
          digitalWrite(redrPin, HIGH);
          digitalWrite(stagelPin, HIGH);
          digitalWrite(stagerPin, HIGH);
        }
        state = 0;
        
        break;



    }
  }

Most of the code you have above the switch statement actually belongs IN the switch statement, only you need to add some states.

The switch statement is there so that as the process progresses from state to state, it only runs the case code that fits what is going on in any pass through loop(). All the prestaging should have cases that come before the car ever moves.

How about figuring out in steps how this is supposed to work? This would be my #1, decide just what the code should do before writing. There's less work that way.

Also, your IR detect uses IRremote? Huh?

If you give a simple black bulb IR sensor a view that's restricted to your IR source (red leds make a lot of near-IR, you can see when they're on too), no other IR can be seen by the sensor so you don't need anything but the cheap simple, very very fast sensor. Put the bulb in one end of a flat-black-inside tube (blacken some paper or cardboard at one end, roll it up and tape it) and point that at the source to detect the IR then block the path with your hand to see it turns off.

Really the sensor doesn't have to be IR. A regular phototransistor and visible light will do when using a restricted view.
A phototransistor is a transistor that opens and closes by the strength of light falling on the junction.

These are IR phototransistors.

This shows shipping, just over $5 total but you gotta figure what to do with 100 sensors.

Shipping will be extra.
http://www.yourduino.com/sunshop/index.php?l=product_detail&p=209

Shipping is extra.
https://www.jameco.com/z/LPT2023-Ligitek-Phototransistor-IR-Chip-Silicon-NPN-Transistor-2-Pin-T-1_112176.html

When I buy at places with shipping fees, I get enough parts to spread the cost out.

the code i was using was workin but i wanted to take a additional time reading between the original start and stop so I added in case 1 and moved the original case 1 to case2 that's the code I added in the my last post
the sensors are photo sensors the ir remote starts the lights then the green light triggers the timer start the car is in the first sensor showing a low input when the car moves and makes the first sensor high i want to take a time reading. my start time to the time the car moves is my reaction time. then i want to take a time reading when the car goes though the finish sensor. from the first time to the finish time will be a total time then the time from when the car moved to the finish would be my et time. so will have a reaction, et, and a total time.

You have a red light, 3 yellow lights and then the green. I am assuming that from red, a "button" starts a timed pattern of yellows and then the green? Until the green the early start sensor should be read but from there to the stop there is no need to read that. Likewise why bother reading the stop sensor until after a good start?

Can you describe what happens as steps?

step 0 -- redlight light on, all others off. step 1 next

step 1 -- watch for race start signal.
watch for car start from that sensor, if sensor detects car pre-start then step 90 (false start case).
On signal turn red light off and yellow1 light on, set up yellow timer start and yellow led # that is lit then step 2 next after the timer runs out.

I will put the timer in before the switch-case, don't worry, one small block of code will do for all the race timers.

step 2 -- the timer is up, light the yellow led # led. edit: and turn the red and other yellows off?
watch for car start from that sensor, if sensor detects car pre-start then step 90 (false start case).
if yellow led # is 3 then set the timer for the green light step and then step 3 next.
else increment the yellow led number, set up the timer and stay on step 2.

step 3 -- the timer is up, light the green led, set race start time then step 4 next.

step 4 -- watch for the car to trip the start sensor, set car start time then step 5 next

step 5 -- watch for car to trip the stop sensor, when it does set stop time then step 6 next

step 6 -- calculate and show times then step 0 next

step 90 -- print out the false start message then step 0 next

Perhaps step 0 should have a button/signal so that cars can be positioned without making false start messages or perhaps the false start messages can help position the cars right up to the line?

The only sensors I see that you need are the car start and stop sensors and the race start button/sensor.
With the way that the state machine works, you really don't a lot of the variables you have now.

I see 16 pins needed, counting the IRremote. If you add sensors it will go up but you could profile each run that way.
What is with pre-stage sensors? Can't the start line sensor do for that?

Ok the first step is both cars roll into the start sensor input goes low turns a yellow light on on both sides

Step 1 wen I see cars are ready I use it remote to start lights yell lights

Step 2 if car moves and input goes high red light comes on if didn't move imput stays low and green light comes on and timer starts

Step 3 when car moves and signal goes high record time this is the reaction time

Step 4 car crosses finish input go low for stop time first start time and last stop is total time
First stop and second stop is it time

Step 5 display times and winner

Step 6 reset for rest/ turn of lights for next race

There is only 5 sensors in the set up 1 ir and a prestage/start sensor for each lane so 4 total
The prestage sensor is turning on my lights checks for the false start and is recording the first first stop time

The ir starts the light sequence and starts the timer

Then the finish sensor records the last stop time