#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
/* --- 硬體腳位設定 --- */
// DHT22 設定
#define DHTPIN 15 // DHT22 連接到 GPIO 15
#define DHTTYPE DHT22 // 指定型號為 DHT22
// Relay 設定
#define RELAY_PIN 4 // Relay 連接到 GPIO 4
/* --- 物件初始化 --- */
DHT dht(DHTPIN, DHTTYPE);
// LCD 位址通常是 0x27,大小為 16行 2列
LiquidCrystal_I2C lcd(0x27, 16, 2);
/* --- 變數區 --- */
const float TEMP_THRESHOLD = 28.0; // 設定啟動風扇的溫度門檻
void setup() {
Serial.begin(115200);
// 1. 啟動 DHT 感測器
dht.begin();
// 2. 啟動 LCD
lcd.init();
lcd.backlight(); // 開啟背光
// 3. 設定 Relay 腳位為輸出模式
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // 預設先關閉風扇
// 開機畫面
lcd.setCursor(0, 0);
lcd.print("Smart Fan Sys.");
lcd.setCursor(0, 1);
lcd.print("Starting...");
delay(2000);
lcd.clear();
}
void loop() {
// --- 步驟 1: 讀取數據 ---
// 讀取溫度 (攝氏)
float t = dht.readTemperature();
// 讀取濕度 (%)
float h = dht.readHumidity();
// 檢查讀取是否失敗 (例如線沒接好)
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
lcd.setCursor(0, 0);
lcd.print("Sensor Error!");
return; // 離開這次迴圈,重試
}
// --- 步驟 2: 更新 LCD 顯示 ---
updateLCD(t, h);
// --- 步驟 3: 自動溫控邏輯 ---
if (t > TEMP_THRESHOLD) {
// 溫度太高,開風扇
digitalWrite(RELAY_PIN, HIGH);
// 在 Serial Monitor 印出狀態方便除錯
Serial.print("Temp: "); Serial.print(t);
Serial.println("C -> Fan ON (Too Hot)");
}
else {
// 溫度舒適,關風扇
digitalWrite(RELAY_PIN, LOW);
Serial.print("Temp: "); Serial.print(t);
Serial.println("C -> Fan OFF (Comfortable)");
}
// 每 2 秒更新一次,避免感測器讀取太頻繁
delay(2000);
}
// 獨立出來的 LCD 顯示函式,讓主程式更整潔
void updateLCD(float temp, float humi) {
// 第一行顯示溫度
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temp, 1); // 顯示小數點後1位
lcd.print(" C "); // 多加空格是為了蓋掉舊的字
// 第二行顯示濕度與風扇狀態
lcd.setCursor(0, 1);
lcd.print("Humi: ");
lcd.print(humi, 1);
lcd.print(" %");
// 在右下角顯示一個小小的狀態提示
lcd.setCursor(13, 1);
if (temp > TEMP_THRESHOLD) {
lcd.print("ON "); // 風扇運轉中
} else {
lcd.print("OFF"); // 風扇靜止
}
}