Bird
Raised Fist0
Arduinoprogramming~20 mins

millis() for non-blocking timing in Arduino - Practice Problems & Coding Challenges

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Challenge - 5 Problems
🎖️
Millis Timing Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
Predict Output
intermediate
2:00remaining
What is the output of this millis() timing code?

Consider this Arduino code snippet using millis() to toggle an LED every 1000 milliseconds. What will be printed to the serial monitor after 3500 milliseconds?

Arduino
unsigned long previousMillis = 0;
const long interval = 1000;
int ledState = LOW;

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

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    ledState = !ledState;
    Serial.println(ledState);
  }
}
A1 0 1
B0 1 0 1
C0 1 0
D1 0 1 0
Attempts:
2 left
💡 Hint

Think about how many times the interval of 1000 ms fits into 3500 ms and how the LED state toggles each time.

🧠 Conceptual
intermediate
1:30remaining
Why use millis() instead of delay() for timing?

Which of the following best explains why millis() is preferred over delay() for non-blocking timing in Arduino?

Adelay() can only be used once in a program, millis() can be used multiple times.
Bdelay() is faster than millis(), so millis() is rarely used.
Cmillis() allows the program to keep running other code while waiting, delay() stops everything.
Dmillis() uses less memory than delay(), making it more efficient.
Attempts:
2 left
💡 Hint

Think about what happens to the program flow when delay() is called.

🔧 Debug
advanced
2:30remaining
Identify the bug in this millis() timing code

What is the problem with this Arduino code that tries to toggle an LED every 500 ms?

Arduino
unsigned long previousMillis = 0;
const long interval = 500;
int ledState = LOW;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis > previousMillis + interval) {
    previousMillis = currentMillis;
    ledState = !ledState;
    digitalWrite(LED_BUILTIN, ledState);
  }
}
AUsing '>' can cause missed intervals due to millis() overflow; subtraction is safer.
BLED_BUILTIN is not defined by default in Arduino.
CledState should be a boolean, not int.
DdigitalWrite requires delay() to work properly.
Attempts:
2 left
💡 Hint

Consider what happens when millis() value wraps around after about 50 days.

📝 Syntax
advanced
2:00remaining
Which option correctly uses millis() for non-blocking delay?

Which of the following code snippets correctly toggles an LED every 2000 milliseconds without blocking the program?

Aif (millis() > previousMillis + 2000) { previousMillis = millis(); ledState = !ledState; digitalWrite(LED_BUILTIN, ledState); }
Bif (millis() - previousMillis >= 2000) { previousMillis = millis(); ledState = !ledState; digitalWrite(LED_BUILTIN, ledState); }
Cif (millis() - previousMillis > 2000) { delay(2000); previousMillis = millis(); ledState = !ledState; digitalWrite(LED_BUILTIN, ledState); }
Dif (millis() >= previousMillis + 2000) { previousMillis = millis(); ledState = !ledState; digitalWrite(LED_BUILTIN, ledState); }
Attempts:
2 left
💡 Hint

Look for the safest way to compare times that handles overflow correctly.

🚀 Application
expert
3:00remaining
How many times will the LED toggle in 10 seconds?

Given this Arduino code toggling an LED every 1500 milliseconds using millis(), how many times will the LED change state in 10 seconds?

Arduino
unsigned long previousMillis = 0;
const long interval = 1500;
int ledState = LOW;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    ledState = !ledState;
    digitalWrite(LED_BUILTIN, ledState);
  }
}
A8
B7
C5
D6
Attempts:
2 left
💡 Hint

Divide 10,000 milliseconds by 1500 milliseconds and consider integer division.

Practice

(1/5)
1. What does the millis() function in Arduino return?
easy
A. The current date and time
B. The number of milliseconds since the Arduino board started running the current program
C. The number of microseconds since the last reset
D. The current time in seconds

Solution

  1. Step 1: Understand what millis() measures

    millis() returns the time in milliseconds since the Arduino started running the program.
  2. Step 2: Compare options with the definition

    Only The number of milliseconds since the Arduino board started running the current program correctly describes this behavior; others mention seconds, microseconds, or date/time which are incorrect.
  3. Final Answer:

    The number of milliseconds since the Arduino board started running the current program -> Option B
  4. Quick Check:

    millis() = milliseconds since start [OK]
Hint: Remember millis() counts milliseconds since start [OK]
Common Mistakes:
  • Confusing millis() with delay()
  • Thinking millis() returns seconds
  • Assuming millis() gives current date/time
