Skip to main content

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:

  1. for loops - Used when you know exactly how many times you want to repeat a block of code
  2. while loops - Used when you want to repeat code as long as a specific condition is true
  3. do-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

cpp
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

cpp
// 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:

  1. Initialize all LED pins as outputs in the setup() function
  2. Turn on each LED sequentially in the first loop
  3. 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

cpp
while (condition) {
// Code to be repeated
}

Example: Reading a Button Until Pressed

cpp
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:

  1. We use a while loop to continuously check if the button is not pressed (HIGH when using INPUT_PULLUP)
  2. While waiting, the LED blinks rapidly
  3. 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

cpp
do {
// Code to be repeated
} while (condition);

Example: Menu Selection System

cpp
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:

  1. We use a do-while loop to display the current menu selection
  2. The current selection is always shown at least once (even if the button is already pressed)
  3. When the button is pressed, we move to the next option
  4. 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

cpp
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:

  1. The outer loop iterates through each row
  2. The inner loop iterates through each column for the current row
  3. 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.

cpp
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.

cpp
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.

cpp
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:

cpp
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:

  1. A for loop used as a timeout mechanism
  2. A break statement to exit early when a button is pressed
  3. A while loop for a countdown timer
  4. Conditional logic within loops

Loop Efficiency and Best Practices

When using loops in Arduino projects, keep these best practices in mind:

  1. Avoid blocking delays in critical applications - Instead of using delay(), consider using timers and state machines
  2. Keep loops as short as possible - Long-running loops can make your Arduino unresponsive
  3. 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++) { ... }
  4. Watch out for infinite loops - Always ensure there's a way to exit the loop
  5. Consider the millis() function for timing operations without blocking:
    cpp
    unsigned 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 code
  • while loops execute as long as a condition remains true
  • do-while loops always execute at least once, then check if they should continue
  • Loop control statements like break and continue 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

  1. LED Chase Effect: Create a program that makes an LED "chase" back and forth across a row of 6-8 LEDs.
  2. Button Counter: Make a circuit with a button and display that counts how many times the button has been pressed.
  3. Light Dimmer: Use a for loop with analogWrite() to gradually dim and brighten an LED.
  4. Sensor Data Logger: Read an analog sensor every second for one minute, then calculate and display the average reading.
  5. Interactive Menu: Create a menu system that allows users to select between different modes of operation using a button.

Additional Resources



If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)