The "If-Then" Misconception in Arduino C++
If you are coming from BASIC, Python, or pseudocode, you are likely searching for if then statements in Arduino. Here is the direct answer: Arduino C++ does not use the word then.
Arduino's programming language is based on C/C++. In C++, the then keyword is entirely omitted. Instead, conditional execution is handled by wrapping the action in curly braces { } immediately following the if (condition) evaluation. Attempting to type the word "then" in the Arduino IDE will result in an immediate compilation error.
The correct syntax structure is:
if (temperature > 25.0) {
// This block executes if the condition is true
digitalWrite(RELAY_PIN, LOW);
}
In this guide, we will move past the syntax myth and build a practical project that relies heavily on robust conditional logic: a multi-stage thermal management system. We will cover exact wiring, write production-ready code featuring hysteresis (a concept most beginner tutorials miss), and debug the exact compiler errors you will face when writing if statements.
Project Spec Sheet: Multi-Stage Thermal Management
This project reads ambient temperature and uses conditional logic to trigger a 5V cooling fan via a relay, while displaying the state on an I2C OLED. We are targeting the Arduino Uno R4 Minima, which features a 48 MHz Arm Cortex-M4 processor, making it ideal for fast sensor polling without the overhead of the WiFi module found on the R4 WiFi variant.
Bill of Materials
| Component | Exact Variant / Model | Notes |
|---|---|---|
| Microcontroller | Arduino Uno R4 Minima | ATmega4809 / RA4M1 hybrid |
| Temp Sensor | DHT22 (AM2302) | 3.3V to 5V tolerant, 0.1°C resolution |
| Display | 0.96" SSD1306 I2C OLED | 128x64 pixels, 4-pin I2C interface |
| Relay Module | SRD-05VDC-SL-C (1-Channel) | Active LOW trigger, opto-isolated |
| Load | 5V DC Brushless Fan (40mm) | Keep it 5V DC for bench safety |
| Wiring | 22 AWG solid core jumper wires | Pre-cut breadboard lengths |
Pin Mapping Table
| Component Pin | Arduino Uno R4 Minima Pin | Wire Color (Recommended) |
|---|---|---|
| DHT22 VCC | 5V | Red |
| DHT22 Data | D2 | Yellow |
| DHT22 GND | GND | Black |
| OLED VCC | 5V | Red |
| OLED GND | GND | Black |
| OLED SDA | A4 (SDA) | Blue |
| OLED SCL | A5 (SCL) | Green |
| Relay VCC | 5V | Red |
| Relay IN | D8 | Orange |
| Relay GND | GND | Black |
Step-by-Step Wiring and Assembly
- Power Rails: Connect the Arduino 5V and GND pins to the breadboard's positive and negative power rails.
- DHT22 Sensor: Wire VCC to 5V, GND to ground, and the Data pin to D2. Critical: If your DHT22 breakout board does not have a built-in pull-up resistor, you must place a 10kΩ resistor between the VCC and Data pins.
- I2C OLED: Connect VCC to 5V, GND to ground, SDA to A4, and SCL to A5. The Uno R4 Minima maps the primary I2C bus to these analog pins.
- Relay Module: Wire VCC to 5V, GND to ground, and the IN (signal) pin to D8. Note that most 5V relay modules are Active LOW, meaning the relay engages when the pin is pulled to GND (0V).
- Fan Load: Connect the 5V power supply positive to the relay's COM terminal. Connect the NO (Normally Open) terminal to the positive wire of your 5V fan. Connect the fan's negative wire directly to the power supply ground.
- Verify: Before plugging in the Arduino, use a multimeter in continuity mode to check for accidental shorts between the 5V and GND rails on your breadboard.
Complete Compilable Code with Conditional Logic
The following code targets the Arduino Uno R4 Minima. It requires the DHT sensor library and Adafruit SSD1306 libraries (install both via the Arduino Library Manager, ensuring you also install the Adafruit GFX dependency).
Notice the use of hysteresis in the if / else if blocks. A naive if (temp > 25) statement will cause the relay to click on and off rapidly if the temperature hovers exactly at 25.0°C. Hysteresis introduces a deadband to prevent this hardware-killing chatter.
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --- PIN DEFINITIONS ---
#define DHTPIN 2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // Sensor type
#define RELAY_PIN 8 // Digital pin connected to Relay IN
// --- DISPLAY DEFINITIONS ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin not used
#define SCREEN_ADDRESS 0x3C
// --- THERMAL THRESHOLDS (Hysteresis) ---
#define TEMP_HIGH 26.0 // Turn fan ON above this temp
#define TEMP_LOW 24.5 // Turn fan OFF below this temp
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
bool fanState = false; // Track current state to prevent redundant writes
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // HIGH = OFF for Active LOW relays
dht.begin();
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Halt execution if display fails
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
}
void loop() {
// Wait 2 seconds between readings (DHT22 max sample rate)
delay(2000);
float tempC = dht.readTemperature();
// ERROR HANDLING: Check if sensor read failed
if (isnan(tempC)) {
Serial.println(F("Failed to read from DHT sensor!"));
display.clearDisplay();
display.setCursor(0,0);
display.println("DHT22 ERROR");
display.display();
return; // Skip the rest of the loop
}
// --- CONDITIONAL LOGIC WITH HYSTERESIS ---
if (tempC >= TEMP_HIGH && !fanState) {
// Temperature crossed upper threshold and fan is currently OFF
fanState = true;
digitalWrite(RELAY_PIN, LOW); // Engage relay (Active LOW)
Serial.println("Fan ENGAGED");
} else if (tempC <= TEMP_LOW && fanState) {
// Temperature dropped below lower threshold and fan is currently ON
fanState = false;
digitalWrite(RELAY_PIN, HIGH); // Disengage relay
Serial.println("Fan DISENGAGED");
} else {
// Temperature is in the deadband (between 24.5 and 26.0)
// Maintain current state. No action required.
}
// --- UPDATE DISPLAY ---
display.clearDisplay();
display.setCursor(0, 0);
display.print("Temp: ");
display.print(tempC, 1);
display.println(" C");
display.setCursor(0, 20);
if (fanState) {
display.println("Status: COOLING");
} else {
display.println("Status: STANDBY");
}
display.display();
}
Debugging: First 3 Things to Check When Logic Fails
When your conditional logic doesn't behave as expected, or the IDE throws a red error, follow this ranked troubleshooting path.
1. The Literal "Then" Syntax Error
Symptom: You typed if (temp > 25) then { out of habit from other languages.
Exact Error String: error: expected ';' before 'then'
The Fix: Delete the word then. The C++ compiler evaluates the parenthesis and immediately expects an opening curly brace { or a single executable statement. Review the official Arduino if statement reference to internalize the syntax.
2. The Assignment vs. Equality Trap
Symptom: Your if block always executes, regardless of the sensor value, and the relay stays on.
Exact Error String: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
The Fix: You used a single equals sign = (assignment) instead of a double equals sign == (comparison). if (fanState = true) assigns true to the variable, and then evaluates the result (which is true), causing the block to always run. Change it to if (fanState == true) or simply if (fanState).
3. Relay Chatter (The Missing Deadband)
Symptom: The code compiles perfectly, but the relay clicks rapidly on and off every 2 seconds when the room is near your target temperature.
The Cause: Floating point noise and lack of hysteresis. If your threshold is 25.0°C, the DHT22 might read 25.01°C (turns on), then 24.99°C (turns off), then 25.02°C (turns on).
The Fix: Implement the hysteresis logic shown in the code above. Use an upper threshold to turn the load ON, and a lower threshold to turn it OFF, creating a "deadband" where the state is locked.
How to Extend or Simplify the Build
Depending on your project goals, you can scale this conditional logic framework up or down.
- Simplify (Bench Testing): Strip out the I2C OLED code and the
Adafruit_SSD1306library dependencies. Rely entirely onSerial.println()to monitor theif/elsestate transitions. This reduces memory footprint and eliminates I2C address conflicts. - Extend (Multi-Stage Logic): Add a second relay and a heating element (like a 12V polyimide heater pad). You can chain
else ifstatements to create a climate controller:if (temp < 18)trigger heater,else if (temp > 26)trigger fan,elseidle both. - Extend (PID Control): For precision incubators, standard
if/thenlogic is too binary. Replace the conditional blocks with a PID library (likeArduinoPID) to output a PWM signal to a MOSFET, allowing proportional heating/cooling rather than harsh on/off switching.
Frequently Asked Questions
How do you write an if-then statement in Arduino?
You do not use the word "then". In Arduino C++, you write if (condition) { action; }. The curly braces act as the boundary for the conditional execution block, replacing the need for a then keyword found in languages like BASIC or Ruby.
Can I use multiple conditions in one Arduino if statement?
Yes. You can combine multiple evaluations using the logical AND (&&) or logical OR (||) operators. For example: if (tempC > 25.0 && humidity > 60.0) will only execute if both conditions are true. Always use parentheses to group complex logic to ensure the compiler evaluates the order of operations exactly as you intend.
Why is my Arduino if statement failing with float variables?
Comparing floating-point numbers for exact equality (e.g., if (tempC == 25.0)) is dangerous due to floating-point precision limits in C++. A calculated float might actually be 25.000001 or 24.999998. Always use greater-than/less-than operators (>, <, >=, <=) or check if the absolute difference between two floats is smaller than a tiny epsilon value.
What is the difference between if-else and switch-case in Arduino?
Use if/else statements when evaluating ranges, floating-point numbers, or complex boolean logic (e.g., temp > 20 && fan == ON). Use switch/case when evaluating a single integer or character variable against a list of discrete, exact values (e.g., parsing a serial command character like 'A', 'B', or 'C'). Switch-case is generally faster for the microcontroller to execute when dealing with many discrete integer states.






