Arduino: Independent On-Off Times with Millis()

When using delay() to flash a LED there is a time for the LED to be on and then off. This makes it easy to have independent control of the “on” and “off” times. The standard blink without delay example doesn’t give you this flexibility.

millis-cookbook-two-duty-cycles

This example code gives you complete independant control of how long a LED (or any OUTPUT pin) stays “ON” or “OFF”. This also demonstrates a very simple two-state state machine.

The variable “LED13state” is used to track what should happen each time the millis() event fires.

// On and Off Times (as int, max=32secs)
const unsigned int onTime = 1000;
const unsigned int offTime = 500;

// Tracks the last time event fired
unsigned long previousMillis=0;

// Interval is how long we wait
int interval = onTime;

// Used to track if LED should be on or off
boolean LED13state = true;

// Usual Setup Stuff
void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  // Set Pin 13 to state of LED13state each timethrough loop()
  // If LED13State hasn't changed, neither will the pin
  digitalWrite(13, LED13state);

  // Grab snapshot of current time, this keeps all timing
  // consistent, regardless of how much code is inside the next if-statement
  unsigned long currentMillis = millis();

  // Compare to previous capture to see if enough time has passed
  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    // Change wait interval, based on current LED state
    if (LED13state) {
      // LED is currently on, set time to stay off
      interval = offTime;
    } else {
      // LED is currently off, set time to stay on
      interval = onTime;
    }
    // Toggle the LED's state, Fancy, eh!?
    LED13state = !(LED13state);

    // Save the current time to compare "later"
    previousMillis = currentMillis;
  }
}

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

ALL comments submitted with fake or throw-away services are deleted, regardless of content.

Don't be a dweeb.

Leave a comment

56 thoughts on “Arduino: Independent On-Off Times with Millis()

  1. How code run ounce blink led 3 time using millis(); if some variable have true condition
    I want blink my led 3 time if button have 4 pressed

  2. Thanks James, I had almost given up on trying to get this scenario to work. This code works perfectly for my purposes. I had spent hours with it and you sorted me out in five minutes. Excellent job.
    Peter

  3. Thanks for this tutorial. I am new to arduino and have been practicing with sketches but your sketch is quite strange to me. I use original Arduino IDE downloaded from the net. I wanted to copy your sketch and make some few changes to suit my case. I need a 8 hour ON and 6 minutes OFF cyclic timer ( probably with adjustable OFF timer).

    • As long as the variables used to track millis() are defined as an “unsigned long”, it will take 47 days for milils() to roll-over. The code used in this example specifically handles the roll-over condition. So unless they roll-over twice, e.g. 94 days, without previousMillis being updated, there is no need to worry about roll-over–with this code.

  4. James…excellent tutorials on Millis(). I am new to Arduino and am trying different examples.. When I loaded this sketch into my Nano it throws the following error pointing to line 22;

    cannot convert ‘boolean {aka bool}’ to ‘Pin Status’ for argument ‘2’ to ‘void digitalWrite(pin_size_t, PinStatus)’

  5. HI James, have been trying to use google assisant with my raspeberry pi to turn a relay on then off. I have managed to do this, BUT I have to issue 2 separate voice commans, one to turn relay HIGH and second command to turn relay LOW. I would like to issue only ONE command to turn relay HIGH and then after set time 2 seconds for the relay to turn LOW with out an extra voice command.Any help would be very much appreciated. Sean

  6. Hi James,

    i wrote some code to blink a led n times depending how many users are connected.
    i use the delay function but want to convert that to milis().
    can you push me in the right direction ?

    the code now is:

    switch (aantal){
        case 0:
         digitalWrite(RedLed,LOW);
        break;
        
        case 1:
         delay(350);
         digitalWrite(RedLed,HIGH);
         delay(700);
         digitalWrite(RedLed,LOW);
        break;
        
        case 2:
         delay(350);
         digitalWrite(RedLed,HIGH);
         delay(700);
         digitalWrite(RedLed,LOW);
         delay(350);
         digitalWrite(RedLed,HIGH);
         delay(700);
         digitalWrite(RedLed,LOW);
        break;
        
    
        case 3:
         delay(350);
         digitalWrite(RedLed,HIGH);
         delay(700);
         digitalWrite(RedLed,LOW);
         delay(350);
         digitalWrite(RedLed,HIGH);
         delay(700);
         digitalWrite(RedLed,LOW);
         delay(350);
         digitalWrite(RedLed,HIGH);
         delay(700);
         digitalWrite(RedLed,LOW);
        break;
    

    this goes up to 6

    How to convert this ?

    • You need to create a state machine, like the example, I did here. I would start with making each pattern work correctly with millis() and then slowly integrate them together. It isn’t optimized, but I would consider using separate variables for the on/off times of each pattern.