#include <Arduino.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include <Adafruit_ILI9341.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "GyverEncoder.h"
#include "time.h"
#define TFT_DC 2
#define TFT_CS 15
#define Encoder_CLK 14
#define Encoder_DT 12
#define Encoder_SW 13
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
Encoder encoder(Encoder_CLK, Encoder_DT, Encoder_SW); // для работы c кнопкой
// Глобальна змінна для вибраного пункту меню
volatile int selectedMenuItem = 0;
volatile boolean inMenu = false;
volatile int valueEncoder = 0;
// Масив для основного меню
String mainMenu[] = {"Menu Item 1", "Menu Item 2", "Menu Item 3", "Menu Item 4", "Menu Item 5"};
// Масиви для підменю
String submenu1[] = {"Submenu 1.1", "Submenu 1.2", "Back"};
String submenu2[] = {"Submenu 2.1", "Submenu 2.2", "Submenu 2.3", "Back"};
String submenu3[] = {"Submenu 3.1", "Submenu 3.2", "Back"};
String submenu4[] = {"Submenu 4.1", "Back"};
String submenu5[] = {"Submenu 5.1", "Back"};
String* submenus[] = {submenu1, submenu2, submenu3, submenu4, submenu5};
// Функція відображення часу з моменту включення
void displayTime() {
unsigned long currentTime = millis();
unsigned long seconds = currentTime / 1000;
unsigned long minutes = seconds / 60;
unsigned long hours = minutes / 60;
// tft.fillScreen(ILI9341_BLACK);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 0);
tft.print(hours % 24); // Виводимо години в форматі 24 години
tft.print(":");
if ((minutes % 60) < 10) tft.print("0");
tft.print(minutes % 60);
tft.print(":");
if ((seconds % 60) < 10) tft.print("0");
tft.println(seconds % 60);
}
// Функція відображення головного меню
void displayMainMenu() {
// tft.fillScreen(ILI9341_BLACK);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
for (int i = 0; i < sizeof(mainMenu) / sizeof(mainMenu[0]); i++) {
tft.setCursor(2, i * 20 + 20);
tft.println(mainMenu[i]);
}
}
// Функція відображення підменю
void displaySubmenu(int menuIndex) {
// tft.fillScreen(ILI9341_BLACK);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
for (int i = 0; i < sizeof(submenus[menuIndex]) / sizeof(submenus[menuIndex][0]); i++) {
tft.setCursor(2, i * 20 + 20);
tft.println(submenus[menuIndex][i]);
}
}
// Функція відображення меню
void displayMenu(int menuIndex) {
if (menuIndex == -1) {
displayMainMenu();
} else {
displaySubmenu(menuIndex);
}
}
void encoderTick(void *pvParameters) {
(void) pvParameters;
for (;;) {
// обязательная функция отработки. Должна постоянно опрашиваться
encoder.tick();
if (encoder.isRight()) valueEncoder++; // если был поворот направо, увеличиваем на 1
if (encoder.isLeft()) valueEncoder--; // если был поворот налево, уменьшаем на 1
if (encoder.isRightH()) valueEncoder += 5; // если было удержание + поворот направо, увеличиваем на 5
if (encoder.isLeftH()) valueEncoder -= 5; // если было удержание + поворот налево, уменьшаем на 5
if (encoder.isFastR()) valueEncoder += 10; // если был быстрый поворот направо, увеличиваем на 10
if (encoder.isFastL()) valueEncoder -= 10; // если был быстрый поворот налево, уменьшаем на 10
if (encoder.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
Serial.println(valueEncoder); // выводим значение при повороте
}
//vTaskDelay(pdMS_TO_TICKS(1));
}
}
// Задача для обробки енкодера та кнопки
void encoderTask(void *pvParameters) {
(void) pvParameters;
boolean pressed = false;
unsigned long previousTime = millis(); // Зберігаємо час останнього оновлення
for (;;) {
// обязательная функция отработки. Должна постоянно опрашиваться
// encoder.tick();
if (!inMenu) {
unsigned long currentTime = millis();
if (currentTime - previousTime >= 200) { // Оновлюємо кожну секунду
displayTime();
previousTime = currentTime;
}
}
if (encoder.isPress()){
pressed = true;
inMenu = true;
tft.setCursor(204, 40);
tft.println("pr=true");
displayMainMenu();
}
// else if (pressed) {
// if (!inMenu) {
// inMenu = true;
// displayMenu(selectedMenuItem);
// } else {
// if (selectedMenuItem == -1) {
// inMenu = false;
// displayMainMenu();
// } else {
// if (encoder.isRight()) {
// selectedMenuItem ++;
// }
// if (encoder.isLeft()){
// selectedMenuItem --;
// }
// displayMenu(selectedMenuItem);
// }
// }
// }
if (encoder.isPress()){
tft.setCursor(124, 20);
tft.println("isPress");
}
if (encoder.isClick()){
tft.setCursor(124, 40);
tft.println("isClick");
}
if (encoder.isTurn()){
tft.setCursor(124, 60);
tft.println("isTurn");
}
if (encoder.isRight()){
tft.setCursor(124, 80);
tft.println("isRight");
}
if (encoder.isLeft()){
tft.setCursor(124, 100);
tft.println("isLeft");
}
if (encoder.isHolded()){
tft.setCursor(124, 100);
tft.println("isHolded");
}
vTaskDelay(pdMS_TO_TICKS(30));
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
tft.begin();
tft.setRotation(3);
// Початкове відображення годин
displayTime();
xTaskCreatePinnedToCore(
encoderTask, // Функція, яка виконується в задачі
"EncoderTask", // Ім'я задачі
4096, // Розмір стеку задачі (в словах)
NULL, // Параметри задачі
3, // Пріоритет задачі
NULL, // Дескриптор задачі
1 // Ядро, на якому буде виконуватися задача (0 або 1)
);
xTaskCreatePinnedToCore(
encoderTick, // Функція, яка виконується в задачі
"encoderTick", // Ім'я задачі
4096, // Розмір стеку задачі (в словах)
NULL, // Параметри задачі
3, // Пріоритет задачі
NULL, // Дескриптор задачі
1 // Ядро, на якому буде виконуватися задача (0 або 1)
);
}
void loop() {
// Порожній цикл, бо всі задачі виконуються в RTOS
}
/**
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
// enc1.setType(TYPE2);
tft.begin();
tft.setCursor(20, 120);
tft.setTextColor(ILI9341_RED);
tft.setTextSize(3);
tft.println("Hello ESP32");
tft.setCursor(24, 160);
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(2);
tft.println("I can do SPI :-)");
tft.setCursor(0, 0);
}
void loop() {
// put your main code here, to run repeatedly:
// обязательная функция отработки. Должна постоянно опрашиваться
enc1.tick();
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
// ваш код
Serial.println("isTurn");
tft.println("isTurn");
}
if (enc1.isRight()) {
Serial.println("Right"); // если был поворот
tft.println("Right");
}
if (enc1.isLeft()){
Serial.println("Left");
tft.println("Left");
}
if (enc1.isRightH()) {
Serial.println("Right holded"); // если было удержание + поворот
tft.println("Right holded");
}
if (enc1.isLeftH()){
Serial.println("Left holded");
tft.println("Left holded");
}
if (enc1.isPress()){
Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
tft.println("Press");
}
if (enc1.isClick()){
Serial.println("Click"); // отпускание кнопки (+ дебаунс)
tft.println("Click");
}
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
if (enc1.isHolded()){
Serial.println("Holded"); // если была удержана и энк не поворачивался
tft.println("Holded");
}
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
}
**/