Day 5 of 5
⏱ ~60 minutes
Arduino in 5 Days — Day 5

Complete Project: Temp-Controlled Fan

Day 5 brings it all together: a temperature-controlled fan with LCD display, threshold settings, alarm, and serial logging.

Project Architecture

The system: DHT22 temperature/humidity sensor → Arduino → L298N DC motor (fan speed proportional to temperature) → 16x2 LCD display (show temp, humidity, fan speed) → buzzer alarm (when temp exceeds max threshold) → potentiometer (set threshold). This uses analog input, digital I/O, PWM output, I2C communication (LCD), and a library (DHT).

I2C LCD Display

Most 16x2 LCDs come with an I2C backpack (PCF8574 chip). This reduces connections from 16 pins to 4 (VCC, GND, SDA, SCL). Install the LiquidCrystal_I2C library from Library Manager. Use i2cdetect (or an I2C scanner sketch) to find the LCD address — usually 0x27 or 0x3F. lcd.begin(16,2), lcd.setCursor(col, row), lcd.print(value).

PID-like Fan Control

A simple proportional controller: fan speed = 0 below min_temp, maximum at max_temp, linearly proportional between. Use map(temp, min_temp, max_temp, 0, 255) then constrain(speed, 0, 255). This is a P controller (proportional only). A full PID would add integral and derivative terms to eliminate steady-state error and reduce overshoot — but for a fan, proportional is usually enough.

cpp
// Temperature-controlled fan with LCD
#include <DHT.h>
#include <LiquidCrystal_I2C.h>

#define DHT_PIN  4
#define DHT_TYPE DHT22
#define ENA_PIN  9
#define IN1_PIN  7
#define IN2_PIN  8
#define BUZZER   11
#define POT_PIN  A0

DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);

const float MIN_TEMP = 20.0;  // fan starts
const float MAX_TEMP = 35.0;  // fan at 100%
float alarmThreshold;

void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.init(); lcd.backlight();
  pinMode(ENA_PIN, OUTPUT);
  pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  digitalWrite(IN1_PIN, HIGH); digitalWrite(IN2_PIN, LOW); // always forward
  lcd.print("Temp Fan Control");
  delay(1500); lcd.clear();
}

void loop() {
  // Read threshold from pot
  alarmThreshold = map(analogRead(POT_PIN), 0, 1023, 25, 45);

  // Read sensor
  float temp = dht.readTemperature();
  float hum  = dht.readHumidity();
  if (isnan(temp) || isnan(hum)) { delay(2000); return; }

  // Calculate fan speed
  int speed = constrain(map(temp*10, MIN_TEMP*10, MAX_TEMP*10, 0, 255), 0, 255);
  analogWrite(ENA_PIN, speed);

  // Alarm
  bool alarm = temp > alarmThreshold;
  digitalWrite(BUZZER, alarm ? HIGH : LOW);

  // Display
  lcd.setCursor(0, 0);
  lcd.print("T:"); lcd.print(temp,1); lcd.print("C H:"); lcd.print(hum,0); lcd.print("%  ");
  lcd.setCursor(0, 1);
  lcd.print("Fan:"); lcd.print(map(speed,0,255,0,100)); lcd.print("% A:");
  lcd.print(alarmThreshold,0); lcd.print("C  ");

  // Serial log CSV
  Serial.print(millis()); Serial.print(",");
  Serial.print(temp,1); Serial.print(",");
  Serial.print(hum,1);  Serial.print(",");
  Serial.print(speed);  Serial.print(",");
  Serial.println(alarm ? "ALARM" : "OK");

  delay(2000);
}
💡
Always check for NaN from DHT sensors with isnan() — the DHT22 occasionally fails to respond. Return early and retry after 2 seconds. Production firmware always validates sensor data before acting on it.
📝 Day 5 Exercise
Build and Extend the Fan Controller
  1. Wire all components. Upload the sketch. Verify LCD shows temperature and fan speed.
  2. Warm the sensor with your fingers. Watch fan speed increase on the LCD and Serial Monitor.
  3. Plot temperature and fan speed in Serial Plotter (Tools → Serial Plotter) — you should see the proportional relationship.
  4. Add an LED bar graph: 5 LEDs representing fan speed in 20% increments (0-20%=1 LED, 80-100%=5 LEDs).
  5. Log data to SD card: add an SD module, write CSV lines every 10 seconds for a 1-hour temperature profile.

Day 5 Summary

  • I2C LCD reduces wiring to 4 wires — find address with I2C scanner sketch (usually 0x27 or 0x3F)
  • Proportional control maps input range to output range with constrain() to clamp extremes
  • DHT sensors fail occasionally — always check isnan() and retry, never trust raw reads blindly
  • Serial CSV logging enables post-analysis in Excel, Python, or Serial Plotter
Challenge

Implement a full PID controller for the fan. The set point is a target temperature (from the potentiometer). The fan speed is the control output. Track the error (target - actual), accumulate the integral term, and calculate the derivative (error - last_error). Tune Kp, Ki, Kd coefficients until the fan reaches target temperature stably without oscillation.

Finished this lesson?