Arduino Switch Case
Introduction
The switch case
statement is a powerful control flow structure in Arduino programming that allows you to select one of many code blocks to execute based on the value of a variable. It provides a cleaner and more efficient alternative to multiple if-else
statements when you need to compare a variable against several possible values.
In this tutorial, we'll explore how to use switch case
statements in Arduino, understand their syntax, and see practical examples that demonstrate their usefulness in real-world applications.
Basic Syntax
The basic syntax of a switch case
statement in Arduino is:
switch (variable) {
case value1:
// code to execute if variable equals value1
break;
case value2:
// code to execute if variable equals value2
break;
case value3:
// code to execute if variable equals value3
break;
.
.
.
default:
// code to execute if variable doesn't match any case
break;
}
Let's break down the key components:
switch (variable)
: Evaluates the variable to match against different cases.case value
: Specifies a value to compare against the variable.break
: Terminates the switch block. If omitted, execution will "fall through" to the next case.default
: Optional section that executes when no case matches the variable.
How Switch Case Works
When the Arduino encounters a switch case
statement:
- It evaluates the expression inside the parentheses once.
- It compares the result with the values in each
case
. - If a match is found, it executes the code associated with that case.
- The
break
statement exits the switch block. - If no match is found and a
default
section exists, it executes the default code.
Basic Example: LED Control
Let's start with a simple example that uses a switch case
statement to control an LED based on a button press counter:
const int buttonPin = 2; // Push button connected to pin 2
const int ledPin = 13; // LED connected to pin 13
int buttonPresses = 0; // Counter for button presses
int lastButtonState = HIGH; // Previous button state
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("LED Control Program Started");
}
void loop() {
// Read the current button state
int buttonState = digitalRead(buttonPin);
// Check if button was pressed (LOW) and previously was not pressed (HIGH)
if (buttonState == LOW && lastButtonState == HIGH) {
// Increment counter and wrap around after 4
buttonPresses = (buttonPresses + 1) % 5;
// Use switch case to handle different button press counts
switch (buttonPresses) {
case 0:
digitalWrite(ledPin, LOW);
Serial.println("LED OFF");
break;
case 1:
digitalWrite(ledPin, HIGH);
Serial.println("LED ON");
break;
case 2:
// Blink slowly
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
Serial.println("LED Blinking Slowly");
break;
case 3:
// Blink quickly
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
delay(100);
Serial.println("LED Blinking Quickly");
break;
case 4:
// Pulse (fade in and out)
for (int i = 0; i < 255; i++) {
analogWrite(ledPin, i);
delay(5);
}
for (int i = 255; i >= 0; i--) {
analogWrite(ledPin, i);
delay(5);
}
Serial.println("LED Pulsing");
break;
}
}
// Save current button state for next comparison
lastButtonState = buttonState;
}
Example Output
When you run this program and press the button multiple times, you'll see the following output in the Serial Monitor:
LED Control Program Started
LED OFF
LED ON
LED Blinking Slowly
LED Blinking Quickly
LED Pulsing
LED OFF
...
Fall-Through Behavior
One important aspect of switch case
statements is the "fall-through" behavior that occurs when you omit the break
statement. This can be useful when you want multiple cases to execute the same code:
int sensorValue = analogRead(A0) / 200; // Read analog value and scale to 0-5
switch (sensorValue) {
case 5:
Serial.println("Level 5: Critical level reached!");
// Fall through to case 4
case 4:
Serial.println("Level 4: Warning level exceeded!");
// Fall through to case 3
case 3:
Serial.println("Level 3: Caution level reached!");
digitalWrite(redLED, HIGH); // Turn on red warning light
break;
case 2:
Serial.println("Level 2: Normal operation");
digitalWrite(greenLED, HIGH); // Turn on green status light
break;
case 1:
case 0:
Serial.println("Level 0-1: Low level detected");
digitalWrite(blueLED, HIGH); // Turn on blue indicator
break;
default:
Serial.println("Invalid reading");
break;
}
In this example, if sensorValue
is 5, all messages for levels 5, 4, and 3 will be printed, and the red LED will be turned on.
Practical Application: Multi-Mode Device Control
Let's look at a more complex example that demonstrates how switch case
can be used in a real-world application to create a multi-mode device:
const int modeButtonPin = 2; // Button to change modes
const int actionButtonPin = 3; // Button to perform action in current mode
const int ledPins[] = {9, 10, 11}; // RGB LED pins (R, G, B)
int currentMode = 0; // Current operating mode
int lastModeButtonState = HIGH; // Previous state of mode button
int lastActionButtonState = HIGH; // Previous state of action button
void setup() {
pinMode(modeButtonPin, INPUT_PULLUP);
pinMode(actionButtonPin, INPUT_PULLUP);
for (int i = 0; i < 3; i++) {
pinMode(ledPins[i], OUTPUT);
}
Serial.begin(9600);
Serial.println("Multi-Mode Device Started");
printCurrentMode();
}
void loop() {
// Read button states
int modeButtonState = digitalRead(modeButtonPin);
int actionButtonState = digitalRead(actionButtonPin);
// Check for mode button press
if (modeButtonState == LOW && lastModeButtonState == HIGH) {
// Change mode (cycle through 0-3)
currentMode = (currentMode + 1) % 4;
printCurrentMode();
// Reset all LEDs when changing mode
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], LOW);
}
}
// Check for action button press
if (actionButtonState == LOW && lastActionButtonState == HIGH) {
// Perform action based on current mode
performAction();
}
// Update button states
lastModeButtonState = modeButtonState;
lastActionButtonState = actionButtonState;
delay(50); // Small delay for button debouncing
}
void printCurrentMode() {
Serial.print("Current Mode: ");
switch (currentMode) {
case 0:
Serial.println("RGB Control");
break;
case 1:
Serial.println("Light Show");
break;
case 2:
Serial.println("SOS Signal");
break;
case 3:
Serial.println("Brightness Control");
break;
}
}
void performAction() {
Serial.print("Performing action in mode: ");
switch (currentMode) {
case 0: // RGB Control - Cycle through R, G, B
static int rgbIndex = 0;
// Reset all LEDs
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], LOW);
}
// Turn on one color
digitalWrite(ledPins[rgbIndex], HIGH);
// Print current color
switch (rgbIndex) {
case 0:
Serial.println("Red");
break;
case 1:
Serial.println("Green");
break;
case 2:
Serial.println("Blue");
break;
}
// Cycle to next color
rgbIndex = (rgbIndex + 1) % 3;
break;
case 1: // Light Show - Run a sequence of patterns
Serial.println("Light Show");
runLightShow();
break;
case 2: // SOS Signal - Morse code SOS
Serial.println("SOS Signal");
runSOSSignal();
break;
case 3: // Brightness Control - Cycle through brightness levels
static int brightness = 0;
// Set brightness on all LEDs
for (int i = 0; i < 3; i++) {
analogWrite(ledPins[i], brightness);
}
// Print current brightness level
Serial.print("Brightness: ");
Serial.println(brightness);
// Cycle through brightness levels (0, 64, 128, 192, 255)
brightness = (brightness + 64) % 256;
if (brightness == 0) brightness = 1; // Avoid completely off
break;
}
}
void runLightShow() {
// Simple light show pattern
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], HIGH);
delay(200);
digitalWrite(ledPins[i], LOW);
}
for (int i = 2; i >= 0; i--) {
digitalWrite(ledPins[i], HIGH);
delay(200);
digitalWrite(ledPins[i], LOW);
}
// Blink all LEDs
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], HIGH);
}
delay(200);
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], LOW);
}
delay(200);
}
}
void runSOSSignal() {
// SOS in Morse Code (... --- ...)
// S: Three short flashes
for (int j = 0; j < 2; j++) { // Repeat SOS twice
// S: Three short flashes
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[0], HIGH); // Use red LED for SOS
delay(200);
digitalWrite(ledPins[0], LOW);
delay(200);
}
delay(300);
// O: Three long flashes
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[0], HIGH);
delay(600);
digitalWrite(ledPins[0], LOW);
delay(200);
}
delay(300);
// S: Three short flashes again
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[0], HIGH);
delay(200);
digitalWrite(ledPins[0], LOW);
delay(200);
}
delay(1000); // Pause between SOS signals
}
}
This example creates a device with four different modes that can be cycled through with one button, while another button performs actions within the current mode. The switch case
statements are used both to select the appropriate mode and to handle mode-specific actions.
Limitations and Considerations
While switch case
statements are powerful, they do have some limitations:
-
Data Type Restrictions: In Arduino C++,
switch
can only be used with integral data types (int, char, etc.). You cannot use it with floating-point values or strings. -
Case Values Must Be Constants: The case values must be constant expressions evaluated at compile time.
// This will NOT work:
int myVariable = 5;
switch (x) {
case myVariable: // ERROR: Not a constant expression
// ...
break;
}
// This will work:
const int myConstant = 5;
switch (x) {
case myConstant: // OK: myConstant is a constant
// ...
break;
}
- No Range Checking: You cannot use ranges in case statements directly. Each case must be a specific value.
Switch Case vs. If-Else If
When should you use switch case
instead of if-else if
chains?
Use switch case
when:
- You're comparing a single variable against multiple constant values
- You have many conditions to check against
- Code readability and maintainability are priorities
- Performance matters (switch can be more efficient for many cases)
Use if-else if
when:
- You need to evaluate different variables or expressions
- You need to check ranges rather than exact values
- You need to use non-integral types (floating point, strings)
- You need complex conditional logic
Example: Switch Case vs. If-Else
Here's a comparison of the same logic implemented with both approaches:
Switch Case Implementation:
int sensorValue = map(analogRead(A0), 0, 1023, 0, 5);
switch (sensorValue) {
case 0:
Serial.println("Very Low");
break;
case 1:
Serial.println("Low");
break;
case 2:
Serial.println("Medium");
break;
case 3:
Serial.println("High");
break;
case 4:
case 5:
Serial.println("Very High");
break;
default:
Serial.println("Invalid reading");
break;
}
If-Else Implementation:
int sensorValue = map(analogRead(A0), 0, 1023, 0, 5);
if (sensorValue == 0) {
Serial.println("Very Low");
} else if (sensorValue == 1) {
Serial.println("Low");
} else if (sensorValue == 2) {
Serial.println("Medium");
} else if (sensorValue == 3) {
Serial.println("High");
} else if (sensorValue == 4 || sensorValue == 5) {
Serial.println("Very High");
} else {
Serial.println("Invalid reading");
}
As you can see, the switch case
version is more readable when you have many conditions checking the same variable.
Summary
The switch case
statement is a valuable control structure in Arduino programming that allows you to:
- Select from multiple code blocks based on a variable's value
- Create more readable code compared to long if-else chains
- Implement complex state machines and mode-based behaviors
- Improve code organization for multi-function devices
Remember to always include the break
statement at the end of each case unless you specifically want to leverage the fall-through behavior. While switch case
has some limitations, it's an excellent tool for creating more maintainable Arduino programs when handling multiple discrete states or modes.
Exercises
-
Basic Switch: Create a program that reads a value from a potentiometer (analog input) and maps it to 5 different states (0-4). Use a switch case to light up different LEDs based on the state.
-
Menu System: Build a simple menu system that displays different options on the Serial Monitor and allows the user to select an option by sending a number. Use a switch case to handle each menu option.
-
State Machine: Create a traffic light controller using a switch case statement to manage the state transitions between red, yellow, and green lights.
-
Enhanced Control: Modify the "Multi-Mode Device" example to add a fifth mode of your choice. Think about what new functionality you could add and how to implement it.
-
Fall-Through Practice: Write a program that uses the fall-through behavior of switch case to implement a cascading alarm system where higher alert levels trigger all lower-level responses as well.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)