//Q4
#include <Arduino.h>
#include <TimerOne.h>
#include "TrafficLight.h"
#include "DualDigitDisplay595.h"
#define BUTTON_PIN 2 // 定義按鍵接腳
// 設定燈號持續時間 (秒)
const int RED_TIME = 12;
const int GREEN_TIME = 9;
const int YELLOW_TIME = 5;
int latchPin = 10;
int clockPin = 9;
int dataPin = 8;
int trafficLightDigitSelPin = 5;
int tensDigitPin = 7;
int onesDigitPin = 6;
TrafficLight trafficLight(latchPin, clockPin, dataPin, trafficLightDigitSelPin);
DualDigitDisplay595 countdownDisplay(latchPin, clockPin, dataPin, tensDigitPin, onesDigitPin);
enum LightState { RED, GREEN, YELLOW };
LightState currentState = RED;
volatile bool updateCountdown = false;
volatile bool NUM_ON = true;
volatile bool isNightMode = false;
volatile bool YellowON = true;
volatile bool updateFlag = false;
int remainingSeconds = RED_TIME;
void timerIsr() {
updateFlag = true;
static int tick = 0;
tick++;
NUM_ON = !NUM_ON; // 每次中斷交替顯示狀態(閃爍)
YellowON = !YellowON;
if (tick % 4 == 0) // 每 1 秒更新一次倒數計時
updateCountdown = true;
if (tick >= 1000) tick = 0; // 防止溢位
}
void toggleNightModeISR() {
// 軟體防抖動邏輯
static unsigned long lastDebounceTime = 0; // 靜態變數,記錄上次有效按下的時間
unsigned long currentTime = millis(); // 獲取當前時間
// 如果當前時間距離上次有效按下超過 200 毫秒 (防抖時間)
// 這個 200ms 可以根據你的按鈕特性調整,一般 50-200ms 之間
if ((currentTime - lastDebounceTime) > 200) {
isNightMode = !isNightMode; // 切換夜間模式狀態
lastDebounceTime = currentTime; // 更新上次按下時間
// 當模式切換時,立即將閃爍狀態重置為開啟,避免剛切換時顯示熄滅
NUM_ON = true;
YellowON = true;
}
}
void setup() {
trafficLight.begin();
countdownDisplay.begin();
trafficLight.showRed();
Timer1.initialize(250000); // 250ms中断
Timer1.attachInterrupt(timerIsr);
// 設定按鍵
pinMode(BUTTON_PIN, INPUT_PULLUP); // 使用內部拉高,避免浮動
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), toggleNightModeISR, FALLING); // 按下時觸發
}
void loop() {
if (isNightMode) {
// 夜間模式:黃燈閃爍、倒數關閉
if (YellowON) {
trafficLight.showYellow(); // 顯示黃燈
} else {
trafficLight.showOff(); // 關燈(可改為 showBlank())
}
countdownDisplay.showBlank(); // 不顯示倒數
} else {
// 正常模式 → 倒數顯示
switch (currentState) {
case RED: trafficLight.showRed(); break;
case GREEN: trafficLight.showGreen(); break;
case YELLOW: trafficLight.showYellow(); break;
}
if ((currentState == YELLOW) && (remainingSeconds <= 3) && (remainingSeconds > 0)) {
if (NUM_ON)
countdownDisplay.showNumber(remainingSeconds);
else
countdownDisplay.showBlank();
} else {
countdownDisplay.showNumber(remainingSeconds);
}
}
if (updateCountdown) {
updateCountdown = false;
if (updateFlag) {
updateFlag = false; }
if (remainingSeconds > 1) {
remainingSeconds--;
} else {
switch (currentState) {
case RED:
currentState = GREEN;
remainingSeconds = GREEN_TIME;
break;
case GREEN:
currentState = YELLOW;
remainingSeconds = YELLOW_TIME;
break;
case YELLOW:
currentState = RED;
remainingSeconds = RED_TIME;
break;
}
}
}
}