📖 Scenario: You are building a simple Arduino program to blink an LED without stopping other tasks. Instead of using delay(), which pauses everything, you will learn how to write non-blocking code that lets the Arduino do other things while blinking the LED.
🎯 Goal: Create an Arduino sketch that blinks the built-in LED every 1 second using non-blocking code with millis(). This will keep the program responsive and able to do other tasks.
📋 What You'll Learn
Use the built-in LED on pin 13
Use a variable to store the LED blink interval (1000 milliseconds)
Use millis() to check elapsed time without blocking
Toggle the LED state every interval
Print LED ON or LED OFF to the Serial Monitor when the LED changes
💡 Why This Matters
🌍 Real World
Non-blocking code lets microcontrollers handle multiple tasks smoothly, like reading sensors while blinking LEDs or controlling motors without delays.
💼 Career
Understanding non-blocking code is essential for embedded systems programming, robotics, and IoT device development where responsiveness is critical.
Progress0 / 4 steps
1
Setup LED pin and initial variables
Create a variable called ledPin and set it to 13. Create a variable called previousMillis and set it to 0. Create a variable called ledState and set it to LOW. In the setup() function, set ledPin as an output and start Serial communication at 9600 baud.
Arduino
Hint
Remember to set the LED pin as output and start Serial communication in setup().
2
Add blink interval variable
Add a variable called interval and set it to 1000 to represent the blink interval in milliseconds.
Arduino
Hint
Use unsigned long for the interval variable to match millis() type.
3
Implement non-blocking LED blink logic
In the loop() function, get the current time using millis() and store it in a variable called currentMillis. Use an if statement to check if the difference between currentMillis and previousMillis is greater than or equal to interval. Inside the if, update previousMillis to currentMillis, toggle ledState between LOW and HIGH, write ledState to ledPin, and print LED ON or LED OFF to Serial depending on the new state.
Arduino
Hint
Use millis() to check elapsed time and toggle the LED state inside the if block.
4
Display blinking LED status
Add a print statement inside the if block in loop() to print LED ON when the LED turns on and LED OFF when it turns off. This is already done in the previous step. Run the program and observe the Serial Monitor output showing LED ON and LED OFF every second.
Arduino
Hint
Open the Serial Monitor to see the LED status messages every second.
Practice
(1/5)
1. What is the main advantage of using non-blocking code in Arduino programming?
easy
A. It uses less memory than blocking code.
B. It makes the code run slower but more stable.
C. It allows the Arduino to perform multiple tasks without waiting.
D. It automatically fixes hardware errors.
Solution
Step 1: Understand blocking vs non-blocking
Blocking code stops the program until a task finishes, while non-blocking code lets the program keep running other tasks.
Step 2: Identify the benefit of non-blocking
Non-blocking code allows multitasking and keeps the Arduino responsive.
Final Answer:
It allows the Arduino to perform multiple tasks without waiting. -> Option C
Quick Check:
Non-blocking = multitasking [OK]
Hint: Non-blocking means no waiting, so tasks run together [OK]
Common Mistakes:
Thinking non-blocking slows code down
Confusing memory use with blocking behavior
Believing non-blocking fixes hardware issues
2. Which of the following is the correct way to check elapsed time without blocking in Arduino?
easy
A. delay(1000);
B. if (millis() - previousMillis >= interval) { /* do task */ }
C. while(millis() < 1000) { /* wait */ }
D. delayMicroseconds(1000);
Solution
Step 1: Identify blocking vs non-blocking code
delay() and while loops that wait block the program, stopping other tasks.
Step 2: Recognize millis() usage
Using millis() to check elapsed time allows the program to continue running other code.
Final Answer:
if (millis() - previousMillis >= interval) { /* do task */ } -> Option B
Quick Check:
millis() check = non-blocking [OK]
Hint: Use millis() difference, not delay(), to avoid blocking [OK]
Common Mistakes:
Using delay() which blocks the program
Using while loops that wait for time
Confusing delayMicroseconds with non-blocking
3. What will be the output of this Arduino code snippet?
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
if (millis() - previousMillis >= interval) {
previousMillis = millis();
Serial.println("Tick");
}
}
medium
A. Prints "Tick" every second repeatedly.
B. Prints "Tick" continuously without delay.
C. Prints "Tick" once and stops.
D. Does not print anything due to syntax error.
Solution
Step 1: Analyze the millis() timing check
The code checks if 1000 milliseconds (1 second) have passed since last print.
Step 2: Understand the loop behavior
When 1 second passes, it updates previousMillis and prints "Tick" again, repeating forever.
Final Answer:
Prints "Tick" every second repeatedly. -> Option A
Quick Check:
millis() timer triggers print every 1 second [OK]
Hint: millis() timer resets each print for repeated ticks [OK]
Common Mistakes:
Thinking it prints only once
Assuming continuous printing without delay
Believing there is a syntax error
4. Identify the problem in this non-blocking Arduino code and how to fix it:
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
if (millis() > previousMillis + interval) {
Serial.println("Hello");
}
}
medium
A. It never updates previousMillis, causing continuous prints.
B. The comparison operator should be '<' instead of '>'.
C. The interval variable must be unsigned long, not long.
D. Serial.println() cannot be used inside loop.
Solution
Step 1: Check the timing logic
The code checks if millis() is greater than previousMillis + interval but never updates previousMillis.
Step 2: Understand the effect
Without updating previousMillis, the condition stays true, so "Hello" prints continuously without delay.
Final Answer:
It never updates previousMillis, causing continuous prints. -> Option A
Hint: Always update previousMillis after action to avoid repeats [OK]
Common Mistakes:
Forgetting to update previousMillis
Changing comparison operator incorrectly
Thinking Serial.println() is invalid in loop
5. You want to blink an LED every 500ms and read a sensor every 200ms without blocking. Which code structure best achieves this?
hard
A. Use while loops to wait 500ms and 200ms before each task.
B. Use delay(500) for LED blink and delay(200) for sensor reading in sequence.
C. Use a single millis() timer for both tasks with combined interval 700ms.
D. Use two millis() timers, one for LED and one for sensor, each updating separately.
Solution
Step 1: Understand multitasking with millis()
Each task needs its own timer to run independently without blocking.
Step 2: Evaluate options
Use two millis() timers, one for LED and one for sensor, each updating separately. This uses two separate millis() timers, allowing LED and sensor to run at different intervals smoothly.
Final Answer:
Use two millis() timers, one for LED and one for sensor, each updating separately. -> Option D
Quick Check:
Separate timers = true multitasking [OK]
Hint: Use separate millis() timers for each task to avoid blocking [OK]
Common Mistakes:
Using delay() which blocks all tasks
Combining intervals causing missed timings
Using while loops that block execution
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.