The Core Decision: Choosing the Right Conditional Construct
The arduino if then else structure is the foundational decision-making tool in embedded C++. However, applying naive binary thresholds to physical hardware causes rapid relay cycling (chatter), which destroys mechanical contacts and burns out motor windings. When designing control logic, you must map your physical requirement to the correct software construct before writing a single line of code.
| Condition Type | Best Construct | Hardware Example |
|---|---|---|
| Binary threshold (True/False) | if / else | Pushbutton debounce toggle |
| Multi-tier analog ranges | if / else if / else | Temperature bands with hysteresis |
| Discrete integer states | switch / case | Menu navigation on an LCD |
| Complex multi-variable logic | State Machine (Enum + Switch) | Multi-stage battery charger |
if / else if paired with a hysteresis variable. Do not use nested if statements for analog ranges, and never use switch/case for floating-point sensor data.
Parts List and Pin Mapping for a Hysteresis Controller
This build targets the Arduino Uno R4 Minima (ABX00080). The R4 Minima operates at 5V logic but features a 32-bit RA4M1 core, meaning it processes floating-point math for our hysteresis calculations significantly faster than the legacy 8-bit ATmega328P, without requiring the dtostrf() workarounds for serial printing.
Bill of Materials
- MCU: Arduino Uno R4 Minima (ABX00080)
- Sensor: DHT22 / AM2302 (Wired module variant with onboard 10kΩ pull-up resistor)
- Actuator: Songle SRD-05VDC-SL-C 5V Relay Module (Active-LOW trigger)
- Indicators: 2x 5mm LEDs (Red for Heat, Blue for Cool) with 220Ω current-limiting resistors
- Wiring: 22 AWG solid core hookup wire
Pin Mapping Table
| Component | Module Pin | Arduino Uno R4 Pin | Notes |
|---|---|---|---|
| DHT22 Sensor | VCC | 5V | Requires 5V for stable internal regulator |
| DHT22 Sensor | GND | GND | Common ground with relay module |
| DHT22 Sensor | DATA | D2 | Module has internal 10kΩ pull-up |
| Relay Module | VCC | 5V | Powers the optocoupler and coil |
| Relay Module | GND | GND | Common ground |
| Relay Module | IN | D3 | Active-LOW (LOW = Coil Energized) |
| Red LED (Heat) | Anode (+) | D4 | Via 220Ω resistor |
| Blue LED (Cool) | Anode (+) | D5 | Via 220Ω resistor |
Compilable Code: Dual-Threshold Logic with Error Handling
The following code implements a heating controller with a ±1.5°C hysteresis band. This prevents the relay from clicking on and off rapidly if the room temperature hovers exactly at the 24.0°C setpoint. It also includes critical error handling for sensor disconnects.
#include <DHT.h>
// --- PIN DEFINITIONS ---
#define DHTPIN 2
#define DHTTYPE DHT22
#define RELAY_PIN 3
#define LED_HEAT 4
#define LED_COOL 5
// --- CONTROL PARAMETERS ---
const float TARGET_TEMP = 24.0;
const float HYSTERESIS = 1.5;
DHT dht(DHTPIN, DHTTYPE);
bool heaterState = false; // Track state to maintain hysteresis band
void setup() {
Serial.begin(115200);
// Initialize pins
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_HEAT, OUTPUT);
pinMode(LED_COOL, OUTPUT);
// CRITICAL: Songle relay modules are Active-LOW.
// HIGH = Coil de-energized (Relay OFF). Set HIGH immediately to prevent startup spikes.
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_HEAT, LOW);
digitalWrite(LED_COOL, LOW);
dht.begin();
Serial.println("DHT22 Hysteresis Controller Initialized.");
}
void loop() {
float currentTemp = dht.readTemperature();
// --- ERROR HANDLING ---
// Check if any reads failed and exit early (to try again).
if (isnan(currentTemp)) {
Serial.println("ERROR: Failed to read from DHT sensor! Check wiring.");
// Fail-safe: Turn off relay if sensor fails to prevent runaway heating
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_HEAT, LOW);
digitalWrite(LED_COOL, LOW);
delay(2000);
return;
}
// --- DECISION LOGIC (IF / ELSE IF WITH HYSTERESIS) ---
if (currentTemp < (TARGET_TEMP - HYSTERESIS)) {
// Temperature dropped below the lower threshold (22.5°C)
heaterState = true;
}
else if (currentTemp > (TARGET_TEMP + HYSTERESIS)) {
// Temperature rose above the upper threshold (25.5°C)
heaterState = false;
}
// Note: If temp is between 22.5 and 25.5, heaterState remains unchanged.
// This is the hysteresis band that prevents relay chatter.
// --- ACTUATOR CONTROL ---
if (heaterState == true) {
digitalWrite(RELAY_PIN, LOW); // Active-LOW: Energize coil
digitalWrite(LED_HEAT, HIGH);
digitalWrite(LED_COOL, LOW);
}
else {
digitalWrite(RELAY_PIN, HIGH); // Active-LOW: De-energize coil
digitalWrite(LED_HEAT, LOW);
digitalWrite(LED_COOL, HIGH);
}
// DHT22 requires ~2 seconds between reads
delay(2000);
}
Debugging: Syntax Errors and the First 3 Logic Checks
When writing conditional logic in the Arduino IDE, a single misplaced character will halt compilation. The most common syntax failure when chaining conditions is:
error: expected primary-expression before 'else'
Ranked Causes for this Syntax Error
- Stray Semicolon: You placed a semicolon immediately after the
ifcondition.
Wrong:if (temp > 30); { ... }
Fix: Remove the semicolon. The compiler sees the semicolon as the end of theifblock, making the subsequentelsean orphan. - Missing Curly Braces: You omitted
{}around a multi-lineifblock before theelse.
Fix: Always use curly braces forif/elseblocks in embedded C++, even for single-line statements, to prevent scope bleeding. - Assignment vs. Equality: You used
=instead of==inside the condition, and the compiler's strict mode flags the resulting type mismatch before hitting theelse.
Fix: Use==for comparison.
The First 3 Things to Check When the Logic Fails (Hardware Runs Wrong)
If the code compiles but the relay chatters or ignores thresholds, check these three physical/logical traps:
- Floating-Point Exactness: Never use
==to compare floats (e.g.,if (temp == 24.0)). Sensor noise means the value might be24.00001. Always use>,<, or>=with a hysteresis band. - Active-LOW Inversion: Most 5V relay modules use an optocoupler triggered by pulling the IN pin to GND. If your relay clicks on when the code says
HIGH, invert your logic or change your pin definitions. - Sensor Read Timing: The DHT22 has a maximum sampling rate of 0.5Hz. If your
loop()runs every 50ms and you calldht.readTemperature()every cycle, the library will returnNaN(Not a Number) or stale data. Enforce adelay(2000)or use amillis()timer.
Extending the Build: State Machines vs. Nested Ifs
As your project grows—perhaps adding a humidity exhaust fan, a defrost cycle, and an alarm buzzer—your arduino if then else chains will become deeply nested and impossible to debug. This is known as "spaghetti logic."






