Создание меню с кнопками для вашего микроконтроллера

В этом руководстве мы создаем меню с 4 кнопками и 1 ЖК-экраном для микроконтроллера Arduino, ESP8266 или ESP32 для управления запущенной программой.

Статья разделена на две части:

  1. Подключение микроконтроллера, кнопок и ЖК-дисплея для создания меню.
  2. Создайте программный сценарий для управления предопределенными переменными, такими как температура.

Идея меню возникла у меня, когда я планировал новый проект регулятора температуры для моего курильщика. Я подумал, что было бы здорово не только отображать текущую температуру нескольких датчиков температуры на ЖК-экране, но и дать мне обзор, какова выбранная целевая температура мяса. Это важно, потому что разные виды мяса имеют разные целевые температуры.

Вы можете перенести мой пример также в область умного дома. Например, у вас также может быть меню для отображения температуры и влажности для разных комнат в вашем доме, причем каждый экран на дисплее отображает статистику для одной комнаты. И если влажность превышает заранее определенный порог, который можно установить с помощью меню, вы получите сигнал тревоги на своем телефоне.

В этом руководстве мы используем меню с 4 кнопками:

Кнопка Цвет Функция
Влево Синий Показывает предыдущий экран меню
Вниз Красный Уменьшить значение для экрана меню
Вверх Зеленый Увеличить значение для экрана меню
Right Желтый Показывает следующий экран меню

На следующем рисунке показаны кнопки на макетной плате для этого руководства. В реальном проекте я бы припаял кнопки на печатной плате в форме плюса.

Соединение между кнопками и микроконтроллером для создания меню

В следующей таблице представлен обзор всех компонентов и деталей, которые я использовал для этого урока. Я получаю комиссионные за покупки, сделанные по ссылкам в этой таблице.

Компонент Amazon Link AliExpress Link
Arduino Nano Amazon AliExpress
Arduino Pro Mini Amazon AliExpress
Arduino Uno Amazon AliExpress
Arduino Mega Amazon Али Экспресс
EPS32 ESP-WROOM-32 Amazon AliExpress
ESP8266 NodeMCU Amazon AliExpress
ESP8266 WeMos D1 Mini Amazon AliExpress
Набор кнопок Amazon AliExpress
ЖК-дисплей 20×4 Amazon AliExpress
ЖК-дисплей 16×2 Amazon AliExpress

Для этого проекта я использую разные платы Arduino. Но вы можете использовать любой микроконтроллер, какой захотите, например ESP8266 или ESP32. На следующем рисунке показано соединение между платами Arduino, 4 кнопками и ЖК-экраном.

Я использую ЖК-дисплей 20 × 4 с коммуникацией L2C. Если вас также интересуют ЖК-дисплеи в целом, я рекомендую вам ознакомиться с моим руководством по ЖК-дисплеям.

Arduino Nano
Arduino Pro Mini
Arduino Uno
Arduino Mega
Arduino Nano
Меню с кнопками Arduino Nano

Для получения дополнительной информации об Arduino Nano посетите учебное пособие по Arduino Nano.

Arduino Pro Mini
Меню с кнопками Arduino Pro Mini
Arduino Uno
Меню с кнопками Arduino Uno

Дополнительную информацию об Arduino Uno см. в руководстве по Arduino Uno.

Arduino Mega
Меню с кнопками Arduino Mega

Для получения дополнительной информации об Arduino Mega посетите учебное пособие по Arduino Mega.

ЖК-дисплей подключен через интерфейс I2C к платам Arduino для связи и передачи данных между микроконтроллер и ЖК-дисплей. Мы используем вывод 5V для питания дисплея.

Четыре разные кнопки подключены к цифровому выводу платы Arduino. В моем случае я использую цифровой ввод/вывод. Выводы 5… 8. Если вы используете другие цифровые выводы, не забудьте также изменить программный код.

