#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimerOne.h>
// 定義 DHT 設置
#define DHTPIN 2
#define DHTTYPE DHT22
// 定義 LED 和按鈕
#define BUTTON_PIN 3
#define RED_LED 9
#define GREEN_LED 10
#define BLUE_LED 11
// 初始化 DHT 和 LCD
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4); // 根據 I2C 掃描結果修改地址
// 全局變數
volatile bool buttonPressed = false;
volatile unsigned long buttonPressStartTime = 0;
volatile bool isButtonHeld = false;
bool overrideMode = false; // 模式 1:強制綠燈
bool normalMode = true; // 模式 2:正常偵測
float temperature = 0.0;
float humidity = 0.0;
void setup() {
// 初始化 LED 和按鈕
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
// 設定按鈕的外部中斷
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButtonPress, CHANGE);
// 初始化 Timer1
Timer1.initialize(5000000); // 每 5 秒觸發一次
Timer1.attachInterrupt(timerISR);
// 初始化 LCD
lcd.init();
lcd.backlight();
dht.begin();
// 啟動訊息
lcd.setCursor(0, 0);
lcd.print("System Ready");
delay(2000);
lcd.clear();
}
void loop() {
// 判斷按鈕是否持續按住 5 秒
if (isButtonHeld) {
unsigned long holdTime = millis() - buttonPressStartTime;
if (holdTime >= 5000) {
isButtonHeld = false; // 重置狀態
buttonPressed = true; // 切換模式
}
}
if (buttonPressed) {
buttonPressed = false;
// 切換模式
if (overrideMode) {
overrideMode = false; // 切回正常模式
normalMode = true;
lcd.setCursor(0, 2);
lcd.print("Mode: Normal ");
} else {
overrideMode = true; // 切換到強制模式
normalMode = false;
lcd.setCursor(0, 2);
lcd.print("Mode: Override ");
}
}
}
// 按鈕外部中斷處理函數
void handleButtonPress() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
// 防抖處理
if (interruptTime - lastInterruptTime > 50) {
if (digitalRead(BUTTON_PIN) == LOW) {
// 按鈕被按下,記錄按下的起始時間
buttonPressStartTime = millis();
isButtonHeld = true;
} else {
// 按鈕鬆開
isButtonHeld = false;
}
}
lastInterruptTime = interruptTime;
}
// Timer1 中斷處理函數:每 5 秒執行一次
void timerISR() {
// 讀取溫濕度數據
temperature = dht.readTemperature();
humidity = dht.readHumidity();
// 更新 LCD 顯示
updateLCD();
// 控制 LED 狀態
if (overrideMode) {
setLED(0, 255, 0); // 強制綠燈
} else {
// 正常模式下判斷 LED 狀態
if ((temperature >= 15 && temperature <= 23) &&
(humidity >= 30 && humidity <= 55)) {
setLED(0, 255, 0); // 綠燈(正常)
} else {
setLED(255, 0, 0); // 紅燈(異常)
}
}
}
// 更新 LCD 顯示
void updateLCD() {
// 顯示當前溫濕度
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temperature, 1);
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print("Hum: ");
lcd.print(humidity, 1);
lcd.print(" % ");
// 顯示狀態
lcd.setCursor(0, 3);
if (overrideMode) {
lcd.print("Status: Override ");
} else if ((temperature >= 15 && temperature <= 23) &&
(humidity >= 30 && humidity <= 55)) {
lcd.print("Status: Normal ");
} else {
lcd.print("Status: Alert! ");
}
}
// 控制 RGB LED 的顏色
void setLED(int r, int g, int b) {
analogWrite(RED_LED, r);
analogWrite(GREEN_LED, g);
analogWrite(BLUE_LED, b);
}