Can multiple millis be used for independent events without slowing the loop?

Basically I don't want things to slow down.

Below are from different if statements

Led blink millis(50)
Display text then delete text (3000)
Display text 2 then delete (1000)
Display text 3 then delete (1000)
etc.

Any added code will take extra time to execute, but compared to one second timescales, the difference is negligible

There's only one millis(). But there's only one time measured by the clock on your wall. You can cook two things at the same time by looking at the clock and remembering when each one started and then pull them out of the oven at different times on the clock.

Use millis() to remember when each event started. Then every iteration of your main loop() function should check the time that each one should be stopped and do the appropriate action once millis() reaches that time.

ricekikr:
Basically I don't want things to slow down.

Below are from different if statements

Led blink millis(50)
Display text then delete text (3000)
Display text 2 then delete (1000)
Display text 3 then delete (1000)
etc.

Everything that a controller does will slow down all the other things that are done "at the same time".

But fortunately one millisecond is a relatively long time for a microcontroller.
The Arduino can execute 16000 instructions in just one millisecond.

So if one "command" like "display text" or "delete text" would use 16000 instructions to execute and you add another "command" that uses the same number of instructions to execute, this will slow down the program execution by 0.001 seconds when the command is executed.

Just evaluating one "if" condition comparing two numbers will most likely be done in less than 4 microseconds (64 instructions), so if you add one if-condition to the code, this will probably slow down the program execution by something like 0.000004 seconds.

Everything depends on the actual code that you are executing. If you add additional "command execution" that takes a lot of time such like 16000 instructions to do the action, it will slow down the program execution much more than if you add additional "if comparison" that takes very short time to execute.

Thanks for info.

MorganS:
There's only one millis(). But there's only one time measured by the clock on your wall. You can cook two things at the same time by looking at the clock and remembering when each one started and then pull them out of the oven at different times on the clock.

Use millis() to remember when each event started. Then every iteration of your main loop() function should check the time that each one should be stopped and do the appropriate action once millis() reaches that time.

Great. I remember reading somewhere here that multiple millis works almost like delay, in the sense that it waits for one milli timer before it starts another.

Time to write code.

ricekikr:
Thanks for info.

Great. I remember reading somewhere here that multiple millis works almost like delay, in the sense that it waits for one milli timer before it starts another.

Time to write code.

No, there's not a milli timer. It doesn't time things. You don't set it. It is just like the clock on the wall. No matter what you are doing, millis is always counting up 1 tick per millisecond. EVen if you never ever call it, it is still there ticking away. You can look at it any time you want and see what time it is relative to when the board was last reset. And using that time you can time out any number of things you want to time.

There are not multiple "milli timers" to start and stop or wait for one another. There is just the one clock, constantly ticking away. Just like the one one the wall at your house.

Here is a fruit basket you can pick what you need:

//State Machine example
//LarryD

byte messageNumber;
unsigned long TaskWait;
unsigned long FlashTime;
unsigned long currentmillis; 

//define the available machine states that we can have for this sketch
//add more states as needed
enum States{
  stateStart, stateApple, stateOrange, statePear, statePeach, stateKiwi};

//mState = machine State
States mState = stateStart;              //we start out in this machine state 

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

  pinMode(13, OUTPUT);
  FlashTime = millis();
  TaskWait = millis();                   //initialize the next wait time
  mState = stateStart;                   //we start out in this machine state 

} //        >>>>>>>>>>>>>> END OF setup() <<<<<<<<<<<<<<<<<