Я не использую резисторы для подключения к кнопкам. Вместо этого я использую внутренний подтягивающий резистор платы Arduino. Внутреннее подтягивающее напряжение следующее: если кнопка не нажата, внутренний подтягивающий резистор подключается к 5В. Поэтому Arduino сообщает HIGH. Однако, если мы нажмем кнопку, контакт Arduino будет заземлен и сообщит LOW. Мы должны помнить об этом позже, в части программирования этого руководства.

Программный сценарий для создания многоэкранного меню

Теперь давайте погрузимся в программу Arduino. Этот сценарий немного сложнее, потому что сложность заключается не в соединении между дисплеем, кнопками и микроконтроллером, а в скрипте для создания логики меню. Но не паникуйте, мы шаг за шагом проходим сценарий, и я описываю каждую мелочь.

 LiquidCrystal_I2C lcd (0x27, 16, 4); const int buttonPinLeft = 5; const int buttonPinDown = 6; const int buttonPinUp = 7; const int buttonPinRight = 8; int buttonStateLeft = 0;  int buttonStateDown = 0; int buttonStateUp = 0; int buttonStateRight = 0; const int numOfScreens = 4; int currentScreen = 0; Строковые экраны [numOfScreens] [2] = {{"Value_1", "Unit_1"}, {"Value_2"  , "Unit_2"}, {"Value_3", "Unit_3"}, {"Value_4", "Unit_4"}}; int parameters [numOfScreens] = {0, 10, 50, 100}; void setup () {Serial.  begin (9600);  lcd.init (); //инициализация ЖК-дисплея lcd.backlight (); //Включение или отключение подсветки pinMode (buttonPinLeft, INPUT_PULLUP);  pinMode (buttonPinDown, INPUT_PULLUP);  pinMode (buttonPinUp, INPUT_PULLUP);  pinMode (buttonPinRight, INPUT_PULLUP);  lcd.clear ();  lcd.setCursor (4,1);  lcd.print («ЭТО ТАКОЕ»);  lcd.setCursor (3,2);  lcd.print («Учебник по меню»);  задержка (5000);  жк. clear ();} недействительный цикл () {buttonStateLeft = digitalRead (buttonPinLeft);  buttonStateDown = digitalRead (buttonPinDown);  buttonStateUp = digitalRead (buttonPinUp);  buttonStateRight = digitalRead (buttonPinRight);  если (buttonStateLeft == LOW) {lcd.clear ();  если (currentScreen == 0) {currentScreen = numOfScreens-1;  } else {currentScreen--;  }} иначе, если (buttonStateDown == LOW) {lcd.clear ();  параметры [currentScreen] -;} иначе, если (buttonStateUp == LOW) {lcd.clear ();  параметры [currentScreen] ++;} иначе, если (buttonStateRight == LOW) {lcd.clear ();  если (currentScreen == numOfScreens-1) {currentScreen = 0;  } else {currentScreen ++;  }} Снимок экрана();  задержка (200);} void printScreen () {если (currentScreen == 3) {lcd.setCursor (0,0);  lcd.print (экраны [0] [0]);  lcd.print (":");  lcd.print (параметры [0]);  lcd.print ("");  lcd.print (экраны [0] [1]);  lcd.setCursor (0,1);  lcd.print (экраны [1] [0]);  lcd.print (":");  lcd.print (параметры [1]);  lcd.print ("");  lcd.print (скрины [1] [1]);  lcd.setCursor (0,2);  lcd.print (скрины [2] [0]);  lcd.print (":");  lcd.print (параметры [2]);  lcd.print ("");  lcd.print (скрины [2] [1]);  lcd.setCursor (0,3);  lcd.print (скрины [3] [0]);  lcd.print (":");  lcd.print (параметры [3]);  lcd.print ("");  lcd.print (скрины [3] [1]);  } еще {lcd.setCursor (0,0);  lcd.print («МЕНЮ ТОТОРИАЛ»);  lcd.setCursor (0,2);  lcd.print (экраны [currentScreen] [0]);  lcd.setCursor (0,3);  lcd.print (параметры [currentScreen]);  lcd.print ("");  lcd.print (экраны [currentScreen] [1]);  }} 

Сначала мы импортируем необходимую библиотеку для связь ЖК-дисплея I2C и создание объекта LiquidCrystal_I2C. Всего у объекта три переменные:

  • Шестнадцатеричный адрес I2C: 0x27
    В моем случае ЖК-дисплей I2C для меню подключен по шестнадцатеричному адресу 0x27. Это адрес по умолчанию для этого дисплея. Либо вы можете попробовать сценарий с тем же адресом, либо узнать шестнадцатеричный адрес I2C с помощью сканера шестнадцатеричных адресов I2C. Вы найдете сценарий и описание сканера шестнадцатеричных адресов I2C в этой статье.
  • Цифр в строке: 20 и количество строк: 4
    В моем случае я использую 20 × 4 ЖК-дисплей. Если вы используете дисплей 16 × 2, вам необходимо изменить код, потому что мы используем более двух строк дисплея.

Если вы не знаете, как установить библиотеку LiquidCrystal_I2C , вы найдете пошаговое руководство в этой статье.

Теперь мы определяем в общей сложности 4 разные переменные с номером пина, чтобы знать, на каком сигнале разные кнопки отправляют свое состояние в Arduino. Например, кнопка «вниз» подключена к контакту 6.

Переменные buttonState хранят текущее состояние кнопки. В начале скрипта кнопки имеют состояние 0. Если кнопка нажата, она получает состояние 1. В этом состоянии позже в скрипте мы узнаем, какая кнопка была нажата, и можем вызвать реакцию..

После того, как мы позаботимся о кнопках, мы перейдем к экранам . Первая переменная определяет количество экранов, которые мы хотим показать. В этом случае мы хотим создать 4 экрана. Вторая переменная определяет экран, который отображается в начале программы. Мы определяем экран 0. И вот первое препятствие, потому что теперь мы создаем двумерный массив. На каждом из 4 экранов мы хотим сохранить по 2 переменные. Две переменные — это значение и единица измерения, они могут быть температурой и градусом Кельвина. Переменная текущего экрана равна 0, потому что мы получаем доступ к первому элементу массива в Arduino с 0, а не с 1.

В следующей таблице показан двумерный массив.

0 1
numOfScreens 0 Value_1 = 0 Unit_1
1 Value_2 = 10 Unit_2
2 Value_3 = 50 Unit_3
3 Value_4 = 100 Unit_4

Последняя переменная, которую мы объявляем, представляет собой массив, в котором хранится текущее значение экрана. Поскольку всего у нас 4 экрана, мы сохраняем 4 значения, которые можно увеличивать или уменьшать.

После того, как все переменные определены, мы позаботимся о функции настройки , которая будет запускаться только один раз при запуске микроконтроллера. Сначала мы определяем скорость передачи до 9600, что означает, что мы можем видеть значения в последовательном мониторе со скоростью 9600 бит в секунду. Скорость передачи данных, определенная в функции настройки и в последовательном мониторе, должна быть синхронной.
После установки скорости передачи мы инициализируем ЖК-дисплей и включаем подсветку.
Затем мы инициализируем 4 кнопки с их контактами, и мы включаем внутренний подтягивающий резистор, так что нам не нужен дополнительный резистор для нашей схемы.

Для функции настройки мы хотим написать короткий текст на дисплеях. Сначала мы очищаем весь дисплей и устанавливаем курсор во второй строке на цифру номер 4. Здесь мы печатаем первую часть текста. Затем мы помещаем курсор в следующую строку и, поскольку вторая часть теста длиннее, мы устанавливаем курсор на трехзначное число и печатаем вторую часть текста. Текст отображается через 5 секунд, и по истечении этого времени дисплей очищается.

Теперь мы вводим всю функцию цикла , которая, конечно, обрабатывается снова и снова. Первые 4 строки функции цикла предназначены для чтения текущего состояния кнопок. Если кнопка нажата, переменная buttonState имеет значение LOW, и мы реагируем следующим образом реакцией в зависимости от того, какая кнопка была нажата, а затем запускаем функцию printScreen, которая будет объяснена в следующем разделе этого руководства по меню..
Сначала мы обсудим инструкции buttonStateLeft и buttonStateRight. Мы вводим первый if-запрос, если кнопка нажата, и очищаем экран, чтобы отобразить новый экран без старой информации. Для левой кнопки мы уменьшаем указатель, чтобы отобразить предыдущий экран, но когда указатель уже находится на первом экране (currentScreen == 0), мы хотим отобразить последний экран, чтобы получить бесконечное вращение, которое вы знаете со своего мобильного телефона. Для правой кнопки мы хотим отобразить следующий экран. Поэтому мы увеличиваем переменную currentScreen. Если мы дойдем до последнего экрана, мы покажем первый экран, чтобы получить функциональность бесконечного цикла в экранах.
Теперь мы хотим обсудить, что произойдет, если мы нажмем кнопку вверх или вниз. Сначала мы очищаем экран, а затем либо увеличиваем, либо уменьшаем значение текущего экрана. Соответствующий массив, который мы определили ранее, хранит значения изменений. Следовательно, для каждого экрана мы можем изменить значение.

Функция printScreen имеет много строк, но она довольно проста и понятна. Сначала мы проверяем, находимся ли мы на последнем экране номер 3. Если да, то мы хотим отображать каждое число и каждую единицу измерения в строке. Поэтому мы устанавливаем курсор в первую строку и печатаем название числа, число и единицу измерения. Мы делаем это построчно, меняя курсор.
Если мы не на последнем экране, мы хотим вывести заголовок «МЕНЮ ТОТОРИАЛ» в первой строке и использовать последние две строки для отображения имени числа, число и единица измерения.

Я знаю, что такие руководства могут быть немного сухими, но в следующем видео вы увидите меню кнопок в действии. Вы видите, как я листаю все экраны и меняю значения. Каждый раз, когда значение изменяется, оно также сохраняется и не перезаписывается с начальных значений.

В этом уроке я показал вам, как создавать базовое меню с 4 кнопками, ЖК-дисплеем и Arduino Nano. Конечно, это основы, но, начиная с этого момента, вы можете создать собственное меню и даже более сложные решения. Если у вас есть проблемы с созданием меню или общие вопросы к этому руководству, не стесняйтесь использовать раздел комментариев ниже, чтобы задать свои вопросы. Я отвечаю на них как можно скорее.

Недавние сообщения
  • Активный и пассивный зуммер для Arduino, ESP8266 и ESP32
  • Учебное пособие по датчику звука для Arduino, ESP8266 и ESP32
  • Руководство по уменьшению Энергопотребление ESP32 на 95%
  • Руководство по датчику газа MQ2 для Arduino, ESP8266 и ESP32
  • Руководство по датчику пламени KY-026 для Arduino, ESP8266 и ESP32

Привет, можно ли изменить значение (калибровка АЦП).

Ответ


Bonsoir: этот комментарий создан в меню для хранения отправителя температуры и запаса в EEPROM и австралийском для настройки даты

Ответ


Мы работаем над более быстрым интерфейсом между нашими ротаторами и нашими камерами. Этот набросок меню очень поможет в поиске способа редактирования значений остановки и запуска, а также времени ожидания между ходами. Большое спасибо за то, что нашли время продемонстрировать эту идею.

Ответ



Как сделать динамическое меню с подменю (Arduino mega или Arduino Uno )

У меня есть мега arduino с экраном LCD (от keyestudio KS2056). Я пытаюсь создать меню с подменю, в котором были бы добавляемые и удаляемые строки на основе входных данных со сканера RFID (добавляемый) и кнопок (для удаления выбранных строк). Я не совсем уверен, как я мог это сделать. Любая помощь будет отличной.


0

I пропустит часть RFID, которая не связана с меню.

Вы можете создать две переменные:

  int menuLevel1 = 0;  int menuLevel2 = 0;  

Предполагая, что у вас есть 2 уровня, если у вас больше уровней, рассмотрите массив.

Теперь вы можете распечатать экран на основе значения этих двух переменных (используйте оператор switch для menuLevel1, который вызывает новые функции, каждая со своим собственным оператором switch для menuLevel2.

Обратите внимание, что есть и другие решения, но это довольно простое решение.

Сканер RFID просто изменяет значения, поэтому переходит к другому экрану меню.

Немного другое решение — использовать не числа, а перечисление (или одно для основного уровня, и x для второго уровня и т. д.). Это может складываться, поэтому вы также можете использовать e — одно значение перечисления (с одной записью на каждую возможную страницу меню).

Последний пример выглядит так:

  enum EMenuPage {StartPage, MainMenu,  FirstMenu, DisplayX, SetY,…} enum EMenuPage _menuPage;  

Отображается как:

  switch (_menuPage) {case StartPage: //Заполняем ЖК-дисплей разрывом начальной страницы; case…  

И когда приходит сообщение RFID:

  if (RFID.  .. == Назад) {_menuPage = MainMenu;} else…  

Улучшите этот ответ
ответил 06 января ’20 в 14:57
добавить комментарий |

Я пропущу часть RFID, которая не связана с меню.

Что вы можете сделать, так это создание двух переменных:

  int menuLevel1 = 0; int menuLevel2 = 0;  

Предполагая, что у вас есть 2 уровня, если у вас есть больше уровней рассматривают массив.

Теперь вы можете распечатать экран на основе значений этих двух переменных (используйте оператор switch для menuLevel1, который вызывает новые функции, каждая со своим собственным switch для menuLevel2.

Обратите внимание, что есть и другие решения, но это довольно простое решение.

Сканер RFID просто изменяет Значения, поэтому переход к другому экрану меню.

Немного другое решение — использовать не числа, а перечисление (или одно для основного уровня, и x для второго уровня и т. д.). можно складывать, поэтому вы также можете использовать одно значение перечисления (с одной записью на каждую возможную страницу меню).

Последний пример выглядит так:

  enum EMenuPage {StartPage, MainMenu, FirstMenu, DisplayX, SetY,…} enum EMenuPage _menuPage;  

Отображается как:

  switch (_menuPage) {case StartPage://Заполняем ЖК-дисплей разрывом начальной страницы; case…  

И когда приходит сообщение RFID:

   if (RFID ... == Назад)  {_menuPage = MainMenu;} else…  

0

[Конечные автоматы] [1]. это общая форма решения, предоставленного Майклом выше. это большая помощь в ситуациях, когда приложение должно отвечать или действовать во многих состояниях (например, меню). хорошо то, что вы можете нарисовать их на листе бумаги , нарисовать график, управлять вводом/выводом и написать общую процедуру для действий в различных состояниях. их имена состояний могут быть представлены целочисленной переменной и лучше представлены перечислением. после этого должна быть процедура, которая будет действовать на основе текущего состояния, и вход из текущего состояния для перехода в другое состояние. в его самой простой форме это просто блок if-else . depsite идея такая же, как и решение с голыми переменными, представленное в других ответах, игнорируя методы, связанные с конечным автоматом (например, просто рисование графов состояний вниз на листе бумаги) делает большое приложение неуправляемым.

Улучшите этот ответ
ответил 4 июня ’20 в 17:32
добавить комментарий |

[Конечные автоматы] [1]. это общая форма решения, предоставленного Майклом выше. это большая помощь в ситуациях, когда приложение должно отвечать или действовать во многих состояниях (например, меню). хорошо то, что вы можете нарисовать их на листе бумаги , нарисовать график, управлять вводом/выводом и написать общую процедуру для работы в различных состояниях. имена состояний могут быть представлены целочисленной переменной и лучше представлены перечислением. после этого должна быть процедура, которая будет действовать на основе текущего состояния, и вход из текущего состояния для перехода в другое состояние. в его самой простой форме это просто блок if-else . depsite идея такая же, как и решение с голыми переменными, представленное в других ответах, игнорируя методы, связанные с конечным автоматом (например, просто рисование графов состояний вниз на листе бумаги) делает большое приложение неуправляемым.

Оцените статью
logicle.ru
Добавить комментарий