Have a loop run for X amount of time

Hi,

I am trying to make a program to control some LED's. There are two inputs. English and French. Each input also has an LED. Before anyone has pushed a button, the LED's will flash alternately. Once someone pushes the a button, that button will stay illuminated for X amount of time. Then go back to alternate flashing.

My code is a bit messy right now, but I'm looking for advice on concept. Is it possible to:

Run a loop until digitalRead detects a HIGH.
Then - digitalRead runs if statement loop. That loop will run for X amount of seconds. Then return to main loop.
I cannot use delay commands since I need it to always be open to input even during the timed loop. Ie. While running the second loop, pushing a button can restart that loop.

Biggest thing I'm looking for is how to run an if statement for X amount of time, then to go back to the main loop.

Hope that is clear.

Thank you!

toedip:
Run a loop until digitalRead detects a HIGH.

Yes.

Then - digitalRead runs if statement loop. That loop will run for X amount of seconds. Then return to main loop.
I cannot use delay commands since I need it to always be open to input even during the timed loop. Ie. While running the second loop, pushing a button can restart that loop.

So you need a counter that gets sets to 0. Every time it blinks, counter gets incremented. Your blink code will check how many times it's blinked to determine if it needs to blink again.

Sounds like you're looking for a state machine.

Hey,

Thanks for the reply.

I'm not familiar with the counter part. I'll do some research.

Is this not possible with a millis variety?

If input = high, run loop for x amount of time until time runs out or input = high again.

Seems simple, haha.

Thanks

toedip:
Is this not possible with a millis variety?

If input = high, run loop for x amount of time until time runs out or input = high again.

Seems simple, haha.

Thanks

It's entirely possible, but if you can't use delay, then you need to start getting away from calling it a loop. It's a state machine, which is If the state is this, do this, otherwise if it's that, do that, etc.. Having the LED blink as one of the states is trivial, you just need to determine the conditions in which the LED will start/stop blinking and change the state when those happens.

Hey,

It's good to clear my terminalogy up. Thanks,

I guess my trouble is how to tell one LED to stay high, and the other low for a certain time frame once the state has been requested to change.

toedip:
I guess my trouble is how to tell one LED to stay high, and the other low for a certain time frame once the state has been requested to change.

The blink without delay example shows you how to blink an LED using millis(). That code can pretty much be copied into the state machine code.

Yeah, That's what I've used for my timing portion.

I still cannot get the timing right once I push the button. This doesn't work how I want, but if it hasen't been running for 10 seconds yet, it sort of does what I want. haha.

void loop()

{
 
  EVAL = digitalRead(EBUTT);

  if(EVAL == HIGH) {
    delay(10);
       
    while(millis() < EndTime) 
    {
       digitalWrite(ELED, HIGH);
       digitalWrite(FLED, LOW);
    }
      // Still need to tell it to stay in this state for VIDEO LENGTH
  
        unsigned long FStartTime = millis();
        
      if(FStartTime - Zero > FEndTime)
    {
        Zero = FStartTime;
      
      if (FSTATE == LOW)
        FSTATE = LOW;
       else
        FSTATE = LOW;
   
       digitalWrite(FLED, FSTATE);
        

    }  
  } 
  else 
  {
     unsigned long ECurrentFlashMillis = millis();
 
     if(ECurrentFlashMillis - EPrevFlashMillis > Einterval) 
     {
      EPrevFlashMillis = ECurrentFlashMillis;
 
       if (ESTATE == LOW)
        ESTATE = HIGH;
       else
        ESTATE = LOW;
   
       digitalWrite(ELED, ESTATE); 
     }   
         
      unsigned long FCurrentFlashMillis = millis();
 
        if(FCurrentFlashMillis - FPrevFlashMillis > Finterval) 
    {
        FPrevFlashMillis = FCurrentFlashMillis;
 
       if (FSTATE == LOW)
        FSTATE = HIGH;
       else
        FSTATE = LOW;
   
       digitalWrite(FLED, FSTATE); 
     } 
  }
}

Sorry,

I've been doing a lot of trial and error / cutting and pasting. There is a big chunk of that code I am not using. The last part is blinking without delay basically. That part is working fine.

I just need to keep one LED (ELED) solid for 10 seconds when I push the button.

Appreciate your help.

Cheers,

one more question.

millis() is a timer from the start of your program.

Is there a way to start a new timer, based off of millis, that starts at 0.

So...

Program starts... millis starts counting away.

Some random time based on user input... start countring from 0 now, start state 2
now I have a reference, and 10 seconds after I started state 2, go back to the state 1.

    while(millis() < EndTime) 
    {
       digitalWrite(ELED, HIGH);
       digitalWrite(FLED, LOW);
    }