void loop()
{
  //leave this line of code at the top
  currentmillis  = millis();

  //***************************
  //just some code to see if the sketch is blocking
  if (CheckTime(FlashTime, 100UL))
  {
    digitalWrite(13,!digitalRead(13));
  }
  //***************************

  //Put your non-blocking regular stuff here


  //****************************************************************
  //Check machine state and do things that must be done accordingly 
  switch (mState)
  {
    //***************************
  case stateStart:
    {
      //let us wait for 5 seconds before we print the Welcome message
      if (CheckTime(TaskWait, 5000UL)) 
      //if (CheckTime(TaskWait, waitTime)) //we could use a variable for the time to wait 
      {      
        Serial.println(F("Welcome"));
        Serial.println(F("Press a KEY then press SEND"));
        Serial.println();
        //Other start stuff goes here

        mState = stateApple; //advance to the next state
      }
    }

    break; //end case stateStart:

    //***************************
  case stateApple: 
    {
      if (Serial.available() > 0)
      {
        // read the incoming character:
        char incomingChar = Serial.read();

        // print what you received:
        Serial.print(F("I received: "));
        Serial.println(incomingChar);
        Serial.println();

        messageNumber = 1;    //used in the next mState
        mState = stateOrange; //advance to the next mState
      }
    }

    break; //end case stateApple:

    //***************************
  case stateOrange:
    {
      //We will stay in this mState until some things are done
      switch(messageNumber)
      {
        //***************************
      case 1:
        Serial.println();
        Serial.println(F("Here is a message, we will wait 10 seconds and continue."));
        Serial.println(F("Notice the LED on pin 13 keeps flashing."));
        Serial.println();

        TaskWait = millis(); //initialize the next wait time
        messageNumber = 2;   //advance to the next messageNumber state

        break;

        //***************************
      case 2:
        if (CheckTime(TaskWait, 10000UL)) 
        {
          Serial.println   (F("Here is another message."));
          Serial.println   (F("We will now wait 5 sec and continue."));
          Serial.println();

          TaskWait = millis();
          messageNumber = 3;
        }   

        break;

        //***************************
      case 3:
        if (CheckTime(TaskWait, 5000UL)) 
        {
          Serial.println (F("We can print some instructions then pause for a while,"));
          Serial.println (F("this can be done without blocking other code from running."));
          Serial.println (F("We will now wait 10 sec and continue, however other things will still happen."));
          Serial.println();

          TaskWait = millis();
          messageNumber = 4;
        }

        break;

        //***************************
      case 4:
        if (CheckTime(TaskWait, 10000UL)) 
        {

          //we are now finished with this mState, advance to the next mState
          mState = statePear; 
        }

        break;

      } //end of switch messageNumber

      break;
    } //end case stateOrange:


    //***************************
  case statePear:
    {
      // You put statePear stuff here

      mState = statePeach; //we are now finished with this mState, advance to the next mState

      break;
    } //end case statePear:

    //***************************   
  case statePeach:
    {
      // You put statePeach stuff here

      mState = stateKiwi; //we are now finished with this mState, advance to the next mSstate

      break;
    } //end case statePeach:

    //***************************   
  case stateKiwi:
    {
      // You put stateKiwi stuff here

      break;
    } //end case stateKiwi:

  } // end of switch(mState)


} //        >>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<


//======================================================================
//                    F U N C T I O N S
//======================================================================

//***************************
//Delay time expired function
boolean CheckTime(unsigned long &lastMillis, unsigned long wait) 
{
  //is the time up for this task?
  if (currentmillis - lastMillis >= wait) 
  {
    lastMillis += wait;  //get ready for the next iteration

    return true;
  }

  return false;
} //END of CheckTime()

//***************************

//======================================================================
//                             END OF CODE
//======================================================================

Currently using elapsedMillis.h, seems to be working ok. 4 timers so far, and doesn't seem to be adding more lag than usual.

The demo several things at a time illustrates how to use millis()

I think the name of the demo matches your title neatly.

...R

LarryD:
Here is a fruit basket you can pick what you need:

//State Machine example

//LarryD

byte messageNumber;
unsigned long TaskWait;
unsigned long FlashTime;
unsigned long currentmillis;

//define the available machine states that we can have for this sketch
//add more states as needed
enum States{
  stateStart, stateApple, stateOrange, statePear, statePeach, stateKiwi};

//mState = machine State
States mState = stateStart;              //we start out in this machine state

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

pinMode(13, OUTPUT);
  FlashTime = millis();
  TaskWait = millis();                  //initialize the next wait time
  mState = stateStart;                  //we start out in this machine state

} //        >>>>>>>>>>>>>> END OF setup() <<<<<<<<<<<<<<<<<

