Меню на Ардуино LCD 1602 с энкодером
Примеры меню с модулем энкодера и жк дисплеем, размещенные на этой странице, вы сможете адаптировать под свои нужды. Во многих проектах на Ардуино требуется для пользователя создать возможность для настройки или управления устройством на микроконтроллере. Энкодер позволяет сделать простое и нативное меню на LCD дисплее для управления светодиодами, микро серво Ардуино или для других задач.
Как сделать меню с энкодером на дисплее
Для этого проекта нам потребуется:
плата Arduino Uno / Arduino Nano / Arduino Mega;
модуль энкодера;
беспаечная макетная плата;
светодиоды и резисторы;
дисплей LCD 1602 Arduino;
провода «папа-папа», «папа-мама».
Управление энкодером меню дисплея LCD
В первом, более простом примере, в меню дисплея имеется три пункта которые можно менять с помощью вращения ручки энкодера. При нажатии на тактовую кнопку энкодера, включается выбранный цвет RGB светодиода. В зависимости от положения курсора на дисплее, при помощи условного оператора if включается нужный цвет. Соберите схему, как показано на картинке выше и загрузите следующую программу.
Code: Select all
#include "Wire.h" // библиотека для протокола I2C
#include "LiquidCrystal_I2C.h" // библиотека для дисплея
LiquidCrystal_I2C LCD(0x27, 16, 2); // присваиваем имя дисплею
#include "RotaryEncoder.h" // библиотека для энкодера
RotaryEncoder encoder(A2, A3); // пины подключение энкодера (DT, CLK)
// задаем шаг энкодера и макс./мин. значение
#define STEPS 6
#define POSMIN 0
#define POSMAX 12
int lastPos, newPos;
boolean buttonWasUp = true;
void setup() {
LCD.init(); // инициализация LCD дисплея и подсветки
LCD.backlight();
pinMode(9, OUTPUT); // пины для светодиодов
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(2, INPUT_PULLUP); // пин для кнопки энкодера
Serial.begin(9600);
encoder.setPosition(10 / STEPS);
}
void loop() {
LCD.setCursor(0, 0);
LCD.print("LED1 LED2 LED3");
// проверяем положение ручки энкодера
encoder.tick();
newPos = encoder.getPosition() * STEPS;
if (newPos < POSMIN) { encoder.setPosition(POSMIN / STEPS); newPos = POSMIN; }
else if (newPos > POSMAX) { encoder.setPosition(POSMAX / STEPS); newPos = POSMAX; }
// если положение изменилось - выводим на монитор и дисплей
if (lastPos != newPos) {
Serial.println(newPos);
LCD.setCursor(lastPos, 1);
LCD.print(" ");
LCD.setCursor(newPos, 1);
LCD.print("====");
lastPos = newPos;
}
// узнаем состояние кнопки модуля энкодера
boolean buttonIsUp = digitalRead(2);
if (buttonWasUp && !buttonIsUp) {
// исключаем дребезг контактов тактовой кнопки
delay(10);
// снова считываем сигнал с кнопки энкодера
buttonIsUp = digitalRead(2);
// если кнопка нажата, то включаем соответствующий светодиод
if (!buttonIsUp && newPos == 0) {
digitalWrite(9, HIGH); digitalWrite(10, LOW); digitalWrite(11, LOW);
}
if (!buttonIsUp && newPos == 6) {
digitalWrite(9, LOW); digitalWrite(10, HIGH); digitalWrite(11, LOW);
}
if (!buttonIsUp && newPos == 12) {
digitalWrite(9, LOW); digitalWrite(10, LOW); digitalWrite(11, HIGH);
}
}
}
Пояснения к коду:
положение курсора на LCD может принимать три значения — 0, 6 или 12;
кнопка энкодера подключена к цифровому порту при помощи конфигурации пина параметром INPUT PULLUP, что позволяет считывать нажатие кнопки.
Двухуровневое меню с энкодером Ардуино
В следующем примере меню имеет второй уровень для регулировки яркости каждого светодиода отдельно. Переход из одного меню в другое происходит при нажатии кнопки энкодера, при котором меняется значение глобальной переменной w в скетче. Схема подключения светодиодов и модулей к микроконтроллеру остается прежней, как на картинке выше, следует лишь загрузить в плату следующий код программы.
Code: Select all
#include "Wire.h" // библиотека для протокола I2C
#include "LiquidCrystal_I2C.h" // библиотека для дисплея
LiquidCrystal_I2C LCD(0x27, 16, 2); // присваиваем имя дисплею
#include "RotaryEncoder.h" // библиотека для энкодера
RotaryEncoder encoder(A2, A3); // пины подключение энкодера (DT, CLK)
// задаем шаг энкодера и макс./мин. значение в главном меню
#define STEPS 6
#define POSMIN 0
#define POSMAX 12
// задаем шаг энкодера и макс./мин. значение в подменю
#define STEPS_2 10
#define POSMIN_2 0
#define POSMAX_2 250
int lastPos, newPos;
boolean buttonWasUp = true;
byte w = 2;
void setup() {
LCD.init(); // инициализация LCD дисплея и подсветки
LCD.backlight();
pinMode(9, OUTPUT); // пины для светодиодов
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(2, INPUT_PULLUP); // пин для кнопки энкодера
Serial.begin(9600);
encoder.setPosition(10 / STEPS);
}
void loop() {
// ЦИКЛ С ГЛАВНЫМ МЕНЮ НА ДИСПЛЕЕ
while (w == 0) {
LCD.setCursor(0, 0);
LCD.print("LED1 LED2 LED3");
// проверяем положение ручки энкодера
encoder.tick();
newPos = encoder.getPosition() * STEPS;
if (newPos < POSMIN) {
encoder.setPosition(POSMIN / STEPS);
newPos = POSMIN;
}
else if (newPos > POSMAX) {
encoder.setPosition(POSMAX / STEPS);
newPos = POSMAX;
}
// если положение изменилось - выводим на монитор и дисплей
if (lastPos != newPos) {
Serial.println(newPos);
LCD.setCursor(lastPos, 1);
LCD.print(" ");
LCD.setCursor(newPos, 1);
LCD.print("====");
lastPos = newPos;
}
// если кнопка нажата, то переходим в цикл с вложенным меню
// перед входом в подменю очищаем дисплей и делаем задержку
boolean buttonIsUp = digitalRead(2);
if (buttonWasUp && !buttonIsUp) {
delay(10);
buttonIsUp = digitalRead(2);
if (!buttonIsUp && newPos == 0) { LCD.clear(); delay(500); w = 1; }
if (!buttonIsUp && newPos == 6) { LCD.clear(); delay(500); w = 2; }
if (!buttonIsUp && newPos == 12) { LCD.clear(); delay(500); w = 3; }
}
}
// ВЛОЖЕННОЕ МЕНЮ-1 С ПЕРВЫМ СВЕТОДИОДОМ
while (w == 1) {
LCD.setCursor(0, 0);
LCD.print("LED1 - ");
// проверяем положение ручки энкодера
encoder.tick();
newPos = encoder.getPosition() * STEPS_2;
if (newPos < POSMIN_2) {
encoder.setPosition(POSMIN_2 / STEPS_2);
newPos = POSMIN_2;
}
else if (newPos > POSMAX_2) {
encoder.setPosition(POSMAX_2 / STEPS_2);
newPos = POSMAX_2;
}
// если положение изменилось - меняем яркость светодиода
if (lastPos != newPos) {
LCD.setCursor(7, 0);
LCD.print(newPos);
analogWrite(9, newPos);
}
// если кнопка энкодера была нажата, то выходим в главное меню
// перед входом очищаем дисплей и выключаем светодиод
boolean buttonIsUp = digitalRead(2);
if (buttonWasUp && !buttonIsUp) {
delay(10);
buttonIsUp = digitalRead(2);
if (!buttonIsUp) { LCD.clear(); digitalWrite(9, LOW); delay(500); w = 0; }
}
}
// ВЛОЖЕННОЕ МЕНЮ-2 СО ВТОРЫМ СВЕТОДИОДОМ
while (w == 2) {
LCD.setCursor(0, 0);
LCD.print("LED2 - ");
// проверяем положение ручки энкодера
encoder.tick();
newPos = encoder.getPosition() * STEPS_2;
if (newPos < POSMIN_2) {
encoder.setPosition(POSMIN_2 / STEPS_2);
newPos = POSMIN_2;
}
else if (newPos > POSMAX_2) {
encoder.setPosition(POSMAX_2 / STEPS_2);
newPos = POSMAX_2;
}
// если положение изменилось - меняем яркость светодиода
if (lastPos != newPos) {
LCD.setCursor(7, 0);
LCD.print(newPos);
analogWrite(10, newPos);
}
// если кнопка энкодера была нажата, то выходим в главное меню
// перед входом очищаем дисплей и выключаем светодиод
boolean buttonIsUp = digitalRead(2);
if (buttonWasUp && !buttonIsUp) {
delay(10);
buttonIsUp = digitalRead(2);
if (!buttonIsUp) { LCD.clear(); digitalWrite(10, LOW); delay(500); w = 0; }
}
}
// ВЛОЖЕННОЕ МЕНЮ-3 С ТРЕТЬИМ СВЕТОДИОДОМ
while (w == 3) {
LCD.setCursor(0, 0);
LCD.print("LED3 - ");
// проверяем положение ручки энкодера
encoder.tick();
newPos = encoder.getPosition() * STEPS_2;
if (newPos < POSMIN_2) {
encoder.setPosition(POSMIN_2 / STEPS_2);
newPos = POSMIN_2;
}
else if (newPos > POSMAX_2) {
encoder.setPosition(POSMAX_2 / STEPS_2);
newPos = POSMAX_2;
}
// если положение изменилось - меняем яркость светодиода
if (lastPos != newPos) {
LCD.setCursor(7, 0);
LCD.print(newPos);
analogWrite(11, newPos);
}
// если кнопка энкодера была нажата, то выходим в главное меню
// перед входом очищаем дисплей и выключаем светодиод
boolean buttonIsUp = digitalRead(2);
if (buttonWasUp && !buttonIsUp) {
delay(10);
buttonIsUp = digitalRead(2);
if (!buttonIsUp) { LCD.clear(); digitalWrite(11, LOW); delay(500); w = 0; }
}
}
}
Пояснения к коду:
для каждого раздела меню используется цикл while, так как изначально глобальная переменная w=0;, то выполняется цикл while (w == 0);
если вы не хотите, чтобы светодиоды выключались при выходе в главное меню — удалите команду digitalWrite() во всех циклах вложенных меню.
Лично мне не понравилась работа энкодера по данной статье