// 定義接腳
#define PIR_PIN 34 // PIR 感測器輸入腳位
#define LED_PIN 18 // 警示 LED 腳位
#define BUZZER_PIN 19 // 蜂鳴器腳位
#define CANCEL_BUTTON_PIN 25 // 取消警報的按鈕腳位
#define MAIN_SWITCH_PIN 32 // 總開關腳位(啟用/關閉整個系統)
// 系統狀態變數
bool alarmActive = false; // 是否正在警報中
bool alarmCanceled = false; // 警報是否已被使用者取消
bool lastMotionState = LOW; // 上一次 PIR 感測狀態
bool readyToDetectAgain = false; // 是否已準備好再次偵測
bool systemJustPoweredOn = false; // 剛開機時暫停警報直到 PIR 區域清空
// 時間控制變數
unsigned long lastPrintTime = 0; // 上次列印入侵訊息的時間
unsigned long lastBlinkTime = 0; // 上次蜂鳴器閃爍的時間
const unsigned long printInterval = 1000; // 每秒輸出一次入侵訊息
const unsigned long blinkInterval = 500; // 每 0.5 秒切換蜂鳴器狀態
bool buzzerState = false; // 蜂鳴器目前狀態(HIGH/LOW)
bool lastMainSwitchState = LOW; // 前一次總開關狀態
void setup() {
// 設定各腳位模式
pinMode(PIR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(CANCEL_BUTTON_PIN, INPUT_PULLUP); // 使用內部上拉電阻
pinMode(MAIN_SWITCH_PIN, INPUT);
Serial.begin(115200); // 啟動序列埠除錯訊息
}
void loop() {
// 讀取各個輸入值
int mainSwitch = digitalRead(MAIN_SWITCH_PIN);
int motionDetected = digitalRead(PIR_PIN);
int cancelButton = digitalRead(CANCEL_BUTTON_PIN);
unsigned long now = millis();
// === 偵測主開關狀態是否改變 ===
if (mainSwitch != lastMainSwitchState) {
if (mainSwitch == HIGH) {
// 主開關剛開啟
Serial.println("主開關開啟,系統啟動中...");
systemJustPoweredOn = true; // 剛開啟,暫時不偵測
alarmActive = false;
alarmCanceled = false;
buzzerState = false;
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
} else {
// 主開關剛關閉
Serial.println("主開關關閉,系統關閉");
alarmActive = false;
alarmCanceled = false;
readyToDetectAgain = false;
buzzerState = false;
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
lastMainSwitchState = mainSwitch;
delay(100); // 消除開關彈跳
return; // 結束這輪 loop
}
// === 如果主開關為關,則不執行任何功能 ===
if (mainSwitch == LOW) {
delay(50);
return;
}
// === 主開關剛開時,等待 PIR 為 LOW 才啟用偵測 ===
if (systemJustPoweredOn && motionDetected == LOW) {
Serial.println("區域清空,系統進入偵測模式");
readyToDetectAgain = true;
systemJustPoweredOn = false;
}
// === 當 PIR 從 LOW → HIGH 且系統準備好時觸發警報 ===
if (motionDetected == HIGH && lastMotionState == LOW && !alarmActive && !alarmCanceled && readyToDetectAgain) {
alarmActive = true; // 啟動警報
digitalWrite(LED_PIN, HIGH); // 開啟警示燈
lastBlinkTime = now; // 重置蜂鳴器閃爍時間
lastPrintTime = 0; // 強制馬上印出第一筆入侵訊息
readyToDetectAgain = false; // 暫停下一次偵測直到人離開
}
// === 警報狀態下的處理:蜂鳴器閃爍 + 顯示入侵訊息 ===
if (alarmActive) {
if (now - lastBlinkTime >= blinkInterval) {
buzzerState = !buzzerState; // 切換蜂鳴器狀態
digitalWrite(BUZZER_PIN, buzzerState);
lastBlinkTime = now;
}
if (now - lastPrintTime >= printInterval) {
Serial.println("偵測到入侵者!");
lastPrintTime = now;
}
}
// === 按下按鈕時,手動取消警報 ===
if (cancelButton == LOW && alarmActive) {
Serial.println("警報已取消(按鈕)");
alarmActive = false;
alarmCanceled = true;
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
buzzerState = false;
}
// === 若已取消且 PIR 偵測為 LOW,重設以便重新偵測 ===
if (motionDetected == LOW && alarmCanceled == true) {
Serial.println("區域已清空,準備重新偵測");
alarmCanceled = false;
readyToDetectAgain = true;
}
// 記錄 PIR 的上一次狀態,供下一輪使用
lastMotionState = motionDetected;
delay(50); // 降低執行頻率,避免 CPU 過度忙碌
}