Using multiple millis() functions in a row

Hello I want send different messages but with a delay.

What the function should do is every 10 seconds it should start sending a row of messages where each message is delayed by 2 seconds.

Fx.:

Serial.println("A");

delay(2000)

Serial.println("B");

delay(2000)

Serial.println("C");

delay(2000)

Serial.println("D");

delay(10000)

I know how to use millis to keep sending a single message with a specific delay.

Create a counter.
Every millis() overflow You reload the millis() comparative variable, then you send the msg and increment the counter. When the counter is greater than the number of messages you want to send, you reload the variable with a higher value and reset the counter.

if you want to get a proposal - post a FULL sketch.
Otherwise, see the example "Blink Without Delay" and use the same concept for your sketch.

Can you give and examples?

I use:

const unsigned long eventInterval = 10000;
unsigned long previousTime = 0;


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


void loop() {

  /* Updates frequently */
  unsigned long currentTime = millis();

  /* This is the event */
  if (currentTime - previousTime >= eventInterval) {
  
  /* Event code */
    Serial.println("A");
    
   /* Update the timing for the next time around */
    previousTime = currentTime;

  }

This keeps sending the "A" every 10 seconds.

But how do I add that 2 seconds later it send a "B"

I have tried many different things but I can't figure it out.

Right here put a counter in, and every time you swing through increment the counter.

Until the counter is too big, so when you increment it past where you want, immindiantly reset the counter to zero.

Now add… instead of printing "A" every time, use the counter to print whatever shoukd correspond to the count.

Here's a sneaky trick

    char x = 'a' + counter;
    Serial.println(x);

which will print 'a' when the counter is zero, and 'b' when it is one, 'c' when it is two and so forth.

HTH

a7

to be tried:

const char *message[] {"alfa", "beta", "three", "Lot of 4444"};

void sendInInterval(uint32_t currentMillis = millis()) {
  static size_t index=0;
  static uint32_t previousMillis = 0;
  if (currentMillis - previousMillis > 1000) {
    previousMillis = currentMillis;
    Serial.println(message[index++]);
    if (index >= sizeof(message) / sizeof(message[0])) index = 0;
  }
}

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

void loop() {
  sendInInterval();
}

Right.

The counting on the way through is the increment of index

   index++

and the resetting when you've gone too far is when index gets to (or somehow slips past) the number of things to print.

    if (index >=   <number of things> ) index = 0;

You could use the index or counter to decide how long to pause each step with a bit of extra logic and maybe an array to hold the dwell times in place of the hard-coded 1000.

a7

Okay so for my use i should write it like this:


//This is my index
const char *message[] {"A", "B", "C", "D"};

void sendInInterval(uint32_t currentTime = millis()) {
  static size_t index=0;
  static uint32_t previousTime = 0;

//The event should happen every 10 seconds
  if (currentTime - previousTime > 10000) {
    previousMillis = currentMillis;

//Print "A" then "B" etc...
    Serial.println(message[index++]);

**//This part I can't understand???**
    if (index >= sizeof(message) / sizeof(message[0])) index = 0;
  }
}

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

void loop() {
  sendInInterval();
}

//Rest of the loop functions happens here

But I still don't get how I can set the time it takes to go through the index.

That's the idiomatic expression for letting the compiler calculate the number of entities in an array.

The size of the entire array divided by the size of one element of the array.

You can stash your delay times in an array like

     unsigned long times[] = {2000, 2000, 2000, 5000, 10000};

Obvsly, I hope, you'd need as many as you were going to index into.

Then where you want the time to be variable in that way, write

  if (currentTime - previousTime > times[index]) {

If you've used arrays before, you may not have asked the questions, so I assume perhaps you have not. Mark it for learning times, array variables are the bomb.

a7

The following is significant --

You have to stop thinking of millis as a block of cryptic code to copy and think about what it means. You're just measuring how much time has passed since some event.

unsigned long previousStartTime;
boolean zerothThingHappened = false;
boolean firstThingHappened = false;
boolean secondThingHappened = false;
boolean thirdThingHappened = false;
boolean fourthThingHappened = false;

void setup() {

  Serial.begin(115200);
  delay(500);
  Serial.println("Lots Of Millis: ");
}

void loop() {

  unsigned long currentTime = millis();

  // 5 events at 2 second intervals for a ten second cycle.
  if (currentTime - previousStartTime >= 10000) {
    // ten seconds have passed, so reset the cycle
    zerothThingHappened = false;
    firstThingHappened = false;
    secondThingHappened = false;
    thirdThingHappened = false;
    fourthThingHappened = false;
    previousStartTime = currentTime;   // <<<<<<  THIS IS THE TIME WE WILL MEASURE FROM
  }
  if(!zerothThingHappened) {  // && currentTime - previousStartTime >= 0 is always true
    Serial.println("ZerothThing");
    zerothThingHappened = true;
  }
  if(!firstThingHappened && currentTime - previousStartTime >= 2000){
    // It's been 2 seconds since previousStartTime
    Serial.println("FirstThing");
    firstThingHappened = true;
  }
  if(!secondThingHappened && currentTime - previousStartTime >= 4000){
    // It's been 4 seconds since previousStartTime
    Serial.println("SecondThing");
    secondThingHappened = true;
  }
  if(!thirdThingHappened && currentTime - previousStartTime >= 6000){
    // It's been 6 seconds since previousStartTime
    Serial.println("ThirdThing");
    thirdThingHappened = true;
  }
  if(!fourthThingHappened && currentTime - previousStartTime >= 8000){
    // It's been 8 seconds since previousStartTime
    Serial.println("FourthThing");
    fourthThingHappened = true;
  }
}
18:16:08.033 -> Lots Of Millis: 
18:16:08.033 -> ZerothThing
18:16:09.540 -> FirstThing
18:16:11.560 -> SecondThing
18:16:13.549 -> ThirdThing
18:16:15.537 -> FourthThing
18:16:17.558 -> ZerothThing
18:16:19.546 -> FirstThing
18:16:21.534 -> SecondThing
18:16:23.553 -> ThirdThing
18:16:25.540 -> FourthThing
18:16:27.559 -> ZerothThing
18:16:29.547 -> FirstThing
18:16:31.535 -> SecondThing
18:16:33.555 -> ThirdThing
18:16:35.544 -> FourthThing
18:16:37.565 -> ZerothThing
18:16:39.553 -> FirstThing
18:16:41.542 -> SecondThing
18:16:43.563 -> ThirdThing
18:16:45.551 -> FourthThing
18:16:47.541 -> ZerothThing
18:16:49.562 -> FirstThing
18:16:51.551 -> SecondThing
18:16:53.538 -> ThirdThing
18:16:55.558 -> FourthThing
18:16:57.546 -> ZerothThing
18:16:59.566 -> FirstThing
18:17:01.554 -> SecondThing
18:17:03.543 -> ThirdThing
18:17:05.563 -> FourthThing
18:17:07.552 -> ZerothThing
18:17:09.540 -> FirstThing
18:17:11.560 -> SecondThing
18:17:13.549 -> ThirdThing
18:17:15.570 -> FourthThing

Okay I will try playing around with the code I have now and see how it works in action.

Then I might make more sense for me.

Maybe I should mention what I am going to use it for.

I have 3 Arduinos and 3 HC12 wireless modules.

1 Arduino as the receiver
2 Arduinos as transmitter

The 2 transmitters is constantly calculating the status of 2 machines, if they are running, in standby or is stuck.

I call the first transmitter A and the other one B

To prevent both transmitters in sending status updates at the same time, the receiver calls A and gets it's value which determine if a Red, Yellow or Green LED should light up.
Then it calls B etc. I plan to add more transmitters later.

I tried using normal delay in my code but it caused the rest of my sketch to stop functioning.

Therefore I discovered millis might be able to what I want because it doesn't interfere with the rest of the sketch.

Thank you so much! It was something like that I imagined the code would look like.

I just couldn't figure out how to get it work, but you gave the details I was missing.

I'm excited to try it out tomorrow!

Your try will not compile. For what ever reason you have changed some variable names but have forgotten some. Why don't you stick to the variables like used in "Blink Without Delay"?

if you really just need A, B, C, D there is no need to hold them in a c-string. Just hold the value in char variable and increment that *)


void sendInInterval(uint32_t currentTime = millis()) {
  static char c = 'A';      // the character/letter to print out
  static uint32_t previousTime = 0;

  //The event should happen every 10 seconds
  if (currentTime - previousTime > 10000) {
    previousTime = currentTime;

    //Print "A" then "B" etc...
    Serial.println(c++);  // print current letter and afterwards increment for next iteration
    
    if (c > 'D') c = 'A'; // wrap around
  }
}

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

void loop() {
  sendInInterval();
  //Rest of the loop functions happens here
}

*) or store 0,1,2,3 and just add +'A' when you print out like already shown.

