Day 5 brings it all together: a temperature-controlled fan with LCD display, threshold settings, alarm, and serial logging.
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).
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).
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.
// 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);
}
isnan() — the DHT22 occasionally fails to respond. Return early and retry after 2 seconds. Production firmware always validates sensor data before acting on it.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.