The Hardware Reality Behind Arduino If Else Logic
Most beginner tutorials teach if/else logic using simple binary examples: if a button is pressed, turn on an LED; else, turn it off. But when you move from digital buttons to analog physical sensors—like temperature, humidity, or light—naive if/else logic falls apart.
Consider a basic thermostat. If you write if (temp > 30) { relay.on(); } else { relay.off(); }, sensor noise will cause the temperature reading to jitter between 29.99°C and 30.01°C. Your relay will click on and off dozens of times per second. This phenomenon, known as relay chatter, will weld your relay contacts shut or destroy your switching transistor within a week.
To fix this, we use hysteresis (a deadband) and the if / else if structure. This guide walks through building a physical thermal controller using an Arduino Uno R4 Minima, demonstrating how to write robust conditional logic that survives the noise of the real world.
Parts List and Pin Mapping
This build targets the Arduino Uno R4 Minima (running the Renesas RA4M1 core), chosen for its 5V logic tolerance and robust power regulation, which is critical when driving relay coils. All code is fully compatible with the classic Uno R3, but the R4 Minima is the recommended 2026 standard for new builds.
Bill of Materials
| Component | Exact Variant / Part Number | Estimated Cost |
|---|---|---|
| Microcontroller | Arduino Uno R4 Minima (ABX00080) | $20.00 |
| Sensor | DHT22 (AM2302) with 3-pin breakout board | $6.50 |
| Relay Module | 5V Optocoupler Relay (Songle SRD-05VDC-SL-C) | $3.00 |
| Load | 12V DC 120mm PC Cooling Fan (4-pin PWM) | $12.00 |
| Power Supply | 12V 2A DC Wall Adapter (for fan and relay VCC) | $8.00 |
| Display | 0.96" I2C OLED 128x64 (SSD1306 driver) | $5.00 |
Pin Mapping Table
| Module | Module Pin | Arduino Uno R4 Minima Pin | Notes |
|---|---|---|---|
| DHT22 | VCC | 5V | Do not use 3.3V |
| DHT22 | Data | D2 | Breakout includes 10k pull-up |
| DHT22 | GND | GND | |
| Relay | VCC | VIN (or external 5V) | See power warning below |
| Relay | IN | D8 | Active LOW on most modules |
| Relay | GND | GND | |
| OLED | SDA | A4 | I2C Data |
| OLED | SCL | A5 | I2C Clock |
Wiring and Setup Steps
- Wire the Sensor: Connect the DHT22 VCC to 5V, GND to GND, and Data to D2. If you are using a bare 4-pin DHT22 without a breakout board, you must solder a 10kΩ pull-up resistor between VCC and the Data pin, or the sensor will return NaN (Not a Number) errors.
- Wire the Display: Connect the SSD1306 OLED SDA to A4 and SCL to A5. Connect VCC to 3.3V or 5V (check your specific module's silkscreen) and GND to GND.
- Wire the Relay (Low Voltage DC): Connect the relay IN pin to D8. For the load side, connect the 12V power supply positive to the relay's COM (Common) terminal. Connect the NO (Normally Open) terminal to the red wire of your 12V fan. Connect the fan's black wire directly to the 12V power supply ground.
- Verify De-energized State: Before plugging the Arduino into your PC, ensure the 12V power supply is unplugged. Double-check that no 12V wires are touching the Arduino's 5V or 3.3V pins.
The Complete Compilable Code with Hysteresis
This code targets the Arduino Uno R4 Minima. It uses the if / else if structure to implement a 2°C deadband. The fan turns on at 28°C, but it will not turn off until the temperature drops to 26°C. This completely eliminates relay 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 // DHT 22 (AM2302)
#define RELAY_PIN 8 // Digital pin connected to Relay IN
// --- THRESHOLDS (Hysteresis Deadband) ---
#define TEMP_HIGH 28.0 // Turn fan ON at this temperature
#define TEMP_LOW 26.0 // Turn fan OFF at this temperature
// --- DISPLAY DEFINITIONS ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
// --- OBJECT INITIALIZATION ---
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// State variable to hold relay status between loops
bool fanState = false;
void setup() {
Serial.begin(115200);
// Initialize Relay Pin
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // HIGH = OFF for active-low relay modules
// Initialize DHT Sensor
dht.begin();
// Initialize OLED Display
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Halt execution if display fails
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.println("System Initializing...");
display.display();
delay(2000); // DHT22 requires 2s startup time
}
void loop() {
// Wait 2 seconds between measurements (DHT22 max sample rate)
delay(2000);
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// --- ERROR HANDLING ---
// Check if any reads failed and exit early (to try again)
if (isnan(temperature) || isnan(humidity)) {
Serial.println(F("Failed to read from DHT sensor! Check wiring."));
updateDisplay("DHT ERROR", 0.0, 0.0);
return;
}
// --- CORE DECISION LOGIC: HYSTERESIS ---
if (temperature >= TEMP_HIGH) {
// Temperature exceeded upper threshold: Force ON
fanState = true;
}
else if (temperature <= TEMP_LOW) {
// Temperature dropped below lower threshold: Force OFF
fanState = false;
}
// IMPLICIT ELSE: If temp is between LOW and HIGH, fanState retains its previous value.
// --- ACTUATE HARDWARE ---
if (fanState) {
digitalWrite(RELAY_PIN, LOW); // LOW = ON for active-low modules
} else {
digitalWrite(RELAY_PIN, HIGH); // HIGH = OFF
}
// --- OUTPUT DATA ---
Serial.print(F("Temp: "));
Serial.print(temperature);
Serial.print(F("C | Fan: "));
Serial.println(fanState ? "ON" : "OFF");
updateDisplay("NORMAL", temperature, humidity);
}
// Helper function to update the OLED
void updateDisplay(String status, float temp, float hum) {
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.print(F("Status: "));
display.println(status);
display.setTextSize(2);
display.setCursor(0, 20);
display.print(temp, 1);
display.print(F("C"));
display.setTextSize(1);
display.setCursor(0, 50);
display.print(F("Hum: "));
display.print(hum, 1);
display.print(F("% | Fan: "));
display.println(fanState ? "ON" : "OFF");
display.display();
}
Debugging: When Your Logic Fails in the Real World
When physical hardware meets software, things break in ways the IDE compiler cannot predict. If your build fails, here are the first three things to check, followed by exact compiler errors you might encounter.
The First 3 Things to Check on Failure
- Floating Input Noise on the DHT22: If your serial monitor spams
Failed to read from DHT sensor!, your data pin is likely floating. Even if your breakout board claims to have a pull-up resistor, cheap clones often omit it. Solder a 10kΩ resistor between the VCC and Data pins on the sensor. - Relay Chatter (Missing Hysteresis): If the relay clicks rapidly when the temperature hovers around 28°C, you have accidentally implemented a simple
if/elseinstead of theif / else ifdeadband structure provided above. Verify your thresholds. - Microcontroller Brownout: If the Arduino resets itself the exact moment the relay clicks on, your 5V rail is sagging. The relay coil inrush current is pulling the voltage below the RA4M1's minimum operating threshold. Power the relay VCC from an external supply.
Exact Compiler Error Strings and Fixes
| Exact Error String | Ranked Cause | The Fix |
|---|---|---|
fatal error: DHT.h: No such file or directory |
1. Missing library. 2. Typo in include statement. |
Open Library Manager (Ctrl+Shift+I), search for DHT sensor library by Adafruit, and install it. Also install the required Adafruit Unified Sensor dependency. |
no matching function for call to 'DHT::DHT(int)' |
1. Outdated library version. 2. Incorrect object initialization. |
The modern Adafruit library requires the sensor type as the second argument. Ensure your code reads DHT dht(DHTPIN, DHTTYPE); and not just DHT dht(DHTPIN);. |
exit status 1 (accompanied by SSD1306 allocation failed in Serial) |
1. Wrong I2C address. 2. SDA/SCL swapped. |
Run the I2C Scanner sketch. If your OLED is at 0x3D instead of 0x3C, change #define SCREEN_ADDRESS 0x3C to 0x3D in the code. |
Decision Tree: Choosing the Right Conditional Structure
Not every problem requires an if / else if hysteresis loop. Use this decision path to select the exact conditional structure your specific embedded project needs.
| Hardware Scenario | Recommended Structure | Concrete Example |
|---|---|---|
| Single Threshold Trigger (e.g., Limit switch, water leak detector) |
if(No else required) |
if (digitalRead(LEAK_PIN) == HIGH) { triggerAlarm(); } |
| Binary Toggle (e.g., Manual button toggling an LED) |
if / else |
if (buttonState == PRESSED) { led = ON; } else { led = OFF; } |
| Environmental Control (e.g., Thermostat, humidifier, battery charger) |
if / else if(Default Pick) |
The hysteresis logic used in this article's code block. |
| Discrete State Machine (e.g., OLED menu navigation, RGB color modes) |
switch / case |
switch(menuState) { case 1: showTemp(); break; case 2: showHum(); break; } |
To Simplify: Remove the OLED display code and rely entirely on
Serial.print() for debugging. This reduces memory footprint and eliminates I2C library dependencies.To Extend: Add a secondary conditional block to check for critical over-temperature faults. For example, add
if (temperature > 45.0) { shutdownSystem(); } at the very top of your loop to act as a hardware-protection watchdog, independent of the normal hysteresis control.
By treating if/else not just as a software syntax rule, but as a physical control mechanism, you bridge the gap between writing code that compiles and writing code that survives on the workbench. Always define your thresholds, protect your inputs, and respect the deadband.