2. Which of the following is the correct way to store the current time using millis() in Arduino?
easy
A. char currentTime = millis();
B. int currentTime = millis();
C. float currentTime = millis();
D. unsigned long currentTime = millis();

Solution

  1. Step 1: Identify the correct data type for millis()

    millis() returns an unsigned long value representing milliseconds.
  2. Step 2: Match the data type with variable declaration

    Only unsigned long currentTime = millis(); uses unsigned long, which can hold large millisecond values without overflow.
  3. Final Answer:

    unsigned long currentTime = millis(); -> Option D
  4. Quick Check:

    Use unsigned long for millis() values [OK]
Hint: Use unsigned long to store millis() time [OK]
Common Mistakes:
  • Using int which can overflow quickly
  • Using float or char which are incorrect types
  • Not declaring variable before assignment
3. What will the following Arduino code print to the Serial Monitor?
unsigned long previousMillis = 0;
const long interval = 1000;

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

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    Serial.println("Tick");
  }
}
medium
A. Prints "Tick" once and stops
B. Prints "Tick" continuously without delay
C. Prints "Tick" every 1000 milliseconds without stopping the program
D. Causes a compile error due to variable scope

Solution

  1. Step 1: Understand the timing logic

    The code checks if 1000 milliseconds have passed since last print using millis() and updates previousMillis accordingly.
  2. Step 2: Analyze the output behavior

    When 1000 ms pass, it prints "Tick" and continues looping without blocking, so it prints every second repeatedly.
  3. Final Answer:

    Prints "Tick" every 1000 milliseconds without stopping the program -> Option C
  4. Quick Check:

    Non-blocking timing prints "Tick" every second [OK]
Hint: Check millis() difference to print repeatedly [OK]
Common Mistakes:
  • Thinking it prints only once
  • Confusing with delay() causing blocking
  • Assuming compile error due to variable scope
4. Identify the error in this Arduino code using millis() for timing:
unsigned long previousMillis;
const long interval = 2000;

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

void loop() {
  if (millis() - previousMillis >= interval) {
    Serial.println("Hello");
  }
}
medium
A. previousMillis is never updated, so "Hello" prints continuously
B. interval should be unsigned long, not long
C. Serial.begin() is missing in setup()
D. millis() cannot be used in loop()

Solution

  1. Step 1: Check how previousMillis is used

    The code checks the time difference but never updates previousMillis after printing.
  2. Step 2: Understand the effect of missing update

    Without updating, the condition stays true, so "Hello" prints repeatedly without delay.
  3. Final Answer:

    previousMillis is never updated, so "Hello" prints continuously -> Option A
  4. Quick Check:

    Update previousMillis to avoid continuous printing [OK]
Hint: Always update previousMillis after action [OK]
Common Mistakes:
  • Forgetting to update previousMillis
  • Thinking interval type causes error
  • Assuming Serial.begin() is missing
5. You want to blink an LED every 500 milliseconds without stopping other code from running. Which code snippet correctly uses millis() for this non-blocking timing? A)
unsigned long previousMillis = 0;
const long interval = 500;
void loop() {
  if (millis() - previousMillis >= interval) {
    previousMillis = millis();
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
  // other code runs here
}
B)
void loop() {
  delay(500);
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
C)
unsigned long previousMillis = 0;
const long interval = 500;
void loop() {
  if (millis() >= previousMillis + interval) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    previousMillis = millis();
  }
}
D)
unsigned long previousMillis = 0;
const long interval = 500;
void loop() {
  if (millis() - previousMillis > interval) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
  }
}
hard
A. Correct non-blocking blink using millis() and toggling LED
B. Uses delay(), which blocks other code from running
C. Correct logic but may cause overflow issues with addition
D. Uses delay() inside if, causing blocking and incorrect blink

Solution

  1. Step 1: Identify non-blocking timing usage

    Correct non-blocking blink using millis() and toggling LED uses millis() difference and updates previousMillis correctly, toggling LED without delay.
  2. Step 2: Compare other options for blocking or logic issues

    The other snippets either use delay(), which blocks other code from running, or use addition in the condition, which can cause overflow issues with large millisecond values.
  3. Final Answer:

    Correct non-blocking blink using millis() and toggling LED -> Option A
  4. Quick Check:

    Use millis() difference and update previousMillis [OK]
Hint: Toggle LED using millis() difference, avoid delay() [OK]
Common Mistakes:
  • Using delay() causing blocking
  • Not updating previousMillis properly
  • Using addition risking overflow bugs