Hello henrik9979

Consider:

//https://forum.arduino.cc/t/using-multiple-millis-functions-in-a-row/1211595
//https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
#define ProjectName "Using multiple millis() functions in a row"
#define NotesOnRelease "Arduino MEGA tested"
// make names
enum TimerEvent {NotExpired, Expired};
enum TimerControl {Halt, Run};
// make structures
struct TIMER
{
  uint32_t interval;
  uint8_t control;
  uint32_t now;
  void launch(uint32_t currentMillis)
  {
    control = Run;
    now = currentMillis;
  }
  void halt()
  {
    control = Halt;
  }
  uint8_t expired(uint32_t currentMillis)
  {
    uint8_t timerEvent = currentMillis - now >= interval and control;
    if (timerEvent == Expired) now = currentMillis;
    return timerEvent;
  }
};
struct MSGTIMER
{
  String message;
  TIMER wait;
};
MSGTIMER msgTimers[]
{
  {"message 1", 1000, Halt, 0},
  {"message 2", 2000, Halt, 0},
  {"message 3", 3000, Halt, 0},
  {"message 4", 4000, Halt, 0},
};
// make support
void heartBeat(const uint8_t LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (setUp == false) pinMode (LedPin, OUTPUT), setUp = true;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
// make application
void setup()
{
  Serial.begin(115200);
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);
  Serial.println(" =-> and off we go\n");
  uint8_t startMessage = 0;
  msgTimers[startMessage].wait.launch(millis());
  Serial.println(msgTimers[startMessage].message);
}
void loop()
{
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
  for (auto &msgTimer : msgTimers)
  {
    if (msgTimer.wait.expired(currentMillis) == Expired)
    {
      static uint8_t messageCounter = 0;
      msgTimer.wait.halt();
      messageCounter = (messageCounter + 1) % (sizeof(msgTimers) / sizeof(msgTimers[0]));
      msgTimers[messageCounter].wait.launch(currentMillis);
      Serial.println(msgTimers[messageCounter].message);
    }
  }
}

hth

Have a nice day and enjoy coding in C++.

1 Like

maybe


const char * msg [] = {
    "msgA", "msgB", "msgC", "msgD", "msgE",
    "", "", "", "", "", 
};
const int Nmsg = sizeof(msg) / sizeof(char *);
      int idx;

unsigned long msec0;
void loop ()
{
    unsigned long msec = millis ();
    if (msec >= msec0) {
        msec0 += 2000;
    
        if ('\0' != *msg [idx])
            Serial.println (msg [idx]);
        if (Nmsg <= ++idx)
            idx = 0;
    }
}

void setup() {
    Serial.begin (9600);    
}
2 Likes

Should one consider switching the order here:

into:

    uint8_t timerEvent = control and currentMillis - now >= interval;

...so it tests the uint8_t and short-circuits before trying the uint32_t subtraction?

1 Like

Hello DaveX

Thank you for your thoughts, which I am happy to read.

To give a good answer, a disassembly of the C++ code would give a reliable answer.

will not be necessary. C/C++ has short circuit evaluation of boolean expressions.

The question you gotta ask yourself is do ya feel lucky today, punk?

No, srsly, the question is do you want to take advantage of that by rearranging the order of the terms as @DaveX suggests? Does it matter?

a7

No.