#include <Wire.h>
// PCF8575 的 I2C 位址,通常是 0x20(取決於 A0、A1、A2 的接線)
#define PCF8575_ADDRESS 0x20
// 用來儲存目前 GPIO 的狀態(16 位元,表示 16 個引腳)
unsigned int gpioState = 0x0000; // 初始化為全部 HIGH (未啟動)
const int segmentPins[8] = {4, 15, 19, 18, 5, 16, 17, 23};
const int digitPins[2] = {32, 33};
const int segmentCodes[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
const int buttonPin1 = 35; // 按鈕1接到的GPIO腳位
const int buttonPin2 = 34; // 按鈕2接到的GPIO腳位
const int buttonPin3 = 39; // 按鈕3接到的GPIO腳位
const int buttonPin4 = 36; // 按鈕4接到的GPIO腳位
unsigned long previousMillis = 0;
const int interval[4] = {50, 70, 100, 150};
int intervalIndex = 0;
int ledIndex = 0;
int circleCount = 0;
int classSize = 35; // 預設班級人數為35人
int randomNumber = classSize;
bool direction = true; // 新增方向變數
bool buttonPressed = false; // 新增按鈕觸發變數
bool settingMode = false; // 新增設定模式變數
unsigned long pauseStart = 0;
bool isPausing = false;
// 防彈跳變數
unsigned long lastDebounceTime1 = 0;
unsigned long lastDebounceTime2 = 0;
unsigned long lastDebounceTime3 = 0;
unsigned long lastDebounceTime4 = 0;
int buttonState1 = HIGH;
int buttonState2 = HIGH;
int buttonState3 = HIGH;
int buttonState4 = HIGH;
int lastButtonState1 = HIGH;
int lastButtonState2 = HIGH;
int lastButtonState3 = HIGH;
int lastButtonState4 = HIGH;
void setup(void)
{
Wire.begin(); // 啟動 I2C 通訊
for (int i = 0; i < 8; i++) {
pinMode(segmentPins[i], OUTPUT);
digitalWrite(segmentPins[i], HIGH);
}
for (int i = 0; i < 2; i++) {
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], LOW);
}
pinMode(buttonPin1, INPUT_PULLUP); // 設定按鈕1腳位為輸入模式,並啟用內部上拉電阻
pinMode(buttonPin2, INPUT_PULLUP); // 設定按鈕2腳位為輸入模式,並啟用內部上拉電阻
pinMode(buttonPin3, INPUT_PULLUP); // 設定按鈕3腳位為輸入模式,並啟用內部上拉電阻
pinMode(buttonPin4, INPUT_PULLUP); // 設定按鈕4腳位為輸入模式,並啟用內部上拉電阻
Serial.begin(9600);
randomSeed(analogRead(0));
}
void loop(void)
{
int reading1 = digitalRead(buttonPin1);
if (reading1 != lastButtonState1) {
lastDebounceTime1 = millis();
}
if ((millis() - lastDebounceTime1) > 50) {
if (reading1 != buttonState1) {
buttonState1 = reading1;
if (buttonState1 == LOW) {
buttonPressed = true;
}
}
}
lastButtonState1 = reading1;
int reading2 = digitalRead(buttonPin2);
if (reading2 != lastButtonState2) {
lastDebounceTime2 = millis();
}
if ((millis() - lastDebounceTime2) > 50) {
if (reading2 != buttonState2) {
buttonState2 = reading2;
if (buttonState2 == LOW) {
classSize++; // 人數增加
}
}
}
lastButtonState2 = reading2;
int reading3 = digitalRead(buttonPin3);
if (reading3 != lastButtonState3) {
lastDebounceTime3 = millis();
}
if ((millis() - lastDebounceTime3) > 50) {
if (reading3 != buttonState3) {
buttonState3 = reading3;
if (buttonState3 == LOW) {
classSize--; // 人數減少
}
}
}
lastButtonState3 = reading3;
int reading4 = digitalRead(buttonPin4);
if (reading4 != lastButtonState4) {
lastDebounceTime4 = millis();
}
if ((millis() - lastDebounceTime4) > 50) {
if (reading4 != buttonState4) {
buttonState4 = reading4;
if (buttonState4 == LOW) {
settingMode = !settingMode; // 切換設定模式
}
}
}
lastButtonState4 = reading4;
if (settingMode) {
randomNumber = classSize; // 更新顯示的數字
} else {
if (buttonPressed) {
updateLEDandRandomNumber();
}
}
displayNumber(randomNumber); // 持續更新顯示器
}
#define BUZZER_PIN 12
void updateLEDandRandomNumber() {
unsigned long currentMillis = millis();
static int targetLedIndex = 0;
if (!isPausing && currentMillis - previousMillis >= interval[intervalIndex]) {
previousMillis = currentMillis;
if (circleCount % 5 == 0) {
intervalIndex = 3; // 第五圈時,設定間隔索引為3
} else if (circleCount % 5 == 4) {
intervalIndex = 3;
} else if (circleCount % 5 == 3) {
intervalIndex = 2;
} else if (circleCount % 5 >= 1) {
intervalIndex = 1;
} else {
intervalIndex = 0;
}
PCF8575Write(ledIndex, 1); // 高態點亮
noTone(BUZZER_PIN);
if (direction) {
ledIndex = (ledIndex + 1) % 16;
} else {
ledIndex = (ledIndex - 1 + 16) % 16;
}
if (ledIndex == 0) {
circleCount++;
if (circleCount % 5 == 0) {
targetLedIndex = random(0, 15);
if (targetLedIndex == 0) {
targetLedIndex = random(1, 15);
}
}
}
if (ledIndex == targetLedIndex && circleCount % 5 == 0) {
isPausing = true;
pauseStart = currentMillis;
buttonPressed = false; // 重置按鈕觸發變數
}
PCF8575Write(ledIndex, 0); // 高態點亮
tone(BUZZER_PIN, 440, 50);
randomNumber = random(1, classSize + 1); // 產生的亂數最大值為班級人數
Serial.println(randomNumber);
} else if (isPausing && currentMillis - pauseStart >= 3000) {
isPausing = false;
if (circleCount % 5 == 0) {
direction = !direction; // 完成五圈時,切換方向
}
}
}
void displayNumber(int number) {
int digits[2] = {number % 10, number / 10};
for (int i = 0; i < 2; i++) {
digitalWrite(digitPins[i], HIGH);
for (int j = 0; j < 8; j++) {
digitalWrite(segmentPins[j], bitRead(segmentCodes[digits[i]], j));
}
delay(5);
for (int j = 0; j < 8; j++) {
digitalWrite(segmentPins[j], HIGH);
}
digitalWrite(digitPins[i], LOW);
}
}
void PCF8575Write(uint8_t pin, uint8_t state) {
if (pin < 0 || pin > 15) return; // 引腳號碼超過範圍,直接返回
if (state == HIGH) {
gpioState &= ~(1 << pin); // 將對應引腳位置為 LOW
} else {
gpioState |= (1 << pin); // 將對應引腳位置為 HIGH
}
// 將更新後的狀態寫入 PCF8575
Wire.beginTransmission(PCF8575_ADDRESS);
Wire.write(gpioState & 0xFF); // 寫入低 8 位
Wire.write((gpioState >> 8) & 0xFF); // 寫入高 8 位
Wire.endTransmission();
}