Using millis as a delay after an input

I am trying to use millis to get rid of every "delay" in my program but cant figure out how to or if I even can use one millis if statement to delay 3 different things.

so a button is pressed and an LED will flash and after a second, a second LED will flash. Is it possible to have a millis "if" statement that will start when the first LED comes on. I could put the millis if statement in the button press statement but I want to have one millis if as a set delay for 3 different functions.

does this make sense?
and is it possible if you can comprehend what I have tried to say?

thanks :slight_smile:

Is this LED, and the other one, going to turn on once just briefly (ie flash) or will they continue to turn on and off (ie blink) ?

Either way you cannot control them with a single if statement, but you could program a state machine (sounds scary but isn't) and use millis() to control the time spent in each state

while delay() waits for a period of time to expire, millis() is used to determine when a period of time is expired

so millis() is often used in a conditional test within loop() to determine when the time is expire and to take some action. it may be one of several conditional tests within loop(). in your cases: a condition for a button press and a time to expire

the button press needs to turn on an LED and capture a timestamp to measure the period of time from

the millis() condition could AND a flag indicating a to wait for a time to expire

when a time expires, the condition can check to see which LED is on (i.e.digitalRead()) to change which LED is on an capture a new timestamp for the 2nd LED

For sure, you can create a timed sequence of events using millis(). Each event is timed the same way by comparison of millis with the time stamp. But, only the last event resets the time stamp. Does that make sense? :slight_smile:

so it'll stay on when the button is held and then after the time the second one will come on.

can the state machine be used as a delay for different functions?

Do you mean, only when the button is held down for a long time, or any time it's pressed?

The problem really is your English, sorry! It's not clear what you want to do. As I understand it, you just want to trigger a LED sequence when a button is pressed. You don't need any state machine for that.

In such cases of unclear understanding, it's best to draw a timing diagram. It's what engineers do.

So neither LED will actually flash or blink, just come on and stay on whilst the button is pressed and presumably turn off when the button is released

It sounds like the states will be
WAITING_FOR_BUTTON_PRESS
LED1_ON_WAIT_1_SECOND
LED2_ON

If at any time the button is released, turn off both LEDs and go back to the WAITING_FOR_BUTTON_PRESS state. Does that sound right ?

The state machine can only be in 1 state at a time, but each state could do more than 1 thing or you could have more tha1 state machine for unrelated actions

Please use Google translate, or provide a timing diagram. It's guesswork to understand what you want.

Hello smellypanda
Create and post a timing diagram with all the dependencies to see how we can help. A picture is always better than 1000 words.
Have a nice day and enjoy coding in C++.
Дайте миру шанс!

no
a state machine can change the behaviour of you code based on stimuli (e.g. button press, time expiring)

flashing means

at timepoint 1 switch LED on
at timepoint 2 switch LED off

repeat
or with example-timestamps
0:00 switch LED on
0:02 switch LED off
0:04 switch LED on
0:06 switch LED off

the switch on / switch off has to be repeated.

With non-blocking timing the repeating is done by

void loop()

no other loops required there are even no other loops allowed
because these other loops would have the same effect as delay() = blocking code-execution

So as pseudo-code blinking an LED looks like this

void loop()
  if (someTimeHasPassedBy) {

    // change LED-state
    if (LED_IS_switched_On) {
      switchLedOff();
    }

    if (LED_IS_switched_Off) {
      switchLedOn();
    }      
  }
}

a better structured version of this code is to declare a function named changeLED_State()


void changeLED_State() {
  if (LED_IS_switched_On) {
    switchLedOff();
  }

  if (LED_IS_switched_Off) {
    switchLedOn();
  }
}


void loop() {
  if (someTimeHasPassedBy) {
    changeLED_State();
  }
}

the name of the function is self-explaining. No additional comment needed

Doing even more advanced things like

wait for a button-press before any blinking starts
start blinking a second led after same time has passed by since the first LED started blinking
is best coded using a state-machine.

This kind of functionality is medium advanced and you need a medium amount of code to make this work which means a medium amount of things to learn new.

best regards Stefan

okay so i have a counter which has an up and a down button, when i press the button i want an LED to come on and a second later i want the second one to come on and both stay on for a second.( i want the count down button to turn the lights on the opposite) i have used millis as a delay but i have to put the millis if statement between each command.

i want to know if i can have one millis timer to act as a delay for counting up and down so two separate sequences. so i can put the same delay in two sequences and not have to put the whole millis if timer in each command.

does this make sense?

It makes sense, but that sense is deceptive because so many different interpretations can be attached to it.

Yes, you can use only one time stamp to run a sequence. See reply #4.

...but now you are introducing yet more confusing language, "two separate sequences"... seriously, you must post a drawing. People are trying to guess what you mean.

seems it's not sinking in

consider

const byte ButPin = A1;
const byte LedPins [] = { 12, 13 };

unsigned long  msec;
unsigned long  msecLst;

enum { Off = HIGH, On = LOW };


// hope this isn't a homewrok assignment

void loop() {
    msec = millis ();

    if (msecLst && (msec - msecLst) > 1000)  {
        if (On == digitalRead (LedPins [0]))  {
            digitalWrite (LedPins [0], Off);
            digitalWrite (LedPins [1], On);
            msecLst = 0 == msec ? 1 : msec;
        }
        else {
            digitalWrite (LedPins [1], Off);
            msecLst = 0; 
        }
    }

    if (LOW == digitalRead (ButPin))  {
        digitalWrite (LedPins [0], On);
        msecLst = 0 == msec ? 1 : msec;
    }
}

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

    pinMode (ButPin, INPUT_PULLUP);

    for (unsigned n = 0; n < sizeof(LedPins); n++)  {
        digitalWrite (LedPins [n], Off);
        pinMode      (LedPins [n], OUTPUT);
    }
}

The main thing about millis() is it is

NON-waiting

in a linear way

linear way would be
execute command 1
wait (and do nothing else than waiting)
execute command 2

non-blocking timing is

completely different!

non-blocking timing is based on

looping.

The train will arrive at 6:15 pm

you are early at the railway-station and arrive at 6:05 pm

You start reading the newspaper
you take a look onto your watch. Watch shows 6:07 pm (not yet time for the train to arrive)
you look up your WhatsAppMessages
you take a look onto your watch. watch shows 6:08 pm (not yet time for the train to arrive)
you by some sweets from an sweet-automat
you take a look onto your watch. watch shows 6:09 pm (not yet time for the train to arrive)
...

You do a repeated look onto your watch if the right time is here

That is the basic principle of non-blocking timing

If you would take the effort of reading the tutorial you would surely grasp it
But I'm unable to click your mouse. This is something you must do yourself

best regards Stefan

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