#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// Piny TFT
#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 23
#define TFT_CLK 18
#define TFT_RST 4
#define TFT_MISO 19
// Piny przycisków
#define BTN_UP 32
#define BTN_DOWN 33
#define BTN_OK 25
// Piny LED
#define LED_RED 26
#define LED_GREEN 27
#define LED_BLUE 14
// Kolory
#define COLOR_BG 0x0000
#define COLOR_HEADER 0x001F
#define COLOR_SELECTED 0x4208
#define COLOR_FOOTER 0xFD20
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
struct MenuItem {
const char* name;
uint16_t color;
uint8_t ledPin;
bool state;
};
MenuItem menu[] = {
{"CZERWONA", ILI9341_RED, LED_RED, false},
{"ZIELONA", ILI9341_GREEN, LED_GREEN, false},
{"NIEBIESKA", ILI9341_BLUE, LED_BLUE, false}
};
const int MENU_SIZE = 3;
int selectedItem = 0;
int previousSelectedItem = -1;
// Stany przycisków
bool btnUpState = HIGH;
bool btnDownState = HIGH;
bool btnOkState = HIGH;
bool lastBtnUpState = HIGH;
bool lastBtnDownState = HIGH;
bool lastBtnOkState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50; // Krótki delay!
void setup() {
Serial.begin(115200);
// Maksymalna prędkość
tft.begin(40000000);
tft.setRotation(0);
tft.fillScreen(COLOR_BG);
// Przyciski
pinMode(BTN_UP, INPUT_PULLUP);
pinMode(BTN_DOWN, INPUT_PULLUP);
pinMode(BTN_OK, INPUT_PULLUP);
// LED
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_BLUE, LOW);
// Rysuj RAZ
drawHeader();
drawFooter();
drawFullMenu();
Serial.println("Ready - Ultra Fast Mode!");
}
void loop() {
// Czytaj przyciski
bool currentUp = digitalRead(BTN_UP);
bool currentDown = digitalRead(BTN_DOWN);
bool currentOk = digitalRead(BTN_OK);
unsigned long now = millis();
// Reaguj na ZBOCZE OPADAJĄCE (przycisk wciśnięty)
if (currentUp != lastBtnUpState || currentDown != lastBtnDownState || currentOk != lastBtnOkState) {
lastDebounceTime = now;
}
if ((now - lastDebounceTime) > debounceDelay) {
// UP
if (currentUp == LOW && btnUpState == HIGH) {
btnUpState = LOW;
handleUp();
} else if (currentUp == HIGH) {
btnUpState = HIGH;
}
// DOWN
if (currentDown == LOW && btnDownState == HIGH) {
btnDownState = LOW;
handleDown();
} else if (currentDown == HIGH) {
btnDownState = HIGH;
}
// OK
if (currentOk == LOW && btnOkState == HIGH) {
btnOkState = LOW;
handleOk();
} else if (currentOk == HIGH) {
btnOkState = HIGH;
}
}
lastBtnUpState = currentUp;
lastBtnDownState = currentDown;
lastBtnOkState = currentOk;
}
void handleUp() {
previousSelectedItem = selectedItem;
selectedItem--;
if (selectedItem < 0) selectedItem = MENU_SIZE - 1;
fastUpdate();
}
void handleDown() {
previousSelectedItem = selectedItem;
selectedItem++;
if (selectedItem >= MENU_SIZE) selectedItem = 0;
fastUpdate();
}
void handleOk() {
menu[selectedItem].state = !menu[selectedItem].state;
digitalWrite(menu[selectedItem].ledPin, menu[selectedItem].state ? HIGH : LOW);
updateStatusOnly(selectedItem);
}
void drawHeader() {
tft.fillRect(0, 0, 240, 50, COLOR_HEADER);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(3);
tft.setCursor(35, 15);
tft.print("MENU LED");
}
void drawFooter() {
tft.fillRect(0, 290, 240, 30, COLOR_FOOTER);
tft.setTextColor(ILI9341_BLACK);
tft.setTextSize(1);
tft.setCursor(10, 302);
tft.print("UP/DOWN-wybor OK-zmien");
}
void drawFullMenu() {
for (int i = 0; i < MENU_SIZE; i++) {
drawItem(i);
}
}
void drawItem(int index) {
int y = 60 + (index * 80);
bool selected = (index == selectedItem);
uint16_t bg = selected ? COLOR_SELECTED : COLOR_BG;
// Batch write dla maksymalnej szybkości
tft.startWrite();
tft.writeFillRect(5, y, 230, 70, bg);
tft.endWrite();
if (selected) {
tft.drawRect(5, y, 230, 70, ILI9341_WHITE);
}
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE, bg);
tft.setCursor(15, y + 10);
tft.print(menu[index].name);
tft.setTextColor(menu[index].color, bg);
tft.setCursor(15, y + 35);
tft.print(menu[index].state ? "[ ON ]" : "[ OFF ]");
uint16_t indColor = menu[index].state ? menu[index].color : ILI9341_DARKGREY;
tft.fillRect(190, y + 15, 35, 35, indColor);
tft.drawRect(190, y + 15, 35, 35, ILI9341_WHITE);
}
// SUPER SZYBKIE ODŚWIEŻANIE
void fastUpdate() {
// Odśwież tylko poprzedni i obecny
if (previousSelectedItem >= 0) {
drawItem(previousSelectedItem);
}
drawItem(selectedItem);
}
void updateStatusOnly(int index) {
int y = 60 + (index * 80);
uint16_t bg = (index == selectedItem) ? COLOR_SELECTED : COLOR_BG;
// Tylko status
tft.setTextSize(2);
tft.setTextColor(menu[index].color, bg);
tft.setCursor(15, y + 35);
tft.print(menu[index].state ? "[ ON ]" : "[ OFF ]");
// Tylko wskaźnik
uint16_t indColor = menu[index].state ? menu[index].color : ILI9341_DARKGREY;
tft.fillRect(190, y + 15, 35, 35, indColor);
tft.drawRect(190, y + 15, 35, 35, ILI9341_WHITE);
}