void loop()
{
  //leave this line of code at the top
  currentmillis  = millis();

//***************************
  //just some code to see if the sketch is blocking
  if (CheckTime(FlashTime, 100UL))
  {
    digitalWrite(13,!digitalRead(13));
  }
  //***************************

//Put your non-blocking regular stuff here

//****************************************************************
  //Check machine state and do things that must be done accordingly
  switch (mState)
  {
    //***************************
  case stateStart:
    {
      //let us wait for 5 seconds before we print the Welcome message
      if (CheckTime(TaskWait, 5000UL))
      //if (CheckTime(TaskWait, waitTime)) //we could use a variable for the time to wait
      {     
        Serial.println(F(“Welcome”));
        Serial.println(F(“Press a KEY then press SEND”));
        Serial.println();
        //Other start stuff goes here

mState = stateApple; //advance to the next state
      }
    }

break; //end case stateStart:

//***************************
  case stateApple:
    {
      if (Serial.available() > 0)
      {
        // read the incoming character:
        char incomingChar = Serial.read();

// print what you received:
        Serial.print(F("I received: "));
        Serial.println(incomingChar);
        Serial.println();

messageNumber = 1;    //used in the next mState
        mState = stateOrange; //advance to the next mState
      }
    }

break; //end case stateApple:

//***************************
  case stateOrange:
    {
      //We will stay in this mState until some things are done
      switch(messageNumber)
      {
        //***************************
      case 1:
        Serial.println();
        Serial.println(F(“Here is a message, we will wait 10 seconds and continue.”));
        Serial.println(F(“Notice the LED on pin 13 keeps flashing.”));
        Serial.println();

TaskWait = millis(); //initialize the next wait time
        messageNumber = 2;  //advance to the next messageNumber state

break;

//***************************
      case 2:
        if (CheckTime(TaskWait, 10000UL))
        {
          Serial.println  (F(“Here is another message.”));
          Serial.println  (F(“We will now wait 5 sec and continue.”));
          Serial.println();

TaskWait = millis();
          messageNumber = 3;
        }

break;

//***************************
      case 3:
        if (CheckTime(TaskWait, 5000UL))
        {
          Serial.println (F(“We can print some instructions then pause for a while,”));
          Serial.println (F(“this can be done without blocking other code from running.”));
          Serial.println (F(“We will now wait 10 sec and continue, however other things will still happen.”));
          Serial.println();

TaskWait = millis();
          messageNumber = 4;
        }

break;

//***************************
      case 4:
        if (CheckTime(TaskWait, 10000UL))
        {

//we are now finished with this mState, advance to the next mState
          mState = statePear;
        }

break;

} //end of switch messageNumber

break;
    } //end case stateOrange:

//***************************
  case statePear:
    {
      // You put statePear stuff here

mState = statePeach; //we are now finished with this mState, advance to the next mState

break;
    } //end case statePear:

//*************************** 
  case statePeach:
    {
      // You put statePeach stuff here

mState = stateKiwi; //we are now finished with this mState, advance to the next mSstate

break;
    } //end case statePeach:

//*************************** 
  case stateKiwi:
    {
      // You put stateKiwi stuff here

break;
    } //end case stateKiwi:

} // end of switch(mState)

} //        >>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<

//======================================================================
//                    F U N C T I O N S
//======================================================================

//***************************
//Delay time expired function
boolean CheckTime(unsigned long &lastMillis, unsigned long wait)
{
  //is the time up for this task?
  if (currentmillis - lastMillis >= wait)
  {
    lastMillis += wait;  //get ready for the next iteration

return true;
  }

return false;
} //END of CheckTime()

//***************************

//======================================================================
//                            END OF CODE
//======================================================================

In the CheckTime() function:
boolean CheckTime(unsigned long &lastMillis, unsigned long wait)

Why do you set a “&” before LastMillis?
Google tells me this is a reference, but why do you use it in this context?
What would be an alternative way without “&” to achieve the same result?

if (CheckTime(FlashTime, 100UL))
. . .
if (CheckTime(TaskWait, 10000UL))

The above two lines of code 'call' go to the CheckTime function.
boolean CheckTime(unsigned long &lastMillis, unsigned long wait)

The address of FlashTime and TaskWait is used to access those variables and change 'them' if necessary.

A pointer could be used.

.

Why do you set a "&" before LastMillis?

The function needs to be able to modify the first argument. The first argument must, therefore, be passed be reference, not be value.

What would be an alternative way without "&" to achieve the same result?

There isn't one.

Ok thx for your relply. I have to think about it.
I thought it would be enough to set TaskWait = millis() for taking time of the last execution.

Thing is: the code works without the "&", too.

Thing is: the code works without the "&", too.

Works? Or compiles and links?

Print the value in the variable out before and after the call, with the & in the function declaration. Then, do the same without the & in the function. Do you really see the same results?

SDHC1:
Ok thx for your relply. I have to think about it.
I thought it would be enough to set TaskWait = millis() for taking time of the last execution.

Thing is: the code works without the “&”, too.

Is that right, are you sure :wink:

Equivalent code using a pointer:

//State Machine example
//LarryD

byte messageNumber;
unsigned long TaskWait;
unsigned long FlashTime;
unsigned long currentmillis; 

//define the available machine states that we can have for this sketch
//add more states as needed
enum States{
  stateStart, stateApple, stateOrange, statePear, statePeach, stateKiwi};

