// МЕНЮ С ВЕРТИКАЛЬНЫМ СКРОЛЛИНГОМ
#include <GyverOLED.h> // Библиотека дисплея
GyverOLED<SSD1306_128x64, OLED_BUFFER> oled(0x3C); // Обьект дисплея
//GyverOLED<SSD1306_128x64, OLED_BUFFER> oled(0x3D); // Для Proteus
#include <GyverButton.h> // Библиотека кнопок
GButton up(4, HIGH_PULL); // Кнопка Вверх
GButton ok(3, HIGH_PULL); // Кнопка ОК
GButton down(2, HIGH_PULL); // Кнопка Вниз
#define ITEMS 12 // Общее количество пунктов
// Картинка Стрелка 10х8
const uint8_t ptr_bmp[] PROGMEM = {0x3C,0x3C,0x3C,0x3C,0x3C,0xFF,0xFF,0x7E,0x3C,0x18};
// Массивы строк с именами пунктов
const char i0[] PROGMEM = " Пункт 0:";
const char i1[] PROGMEM = " Пункт 1:";
const char i2[] PROGMEM = " Пункт 2:";
const char i3[] PROGMEM = " Пункт 3:";
const char i4[] PROGMEM = " Пункт 4:";
const char i5[] PROGMEM = " Пункт 5:";
const char i6[] PROGMEM = " Пункт 6:";
const char i7[] PROGMEM = " Пункт 7:";
const char i8[] PROGMEM = " Пункт 8:";
const char i9[] PROGMEM = " Пункт 9:";
const char i10[] PROGMEM = " Пункт 10:";
const char i11[] PROGMEM = " Пункт 11:";
// Массив ссылок, обращение к пунктам по их номеру
const char* const names[] PROGMEM =
{ i0, i1, i2, i3,
i4, i5, i6, i7,
i8, i9, i10, i11 };
void setup() {
oled.init(); // Инциализация дисплея
oled.setContrast(255); // Контрастность дисплея
}
void loop() {
static int8_t pointer = 0; // Переменная указатель
// Опрос кнопок
up.tick(); down.tick(); ok.tick();
// Обработка кнопки Вверх
if (up.isClick() or up.isHold()) { // Если кнопка нажата или удержана
pointer = constrain(pointer - 1, 0, ITEMS - 1); // Двигаем указатель в пределах дисплея
}
// Обработка кнопки Вниз
if (down.isClick() or down.isHold()) { // Если кнопка нажата или удержана
pointer = constrain(pointer + 1, 0, ITEMS - 1); // Двигаем указатель в пределах дисплея
}
// Обработка кнопки ОК
if (ok.isClick()) { // Нажатие на ОК - переход в пункт меню
switch (pointer) { // По номеру указателей располагаем вложенные функции (или меню)
case 0: func0(); break; // При наведении на пункт 0 и нажатии ОК - вызвать функцию 0
case 1: func1(); break; // При наведении на пункт 1 и нажатии ОК - вызвать функцию 1
case 2: func2(); break; // При наведении на пункт 2 и нажатии ОК - вызвать функцию 2
case 3: func3(); break; // При наведении на пункт 3 и нажатии ОК - вызвать функцию 3
case 4: func4(); break; // При наведении на пункт 4 и нажатии ОК - вызвать функцию 4
case 5: func5(); break; // При наведении на пункт 5 и нажатии ОК - вызвать функцию 5
case 6: func6(); break; // При наведении на пункт 6 и нажатии ОК - вызвать функцию 6
case 7: func7(); break; // При наведении на пункт 7 и нажатии ОК - вызвать функцию 7
case 8: func8(); break; // При наведении на пункт 8 и нажатии ОК - вызвать функцию 8
case 9: func9(); break; // При наведении на пункт 9 и нажатии ОК - вызвать функцию 9
case 10: func10(); break; // При наведении на пункт 10 и нажатии ОК - вызвать функцию 10
case 11: func11(); break; // При наведении на пункт 11 и нажатии ОК - вызвать функцию 11
}
}
// Отображение Меню
oled.clear(); // Очищаем буфер
oled.home(); // Курсор в левый верхний угол
for (uint8_t i = 0; i < 8; i++) { // Цикл, выводящий 8 пунктов на дисплей
printMenuItem(pointer > 7 ? i + (pointer - 7) : i); // Выводим пункты
} // Если указатель > 7, то сдвигаем список
printPointer(constrain(pointer, 0, 7)); // Вывод указателя, в пределах 0-7
oled.update(); // Выводим кадр на дисплей
}
void printPointer(uint8_t pointer) {
// Указатель в начале строки
/*oled.setCursor(0, pointer);
oled.print(">");*/
// Можно еще в конце
/*oled.setCursor(120, pointer);
oled.print("<");*/
// Указатель в виде подчеркивающей линии
/*oled.line(0, (pointer * 8) + 7, 127, (pointer * 8) + 7, true);*/
// Указатель в виде картинки Стрелочки
oled.drawBitmap(0, pointer * 8, ptr_bmp, 10, 8);
}
// Функция, вызываемая при выборе пункта 0
void func0(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 0"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 1
void func1(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 1"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 2
void func2(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 2"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 3
void func3(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 3"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 4
void func4(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 4"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 5
void func5(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 5"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 6
void func6(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 6"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 7
void func7(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 7"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 8
void func8(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 8"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 9
void func9(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 9"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 10
void func10(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 10"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция, вызываемая при выборе пункта 11
void func11(void) {
oled.clear(); oled.home();
oled.println("Выбран Пункт 11"); oled.println("");
oled.println("Для возврата"); oled.print("нажмите ОК");
oled.update();
while (1) {
ok.tick(); if (ok.isClick()) return; // Возврат в предыдущее меню
}
}
// Функция для печати строки из prm
void printMenuItem(uint8_t num) {
char buffer[21]; // Буфер на полную строку
uint16_t ptr = pgm_read_word(&(names[num])); // Получаем указатель на первый символ строки
uint8_t i = 0; // Переменная - счетчик
do { // Начало цикла
buffer[i] = (char)(pgm_read_byte(ptr++)); // В буфер один символ из PGM и подвинуть стрелку на 1
} while (buffer[i++] != NULL); // Если это не конец строки - вернуться в начало цикла
oled.println(buffer); // Вывод готовой строки с переносом на следующую
}