#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>
// OLED 設定
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// NeoPixel 設定
#define LED_PIN 6
#define NUM_PIXELS 8
Adafruit_NeoPixel strip(NUM_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
// 按鈕定義
#define BT_UP 3
#define BT_DOWN 5
#define BT_OK 10
#define BT_BACK 11
// 選單內容(4 項)
const int menuSize = 4;
const char* menuItems[menuSize] = {
"Red Breathing",
"Purple Runner",
"Random Blink",
"Step Lights"
};
int menuIndex = 0;
bool inSubMenu = false;
int stepIndex = 0;
// 防彈跳
unsigned long lastDebounce = 0;
const unsigned long debounceDelay = 150;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(20, 20);
display.println("RGB Menu System");
display.setCursor(35, 35);
display.println("by Student");
display.display();
delay(3000);
pinMode(BT_UP, INPUT_PULLUP);
pinMode(BT_DOWN, INPUT_PULLUP);
pinMode(BT_OK, INPUT_PULLUP);
pinMode(BT_BACK, INPUT_PULLUP);
strip.begin();
strip.show();
}
void loop() {
if (!inSubMenu) {
drawMenu();
handleMenuInput();
} else {
handleSubMenu(menuIndex);
}
}
// 顯示選單介面
void drawMenu() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(40, 0);
display.println("MENU");
display.drawLine(0, 10, 127, 10, WHITE);
for (int i = 0; i < menuSize; i++) {
display.setCursor(0, 12 + i * 12);
if (i == menuIndex) {
display.print("> ");
} else {
display.print(" ");
}
display.println(menuItems[i]);
}
display.display();
}
// 處理選單按鈕輸入
void handleMenuInput() {
if (millis() - lastDebounce > debounceDelay) {
if (digitalRead(BT_UP) == LOW) {
menuIndex = (menuIndex - 1 + menuSize) % menuSize;
lastDebounce = millis();
}
if (digitalRead(BT_DOWN) == LOW) {
menuIndex = (menuIndex + 1) % menuSize;
lastDebounce = millis();
}
if (digitalRead(BT_OK) == LOW) {
inSubMenu = true;
strip.clear(); strip.show();
lastDebounce = millis();
}
}
}
// 處理各子選單功能
void handleSubMenu(int index) {
if (digitalRead(BT_BACK) == LOW && millis() - lastDebounce > debounceDelay) {
inSubMenu = false;
strip.clear(); strip.show();
lastDebounce = millis();
return;
}
switch (index) {
case 0: redBreathing(); break;
case 1: purpleRunner(); break;
case 2: randomBlink(); break;
case 3: stepLighting(); break;
}
}
// 模式 1:紅色呼吸燈
void redBreathing() {
static int brightness = 0;
static int fadeAmount = 5;
for (int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, strip.Color(brightness, 0, 0));
}
strip.show();
brightness += fadeAmount;
if (brightness <= 0 || brightness >= 255) fadeAmount = -fadeAmount;
delay(30);
}
// 模式 2:紫色跑馬燈
void purpleRunner() {
static int position = 0;
strip.clear();
for (int i = 0; i < 3; i++) {
int pixel = (position - i + NUM_PIXELS) % NUM_PIXELS;
int brightness = 255 - i * 80;
strip.setPixelColor(pixel, strip.Color(brightness, 0, brightness)); // 紫色
}
strip.show();
position = (position + 1) % NUM_PIXELS;
delay(100);
}
// 模式 3:隨機閃爍
void randomBlink() {
int i = random(NUM_PIXELS);
strip.setPixelColor(i, strip.Color(random(255), random(255), random(255)));
strip.show();
delay(100);
strip.setPixelColor(i, 0);
strip.show();
}
// 模式 4:段數點亮
void stepLighting() {
if (digitalRead(BT_OK) == LOW && millis() - lastDebounce > debounceDelay) {
if (stepIndex < NUM_PIXELS) {
strip.setPixelColor(stepIndex, strip.Color(0, 0, 255));
strip.show();
stepIndex++;
} else {
stepIndex = 0;
strip.clear(); strip.show();
}
lastDebounce = millis();
}
}