Fun with Arduino 13 Timer with millis(), no delay() , Multitasking

Our day / night light switching unit works fine, but for one thing: when we input a new cycle time via keyboard or via an analog input, we do not have any feedback on the monitor on what we are inputting. This is caused by the delay() instruction, which is easy to use, but which has a major drawback: delay() completely stalls the Arduino.

Luckily there is a solution: the Arduino has a built in internal clock which starts counting milliseconds when the Arduino starts up. millis() is the instruction to see what time it is.

Time_for_Action_smallTo see this at work, let’s do a simple LED blink,  using millis() in stead of delay(). When the LED turns on, we read the current time with the millis() instruction and we add INTERVAL milliseconds to calculate the next time_for_action. The loop() keeps running and every cycle we test if millis() went past time_for_action. If so, we can run some code, in this case we invert the LED-status.

Read on below the video …

 

 

#define INTERVAL 200 // [ms]
byte led; // LED status: 0=off, 1=on
unsigned long time_for_action;

void setup() {
  pinMode(13, OUTPUT); // 13 is the on board LED
}

void loop() {
  if (millis() > time_for_action) {
    time_for_action = millis() + (unsigned long)INTERVAL;
    led = !led;
    digitalWrite(13, led);
  }
}

Note how led = !led; inverts the variable led … “!” means NOT. Without delay() the Arduino never stalls … it keeps running the loop() and only when it is time_for_action it executes the code for the action. We can make multiple LEDs blink, each with its own fully independent timing, something we would never be able to achieve with delay()!

#define INTERVAL_1 200  // [ms]
#define INTERVAL_2 1100  // [ms]
byte led_1;
byte led_2;
unsigned long time_for_action_1;
unsigned long time_for_action_2;

void setup() {
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop() {
  if (millis() > time_for_action_1) {
    time_for_action_1 = millis() + (unsigned long)INTERVAL_1;
    led_1 = !led_1;
    digitalWrite(8, led_1);
  }
  if (millis() > time_for_action_2) {
    time_for_action_2 = millis() + (unsigned long)INTERVAL_2;
    led_2 = !led_2;
    digitalWrite(9, led_2);
  }
}

Want more timers? Just copy – paste the if { … } statements as many times as needed, change the numbers and you have them.

We can also add a toggle switch, and unlike we experienced in the code with delay(), we do not have to wait a complete cycle for the switch to be read and acted upon … the cycle can immediately be stopped.

#define INTERVAL_1 1000  // [ms]
#define INTERVAL_2 3000  // [ms]
byte led_1;
byte led_2;
unsigned long time_for_action_1;
unsigned long time_for_action_2;

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop() {
  if (digitalRead(2) == LOW) { // start the timers
    if (millis() > time_for_action_1) {
      time_for_action_1 = millis() + (unsigned long)INTERVAL_1;
      led_1 = !led_1;
    }
    if (millis() > time_for_action_2) {
      time_for_action_2 = millis() + (unsigned long)INTERVAL_2;
      led_2 = !led_2;
    }
  }
  else { // immediately stop the timers and switch the LEDs off
    time_for_action_1 = 0;
    time_for_action_2 = 0;
    led_1 = 0;
    led_2 = 0;
  }
  digitalWrite(8, led_1);
  digitalWrite(9, led_2);
}

Hey wait … something strange is happening here. When switched on, the LEDs should burn. But ever so often we see a short flicker and then the LEDs are off. How come? What we see here is an effect that most mechanical switches have, called bouncing. The contacts bounce a couple of times before they really are closed. This happens all within just a few milliseconds, but the Arduino is looping fast enough to see it, so first the switch read LOW, then the if is executed. The next loop the switch bounced and is HIGH and the else is executed … maybe this even repeats a few times.

To avoid this we can add a little delay immediately after reading the switch, a delay short enough not to be noticeable, and long enough for the bouncing to have finished.

#define INTERVAL_1 1000  // [ms]
#define INTERVAL_2 3000  // [ms]
byte led_1;
byte led_2;
unsigned long time_for_action_1;
unsigned long time_for_action_2;

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop() {
  if (digitalRead(2) == LOW) { // start the timers
    delay(50) // anti bounce
    if (millis() > time_for_action_1) {
      time_for_action_1 = millis() + (unsigned long)INTERVAL_1;
      led_1 = !led_1;
    }
    if (millis() > time_for_action_2) {
      time_for_action_2 = millis() + (unsigned long)INTERVAL_2;
      led_2 = !led_2;
    }
  }
  else { // immediately end the timers and switch the LEDs off
    time_for_action_1 = 0;
    time_for_action_2 = 0;
    led_1 = 0;
    led_2 = 0;
  }
  digitalWrite(8, led_1);
  digitalWrite(9, led_2);
}

END TEXT

— 0 —

7 thoughts on “Fun with Arduino 13 Timer with millis(), no delay() , Multitasking

  1. Hi, rudy
    I am really happy with your youtube chanel fun with an arduino 13, i just begginer for an arduino,, and i need your favour to help me how to create timer on for 5second after that off,, and timer off for 2second before on with millis program and use switch toggle for each fungtions to control it,, i want to change ic 555 in my project by using an arduino ,,,,
    i am really happy full of thank you for your future information
    Best regards,

    Christian

    Like

      • Hi, rudy
        I am glad for your faster ever for reply my comment, my appologize for my explaned not too clear,,

        To make the specifications clear:
        When S1 is switched, a signal goes from LOW to HIGH for 5s and then Stay HIGH , as a one shot.. and
        When S2 is switched, a signal goes from HIGH to LOW for 2s and then stay LOW , as a one shot…

        In millis please,

        I just let you know i am used a relay 5pins 5volt instead of switch toggle for automatic and several toggle switch for manually both of combine in my project..

        Thank you a lot for future reply

        Best regards,

        Christian

        Like

  2. This sounds like a strange specification. I guess you meant:
    If S1 is switched, a signal gooed from LOW to HIGH AFTER 5s and stays HIGH.
    If S2 is switched a signal goes to HIGN to LOW AFTER 2s and stays LOW.
    Another question: when do the signals change state again? When the switches are switched off?

    Like

  3. Hi, rudy
    Yes it is,, actually it is common timer delay ON or timer delay OFF from ic analog 555,, correct rudy, to change state only switched off ,, it is look like i watched fun with arduino 13 ( you did great program for blinking by use interval ) just switched off all the light is off..

    Thank you fot your future information

    Best regards,

    Christian

    Like

  4. Hi, rudy
    It is ok, i will try to do by my self,, good to see you in comment
    Take time with your busy day

    Best regards,

    Christian

    Like

Leave a Reply to RudyB Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s