В этом уроке мы создадим расширенное меню с поддержкой подменю (например, в разделе «Настройки»).
Такой подход помогает новичкам освоить структуры данных, вложенные условия и переходы между состояниями.
VCC → 5VGND → GNDSDA → A4SCL → A5VRx → A0VRy → A1SW → D2+5V → 5VGND → GND
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define JOY_X A0
#define JOY_Y A1
#define JOY_SW 2
int joyX, joyY;
bool joyBtn;
const int DEADZONE = 200;
unsigned long lastMove = 0;
const int debounceDelay = 200;
// Главное меню
const char* mainMenu[] = {"Start", "Settings", "Info", "Exit"};
int mainSize = sizeof(mainMenu) / sizeof(mainMenu[0]);
// Подменю «Настройки»
const char* settingsMenu[] = {"Bright", "Contrast", "Back"};
int settingsSize = sizeof(settingsMenu) / sizeof(settingsMenu[0]);
int selected = 0; // текущий выбор
int currentMenu = 0; // 0 = главное меню, 1 = настройки
void setup() {
pinMode(JOY_SW, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
for (;;);
}
display.clearDisplay();
display.display();
}
void loop() {
joyX = analogRead(JOY_X);
joyY = analogRead(JOY_Y);
joyBtn = !digitalRead(JOY_SW);
// Работа с текущим меню
int menuSize = (currentMenu == 0) ? mainSize : settingsSize;
// Навигация
if (millis() - lastMove > debounceDelay) {
if (joyY < 512 - DEADZONE) { // вверх
selected--;
if (selected < 0) selected = menuSize - 1;
lastMove = millis();
}
if (joyY > 512 + DEADZONE) { // вниз
selected++;
if (selected >= menuSize) selected = 0;
lastMove = millis();
}
}
// Обработка выбора
if (joyBtn && millis() - lastMove > debounceDelay) {
if (currentMenu == 0) {
handleMainMenu(selected);
} else {
handleSettingsMenu(selected);
}
lastMove = millis(); // фиксируем время последнего нажатия
}
// Отрисовка
drawMenu(currentMenu == 0 ? mainMenu : settingsMenu, menuSize);
}
void drawMenu(const char* items[], int size) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
for (int i = 0; i < size; i++) {
if (i == selected) {
display.fillRect(0, i * 12, 128, 12, SSD1306_WHITE);
display.setTextColor(SSD1306_BLACK);
} else {
display.setTextColor(SSD1306_WHITE);
}
display.setCursor(5, i * 12 + 2);
display.print(items[i]);
}
display.display();
}
void handleMainMenu(int index) {
switch (index) {
case 0: showMessage("START!"); break;
case 1:
currentMenu = 1; // переходим в подменю
selected = 0;
break;
case 2: showMessage("INFO"); break;
case 3: showMessage("EXIT"); break;
}
}
void handleSettingsMenu(int index) {
switch (index) {
case 0: showMessage("BRIGHT"); break;
case 1: showMessage("CONTRAST"); break;
case 2: // Назад
currentMenu = 0;
selected = 0;
break;
}
}
void showMessage(const char* text) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.print(text);
display.display();
delay(1000);
}