Arduino Loops
Introduction
Loops are fundamental control structures in programming that allow you to execute a block of code repeatedly. In Arduino programming, loops are essential for tasks that need to be performed multiple times, such as reading sensor values, updating displays, or controlling LEDs in patterns.
This guide will introduce you to the different types of loops available in Arduino programming, explain how they work, and provide practical examples to help you understand when and how to use them effectively.
Types of Loops in Arduino
Arduino supports three main types of loops:
for
loops - Used when you know exactly how many times you want to repeat a block of codewhile
loops - Used when you want to repeat code as long as a specific condition is truedo-while
loops - Similar to while loops, but guarantees the code block executes at least once
Let's explore each type in detail.
The for
Loop
The for
loop is ideal when you know in advance how many times you want to repeat a block of code.
Syntax
for (initialization; condition; increment/decrement) {
// Code to be repeated
}
- Initialization: Executed once at the beginning, typically sets a counter variable
- Condition: Checked before each iteration; loop continues as long as it's true
- Increment/Decrement: Executed after each iteration, typically updates the counter
Example: Blinking Multiple LEDs
// Define LED pins
const int NUM_LEDS = 5;
const int ledPins[] = {2, 3, 4, 5, 6};
void setup() {
// Initialize all LED pins as outputs
for (int i = 0; i < NUM_LEDS; i++) {
pinMode(ledPins[i], OUTPUT);
}
}
void loop() {
// Turn all LEDs on one by one
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(ledPins[i], HIGH);
delay(200);
}
// Turn all LEDs off one by one
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(ledPins[i], LOW);
delay(200);
}
}
In this example, we use a for
loop to:
- Initialize all LED pins as outputs in the
setup()
function - Turn on each LED sequentially in the first loop
- Turn off each LED sequentially in the second loop
The result is a simple "chase" effect across the five LEDs.
The while
Loop
The while
loop continues executing a block of code as long as a specified condition is true. It checks the condition before executing the loop body.
Syntax
while (condition) {
// Code to be repeated
}
Example: Reading a Button Until Pressed
const int buttonPin = 2;
const int ledPin = 13;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("Press the button to continue...");
}
void loop() {
// Wait for button press
while (digitalRead(buttonPin) == HIGH) {
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
delay(100);
}
Serial.println("Button pressed! Continuing with program...");
delay(2000); // Wait 2 seconds before restarting
}
In this example:
- We use a
while
loop to continuously check if the button is not pressed (HIGH when using INPUT_PULLUP) - While waiting, the LED blinks rapidly
- Once the button is pressed, the loop exits and the program continues
The do-while
Loop
The do-while
loop is similar to the while
loop, but with one important difference: it always executes the code block at least once before checking the condition.
Syntax
do {
// Code to be repeated
} while (condition);
Example: Menu Selection System
const int buttonPin = 2;
const int ledPins[] = {5, 6, 7};
int selectedOption = 0;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
for (int i = 0; i < 3; i++) {
pinMode(ledPins[i], OUTPUT);
}
Serial.begin(9600);
Serial.println("Menu Selection System");
Serial.println("Press the button to cycle through options");
}
void loop() {
// Always show the current selection at least once
do {
// Display the current selection
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], i == selectedOption ? HIGH : LOW);
}
// Print the current option
Serial.print("Current option: ");
Serial.println(selectedOption + 1);
delay(500); // Debounce delay
} while (digitalRead(buttonPin) == HIGH); // Continue until button is pressed
// Button was pressed, move to next option
selectedOption = (selectedOption + 1) % 3;
// Wait for button release
while (digitalRead(buttonPin) == LOW) {
delay(50);
}
}
In this example:
- We use a
do-while
loop to display the current menu selection - The current selection is always shown at least once (even if the button is already pressed)
- When the button is pressed, we move to the next option
- We use another
while
loop to wait for the button to be released
Nested Loops
You can place loops inside other loops to create more complex behaviors. These are called nested loops.
Example: LED Matrix Pattern
const int ROWS = 3;
const int COLS = 3;
const int rowPins[ROWS] = {2, 3, 4};
const int colPins[COLS] = {5, 6, 7};
void setup() {
// Initialize row pins as OUTPUT
for (int i = 0; i < ROWS; i++) {
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], LOW);
}
// Initialize column pins as OUTPUT
for (int j = 0; j < COLS; j++) {
pinMode(colPins[j], OUTPUT);
digitalWrite(colPins[j], HIGH); // Columns are active LOW
}
}
void loop() {
// Pattern 1: Light up one LED at a time
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
// Turn on current LED
digitalWrite(rowPins[row], HIGH);
digitalWrite(colPins[col], LOW);
delay(200); // Keep it on for a moment
// Turn off current LED
digitalWrite(rowPins[row], LOW);
digitalWrite(colPins[col], HIGH);
}
}
delay(1000); // Pause between patterns
}
In this example, we use nested loops to control a 3×3 LED matrix:
- The outer loop iterates through each row
- The inner loop iterates through each column for the current row
- This creates a pattern where each LED lights up one at a time, moving across and down
Loop Control Statements
Arduino provides several statements to control the flow of loops:
break
Statement
The break
statement exits the loop immediately, skipping any remaining iterations.
const int buttonPin = 2;
const int ledPin = 13;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
Serial.println("LED will blink 10 times unless the button is pressed");
for (int i = 0; i < 10; i++) {
// Check if the button is pressed
if (digitalRead(buttonPin) == LOW) {
Serial.println("Button pressed! Breaking out of the loop");
break; // Exit the loop early
}
// Blink the LED
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
Serial.print("Blink count: ");
Serial.println(i + 1);
}
Serial.println("Loop finished");
delay(2000); // Wait before starting again
}
In this example, the break
statement exits the loop early if the button is pressed, stopping the LED from blinking further.
continue
Statement
The continue
statement skips the current iteration and moves to the next one.
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Printing only odd numbers from 1 to 10:");
for (int i = 1; i <= 10; i++) {
// Skip even numbers
if (i % 2 == 0) {
continue; // Skip to the next iteration
}
// This code only executes for odd numbers
Serial.print("Number: ");
Serial.println(i);
delay(500);
}
Serial.println("Loop finished");
delay(3000); // Wait before starting again
}
In this example, the continue
statement skips the printing code whenever i
is an even number, resulting in only odd numbers being printed.
Special Loop: loop()
Function
In Arduino, the loop()
function itself is a special kind of loop that runs continuously after the setup()
function completes. This is automatically handled by the Arduino framework and doesn't require any special syntax.
void setup() {
// Runs once when the Arduino starts or resets
Serial.begin(9600);
Serial.println("Arduino has started!");
}
void loop() {
// Runs repeatedly until the Arduino loses power or resets
Serial.println("This will print forever");
delay(1000); // Wait 1 second between prints
}
Practical Project: Traffic Light Controller
Let's combine different types of loops to create a traffic light controller:
const int redPin = 2;
const int yellowPin = 3;
const int greenPin = 4;
const int pedestrianButtonPin = 7;
const int pedestrianLedPin = 8;
void setup() {
// Initialize traffic light pins
pinMode(redPin, OUTPUT);
pinMode(yellowPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(pedestrianLedPin, OUTPUT);
// Initialize button with pull-up resistor
pinMode(pedestrianButtonPin, INPUT_PULLUP);
// Start with green light for traffic
digitalWrite(redPin, LOW);
digitalWrite(yellowPin, LOW);
digitalWrite(greenPin, HIGH);
digitalWrite(pedestrianLedPin, LOW);
}
void loop() {
// Normal traffic flow (green light)
digitalWrite(greenPin, HIGH);
// Check for pedestrian button press
bool pedestrianWaiting = false;
// Wait for either button press or timeout
for (int i = 0; i < 50; i++) {
if (digitalRead(pedestrianButtonPin) == LOW) {
pedestrianWaiting = true;
break; // Exit the waiting loop
}
delay(100);
}
// Change lights only if pedestrian is waiting or timeout completed
if (pedestrianWaiting) {
// Change to yellow
digitalWrite(greenPin, LOW);
digitalWrite(yellowPin, HIGH);
delay(2000);
// Change to red
digitalWrite(yellowPin, LOW);
digitalWrite(redPin, HIGH);
// Pedestrian crossing time
digitalWrite(pedestrianLedPin, HIGH);
// Countdown with flashing for pedestrians
int countdownSeconds = 5;
while (countdownSeconds > 0) {
if (countdownSeconds <= 2) {
// Flash pedestrian light when time is almost up
digitalWrite(pedestrianLedPin, LOW);
delay(250);
digitalWrite(pedestrianLedPin, HIGH);
delay(250);
} else {
delay(500);
}
countdownSeconds--;
}
// Turn off pedestrian signal
digitalWrite(pedestrianLedPin, LOW);
// Change back to green
digitalWrite(redPin, LOW);
digitalWrite(yellowPin, HIGH);
delay(1000);
digitalWrite(yellowPin, LOW);
}
}
This example demonstrates:
- A
for
loop used as a timeout mechanism - A
break
statement to exit early when a button is pressed - A
while
loop for a countdown timer - Conditional logic within loops
Loop Efficiency and Best Practices
When using loops in Arduino projects, keep these best practices in mind:
- Avoid blocking delays in critical applications - Instead of using
delay()
, consider using timers and state machines - Keep loops as short as possible - Long-running loops can make your Arduino unresponsive
- Use loop variables efficiently - For resource-constrained devices like Arduino, optimize variable types:
cpp
// More efficient for small loops (0-255)
for (byte i = 0; i < 10; i++) { ... }
// For larger loops
for (int i = 0; i < 1000; i++) { ... } - Watch out for infinite loops - Always ensure there's a way to exit the loop
- Consider the
millis()
function for timing operations without blocking:cppunsigned long previousMillis = 0;
const long interval = 1000; // Interval in milliseconds
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Code to run at the interval
}
// Other code runs without being blocked
}
Summary
Loops are essential control structures in Arduino programming that allow you to execute code repeatedly based on specific conditions:
for
loops are ideal when you know exactly how many times to repeat codewhile
loops execute as long as a condition remains truedo-while
loops always execute at least once, then check if they should continue- Loop control statements like
break
andcontinue
give you additional control - Nested loops allow for more complex behaviors and patterns
By mastering loops, you'll be able to create more efficient, responsive, and dynamic Arduino projects that can handle repetitive tasks with ease.
Exercises for Practice
- LED Chase Effect: Create a program that makes an LED "chase" back and forth across a row of 6-8 LEDs.
- Button Counter: Make a circuit with a button and display that counts how many times the button has been pressed.
- Light Dimmer: Use a
for
loop withanalogWrite()
to gradually dim and brighten an LED. - Sensor Data Logger: Read an analog sensor every second for one minute, then calculate and display the average reading.
- Interactive Menu: Create a menu system that allows users to select between different modes of operation using a button.
Additional Resources
- Arduino Reference: Control Structures
- Arduino Tutorial: For Loops
- Arduino Reference: millis() - For more advanced non-blocking timing techniques
If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)