What exactly are you going for here?

      if (FSTATE == LOW)
        FSTATE = LOW;
       else
        FSTATE = LOW;

If FSTATE is LOW, set it to LOW, otherwise, set it to LOW. Think about that one for a minute.

toedip:
one more question.

millis() is a timer from the start of your program.

Is there a way to start a new timer, based off of millis, that starts at 0.

So...

Program starts... millis starts counting away.

Some random time based on user input... start countring from 0 now, start state 2
now I have a reference, and 10 seconds after I started state 2, go back to the state 1.

Why bother? If you need to time two real life activities that start at different times, do you need two separate clocks? That question tells me that while you've looked at the Blink without Delay code, you don't truly understand it. Play around with the code until you are completely comfortable with how it works and what happens when you make changes to it. It's such a fundamental part of learning to program with the Arduino, that's it's not worth skipping over learning it completely.

Hey,

Sound advice.

It's a work project, and in most places it's about productivity not learning :wink: I've never coded before, and also have never worked with Arduino. Figured it's a good way to go since the Arduino can be used for many projects around here once I get a grasp on it.

The first block of code you quoted I was playing with my concept. I just wanted to see if that function worked. EndTime was set to 10 seconds, so as long as I pushed the first input before 10 seconds it would perform as hoped. I just need a way to replace millis() with a timer function starting at 0 seconds when the button is pushed.

The second piece of code I was tinkering with that concept. I wanted the FLED which was controlled by FSTATE to be Low while my timer was still going. Yes, that proves my lack of understanding at this point :wink:

I spent some time looking at Blink without delay and manipulating it. Your assumption is correct, I do not understand it fully. I'll review it again.

It just seems like there should have been an easier way to start a clock from 0 at a designated time. I think that with that idea I can perform my task, but I cannot figure that out yet.

Thanks again for your replies, much appreciated.

Hi,

Perhaps you could clear one part up for me then. I'm not sure how one line works.

unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

"unsigned long currentMillis = millis();"

unsigned long is a variable, currentMillis is the name of that variable. I get that much. but when you = it to millis(), doesn't that mean your setting currentMillis as a clock that keeps on counting till the counter maxes out and resets?

Then your saying if currentMillis (the counter that keeps on counting) - (minus) previousMillis (which was set to zero), is greater than interval (1000ms) then:
reset curentMillis to previousMillis which equals 0. So how can you reset currentMillis to 0 if currentMillis = millis().

I'll keep playing in the meantime :slight_smile:

Thanks again

"unsigned long currentMillis = millis();"

unsigned long is a variable, currentMillis is the name of that variable. I get that much. but when you = it to millis(), doesn't that mean your setting currentMillis as a clock that keeps on counting till the counter maxes out and resets?

No - you're asking millis how long the arduino has been running and storing that time in the currentMillis variable. It won't change by itself.

To use PaulS' usual analogy, you're asking someone the time and when they say ten past twelve, you write it in your notebook to look up later so you can figure how much time has passed since you wrote it.

Hi,

Yeah it's starting to make more sense now. I was looking at one part backwards. So

unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;

That makes sense to me now.

But I still cannot manipulate that into a second state. Where instead of flashing. I need ELED to stay on for 10 seconds. FLED stays off.

 EVAL = digitalRead(EBUTT);

  if(EVAL == HIGH) {
    delay(10);
    
       unsigned long ECurrentFlashMillis = millis();
 
     if(ECurrentFlashMillis - EPrevFlashMillis > EPlayInterval) 
     {
      EPrevFlashMillis = ECurrentFlashMillis;
 
       if (ESTATE == LOW)
        ESTATE = HIGH;
       else
        ESTATE = HIGH;
   
       digitalWrite(ELED, ESTATE);

I tried making a new interval. EPlayInterval.

Hey,

Think I have a working product for what I wanted. Whew! Thanks all for the help.

if(EVAL == HIGH) 
  {
     unsigned long Time = millis();
     
     while(millis() <  Time + 10000) 
    {
            
       digitalWrite(ELED, HIGH);
       digitalWrite(FLED, LOW);

After 10 seconds it goes back to flashing mode, which is exactly what I wanted.

thanks!

toedip:
The first block of code you quoted I was playing with my concept. I just wanted to see if that function worked. EndTime was set to 10 seconds, so as long as I pushed the first input before 10 seconds it would perform as hoped. I just need a way to replace millis() with a timer function starting at 0 seconds when the button is pushed.

The second piece of code I was tinkering with that concept. I wanted the FLED which was controlled by FSTATE to be Low while my timer was still going. Yes, that proves my lack of understanding at this point :wink:

For future reference, It's a good idea to remove "tinkering code" if it isn't part of your actual project. Otherwise, it is distracting and leads to wasted time when you're seeking help.