Skip to content

Arduino - Control Statements

To create interactive and intelligent projects, your program needs to make decisions. Control statements are the fundamental building blocks that allow you to dictate the flow of your program’s execution based on specific conditions. This enables your Arduino to react to sensor inputs, user commands, and internal state changes.

Modern C++ (the language Arduino uses) provides a powerful set of control structures. Let’s explore the most essential ones with practical, real-world examples.

1. Conditional Statements: if, else if, else

Section titled “1. Conditional Statements: if, else if, else”

This is the most common decision-making tool. It executes a block of code only if a certain condition is true.

  • if: Checks a condition. If it’s true, the code inside the curly braces {} runs.
  • else if: If the first if condition is false, this checks a second condition.
  • else: If all preceding if and else if conditions are false, the code in the else block runs.

Let’s make an LED turn on only when a button is pressed. This demonstrates a basic input-to-output reaction.

// Best Practice: Use 'const int' or 'constexpr' for pin numbers.
// This prevents accidental changes and makes code more readable.
constexpr int LED_PIN = 13; // The built-in LED on most Arduino boards
constexpr int BUTTON_PIN = 2; // Connect a push-button to pin 2
void setup() {
// Initialize the pins for their designated purpose
pinMode(LED_PIN, OUTPUT);
// Use INPUT_PULLUP to enable the internal pull-up resistor.
// This means the pin reads HIGH when the button is not pressed and LOW when it is.
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Start serial communication for debugging
Serial.begin(9600);
}
void loop() {
// Read the state of the button
int buttonState = digitalRead(BUTTON_PIN);
// The logic is inverted because of INPUT_PULLUP: LOW means pressed.
if (buttonState == LOW) {
// If the button is pressed, turn the LED on.
digitalWrite(LED_PIN, HIGH);
Serial.println("Button is pressed. LED ON.");
} else {
// If the button is not pressed, turn the LED off.
digitalWrite(LED_PIN, LOW);
// No need to print here, or it will flood the serial monitor.
}
delay(50); // A small delay for debouncing and to prevent serial flooding
}

When you have a single variable to check against multiple possible values, a switch statement is often cleaner and more efficient than a long series of if-else if statements.

Imagine a device with three modes (e.g., solid light, blinking, fading) selected by a command sent over the Serial Monitor.

constexpr int LED_PIN = 9; // Use a PWM pin for fading (e.g., 3, 5, 6, 9, 10, 11 on UNO)
char deviceMode = 's'; // 's' for solid, 'b' for blink, 'f' for fade
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
Serial.println("Enter a mode: 's' (solid), 'b' (blink), 'f' (fade)");
}
void loop() {
// Check if there is data available to read from serial
if (Serial.available() > 0) {
char input = Serial.read();
if (input == 's' || input == 'b' || input == 'f') {
deviceMode = input;
}
}
// Use a switch statement to handle the current mode
switch (deviceMode) {
case 's':
// Solid mode: LED is always on
digitalWrite(LED_PIN, HIGH);
break; // **Crucial**: 'break' exits the switch. Without it, execution falls through!
case 'b':
// Blink mode
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
break;
case 'f':
// Fade mode (using a for loop, see next section)
for (int i = 0; i <= 255; i++) {
analogWrite(LED_PIN, i);
delay(5);
}
for (int i = 255; i >= 0; i--) {
analogWrite(LED_PIN, i);
delay(5);
}
break;
default:
// Best Practice: Always include a default case for unexpected values.
// In this case, do nothing.
break;
}
}

Forgetting the break statement is a very common bug. If you omit it, the program will continue executing the code in the next case block, leading to unintended behavior.

Loops are used to execute a block of code repeatedly. This is essential for tasks like blinking an LED, reading a sensor multiple times, or processing data.

Perfect for when you know exactly how many times you want to repeat an action. The LED fade example in the switch statement uses a for loop.

Ideal for when you want a loop to continue as long as a condition is true, but you don’t know in advance when that will be.

// Practical Example: Wait for a sensor to be ready
// (This is a conceptual example)
#include <Wire.h>
#include <Adafruit_Sensor.h>
// #include <Some_Sensor_Library.h> // A hypothetical sensor library
// SomeSensor sensor;
void setup() {
Serial.begin(9600);
while (!Serial) {
; // Wait for serial port to connect. Needed for native USB port boards.
}
Serial.println("Waiting for sensor to initialize...");
// A while loop is perfect for waiting for a condition to be met
// while (!sensor.isReady()) {
// Serial.print(".");
// delay(100);
// }
Serial.println("\nSensor is ready!");
}
void loop() {
// Main program logic starts here
}

This is a compact, one-line shorthand for a simple if-else statement. It’s great for assigning a value to a variable based on a condition.

Syntax: condition ? value_if_true : value_if_false

Section titled “Syntax: condition ? value_if_true : value_if_false”
// Before (using if-else):
int x = 10;
int y;
if (x > 5) {
y = 100;
} else {
y = 0;
}
// After (using ternary operator):
int x = 10;
int y = (x > 5) ? 100 : 0; // y will be 100
// Another example
int lightLevel = analogRead(A0);
String message = (lightLevel < 500) ? "It's dark" : "It's bright";
Serial.println(message);

Combine what you’ve learned! Create a simple traffic light system with red, yellow, and green LEDs. Use digitalWrite() to control the LEDs and delay() to time the sequence. Structure your logic using if-else or a switch statement to cycle through the states: Green -> Yellow -> Red -> Green…