//mState = machine State
States mState = stateStart;              //we start out in this machine state 

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

  pinMode(13, OUTPUT);
  FlashTime = millis();
  TaskWait = millis();                   //initialize the next wait time
  mState = stateStart;                   //we start out in this machine state 

} //        >>>>>>>>>>>>>> END OF setup() <<<<<<<<<<<<<<<<<


void loop()
{
  //leave this line of code at the top
  currentmillis  = millis();

  //***************************
  //just some code to see if the sketch is blocking
  if (CheckTime(&FlashTime, 100UL))
  {
    digitalWrite(13,!digitalRead(13));
  }
  //***************************

  //Put your non-blocking regular stuff here


  //****************************************************************
  //Check machine state and do things that must be done accordingly 
  switch (mState)
  {
    //***************************
  case stateStart:
    {
      //let us wait for 5 seconds before we print the Welcome message
      if (CheckTime(&TaskWait, 5000UL)) 
      //if (CheckTime(TaskWait, waitTime)) //we could use a variable for the time to wait 
      {      
        Serial.println(F("Welcome"));
        Serial.println(F("Press a KEY then press SEND"));
        Serial.println();
        //Other start stuff goes here

        mState = stateApple; //advance to the next state
      }
    }

    break; //end case stateStart:

    //***************************
  case stateApple: 
    {
      if (Serial.available() > 0)
      {
        // read the incoming character:
        char incomingChar = Serial.read();

        // print what you received:
        Serial.print(F("I received: "));
        Serial.println(incomingChar);
        Serial.println();

        messageNumber = 1;    //used in the next mState
        mState = stateOrange; //advance to the next mState
      }
    }

    break; //end case stateApple:

    //***************************
  case stateOrange:
    {
      //We will stay in this mState until some things are done
      switch(messageNumber)
      {
        //***************************
      case 1:
        Serial.println();
        Serial.println(F("Here is a message, we will wait 10 seconds and continue."));
        Serial.println(F("Notice the LED on pin 13 keeps flashing."));
        Serial.println();

        TaskWait = millis(); //initialize the next wait time
        messageNumber = 2;   //advance to the next messageNumber state

        break;

        //***************************
      case 2:
        if (CheckTime(&TaskWait, 10000UL)) 
        {
          Serial.println   (F("Here is another message."));
          Serial.println   (F("We will now wait 5 sec and continue."));
          Serial.println();

          TaskWait = millis();
          messageNumber = 3;
        }   

        break;

        //***************************
      case 3:
        if (CheckTime(&TaskWait, 5000UL)) 
        {
          Serial.println (F("We can print some instructions then pause for a while,"));
          Serial.println (F("this can be done without blocking other code from running."));
          Serial.println (F("We will now wait 10 sec and continue, however other things will still happen."));
          Serial.println();

          TaskWait = millis();
          messageNumber = 4;
        }

        break;

        //***************************
      case 4:
        if (CheckTime(&TaskWait, 10000UL)) 
        {

          //we are now finished with this mState, advance to the next mState
          mState = statePear; 
        }

        break;

      } //end of switch messageNumber

      break;
    } //end case stateOrange:


    //***************************
  case statePear:
    {
      // You put statePear stuff here

      mState = statePeach; //we are now finished with this mState, advance to the next mState

      break;
    } //end case statePear:

    //***************************   
  case statePeach:
    {
      // You put statePeach stuff here

      mState = stateKiwi; //we are now finished with this mState, advance to the next mSstate

      break;
    } //end case statePeach:

    //***************************   
  case stateKiwi:
    {
      // You put stateKiwi stuff here

      break;
    } //end case stateKiwi:

  } // end of switch(mState)


} //        >>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<


//======================================================================
//                    F U N C T I O N S
//======================================================================

//***************************
//Delay time expired function
boolean CheckTime(unsigned long *lastMillis, unsigned long wait) 
{
  //is the time up for this task?
  if (currentmillis - *lastMillis >= wait) 
  {
    *lastMillis += wait;  //get ready for the next iteration

    return true;
  }

  return false;
} //END of CheckTime()

//***************************

//======================================================================
//                             END OF CODE
//======================================================================

Ok, code doesn’t work the same without &.

In my test yesterday i commented out the call of the LED blink time: CheckTime(&FlashTime, 100UL). In this case it doesn’t matter if the value of TaskWait gets updated or not.

Therefore i didn’t notice any difference in the results without &.

But with two different calls (=different parameters) to the function checktime() TaskWait and FlashTime needs to be updated after each call to checktime().

Thx for your patience :slight_smile: