buttons_menu: как на Arduino с библиотекой LiquidMenu использовать кнопки, функции обратного вызова и переменные, меняющие текст

Добавлено 9 мая 2018 в 11:01

Данный пример демонстрирует, как использовать кнопки, функции обратного вызова и переменные, изменяющие текст.

В примере создается три экрана. Первый показывает статическую информацию. Второй показывает показание аналогового входа и состояние светодиода на выводе 13. И третий экран показывает значение ШИМ, поданное на вывод 3. Аналоговое значение периодически считывается и присваивается прикрепленной переменной, которая так же меняется. Вывод 3 выхода ШИМ управляется через функции обратного вызова, прикрепленные к их строке: "void pwm_up()" and "void pwm_down()". Чтобы вызвать функции перейдите к третьему экрану, используя кнопки "left" и "right", выделите строку, используя кнопку "enter", а затем нажмите кнопку "up" или "down".

Схема

Схема для примера buttons_menu
Схема для примера buttons_menu

Соединения:

  • вывод RS LCD к выводу 12 Arduino;
  • вывод E LCD к выводу 11 Arduino;
  • вывод D4 LCD к выводу 5 Arduino;
  • вывод D5 LCD к выводу 4 Arduino;
  • вывод D6 LCD к выводу 3 Arduino;
  • вывод D7 LCD к выводу 2 Arduino;
  • вывод R/W LCD на корпус;
  • вывод VSS LCD на корпус;
  • вывод VCC LCD к +5В;
  • потенциометр 10 кОм: концы к корпусу и +5В, средний вывод к выводу V0 LCD;
  • резистор 150 Ом между +5В и анодом LCD подсветки;
  • катод LCD подсветки к корпусу;
  • ----
  • кнопка (left, влево) к выводу A0 Arduino и к корпусу;
  • кнопка (right, вправо) к выводу 7 Arduino и к корпусу;
  • кнопка (up, вверх) к выводу 8 Arduino и к корпусу;
  • кнопка (down, вниз) к выводу 9 Arduino и к корпусу;
  • кнопка (enter, ввод) к выводу 10 Arduino и к корпусу;
  • устройство, управляемое ШИМ, (светодиод...) к выводу 6 Arduino;
  • светодиод к выводу 13 Arduino (необязательно);
  • какой-либо аналоговый сигнал к выводу A5 Arduino (неподключенный тоже работает).

Код

Код класса Button (файл Button.h).

#pragma once

class Button 
{
public:
  Button (uint8_t pin, bool pullup = false, uint16_t debounceDelay = 50)
    : _pin(pin), _state(LOW), _lastState(LOW),
      _lastMillis(0), _debounceDelay(debounceDelay),
      _lastDebounceTime(0) 
  {
    if (pullup == true) 
    {
      pinMode(_pin, INPUT_PULLUP);
    } 
    else 
    {
      pinMode(_pin, INPUT);
    }
  }

  // Устраняет дребезг кнопки и возвращает состояние, если оно только что изменилось.
  bool check(bool triggerState = LOW) 
  {
    bool reading = digitalRead(_pin);
    // Проверить, изменилось ли состояние кнопки 
    if (reading != _lastState) 
    {
      _lastDebounceTime = millis();
    }
    // Проверить, изменилось ли состояние кнопки за '_debounceDelay' миллисекунд.
    if ((millis() - _lastDebounceTime) > _debounceDelay) 
    {
      //Проверить, изменилось ли состояние кнопки 
      if (reading != _state) 
      {
        _state = reading;
        return _state;
      }
    }
    _lastState = reading;
    // Если этот код был достигнут, он возвращает нормальное состояние кнопки.
    if (triggerState == HIGH) 
    {
      return LOW;
    } 
    else 
    {
      return HIGH;
    }
  }

private:
  const uint8_t _pin;
  bool _state;
  bool _lastState;
  uint32_t _lastMillis;
  uint16_t _debounceDelay;
  uint32_t _lastDebounceTime;
};

Код скетча buttons_menu.ino

#include <LiquidCrystal.h>
#include <LiquidMenu.h>
#include "Button.h"

// Выводы, подключенные к дисплею:
const byte LCD_RS = 12;
const byte LCD_E = 11;
const byte LCD_D4 = 5;
const byte LCD_D5 = 4;
const byte LCD_D6 = 3;
const byte LCD_D7 = 2;
//LCD R/W вывод на корпус
//Средний вывод потенциометра 10кОм к VO
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

// Инициализация объектов Button
/*
 * Класс Button не является частью библиотеки LiquidMenu library. Первый
 * параметр - это вывод кнопки, второй - включает или выключает внутренний
 * подтягивающий резистор (необязательный), и третий - время устранения
 * дребезга контактов (необязательный).
 */
const bool pullup = true;
Button left(A0, pullup);
Button right(7, pullup);
Button up(8, pullup);
Button down(9, pullup);
Button enter(10, pullup);

// Переменные, используемые для демонстрации управления ШИМ с помощью функций обратного вызова.
/*
 * Переменная 'pwmLevel' позже передается объекту 'pwm_line', чтобы быть
 * показанной на дисплее, и функция прикрепляется к тому же объекту LiquidLine.
 * Функции прикрепляются к разным объектам LiquidLine с номером для
 * идентификации, например, pwm_line.attach_function(2, func); тогда как
 * menu.call_function(2) вызывается при каком-либо событии, например, нажатии кнопки,
 * из-за чего вызывается функция, идентифицируемая с 2 для выделенной строки.
 * Похожие функции (например, инкрементирование) могут быть прикреплены к разным 
 * объетам LiquidLine с одинаковыми номерами идентификации, а затем вызываться
 * при некотором событии (например, нажатии кнопки 'UP') с помощью menu.call_function(2),
 * что вызовет функцию только для выделенной строки, которая идентифицируется с 
 * номером 2.
 */
const byte pwmPin = 6;
byte pwmLevel = 0;

// Переменные для управления выводом и отображения состояния с помощью текста.
// char* используется для добавления изменяющегося текста в объект the LiquidLine.
const byte ledPin = LED_BUILTIN;
bool ledState = LOW;
char* ledState_text;

/*
 * Переменная 'analogValue' позже конфигурируется для печати на дисплее.
 * На этот раз для хранения предыдущего аналогового значения используется статическая переменная.
 */
const byte analogPin = A5;
unsigned short analogValue = 0;


LiquidLine welcome_line1(1, 0, "LiquidMenu ", LIQUIDMENU_VERSION);
LiquidLine welcome_line2(0, 1, "Buttons example");
LiquidScreen welcome_screen(welcome_line1, welcome_line2);

LiquidLine analog_line(0, 0, "Analog: ", analogValue);
LiquidLine ledState_line(0, 1, "LED is ", ledState_text);
LiquidScreen screen2(analog_line, ledState_line);

LiquidLine pwm_line(0, 0, "PWM level: ", pwmLevel);
LiquidScreen pwm_screen(pwm_line);

LiquidMenu menu(lcd);

// Функция для прикрепления к объекту pwm_line.
/*
 * Данная функция используется для инкрементирования уровния ШИМ на
 * 'pwmPin'. Она увеличивает значение 'pwmLevel', а затем
 * записывает его в вывод.
 */
void pwm_up() 
{
  if (pwmLevel < 225) 
  {
    pwmLevel += 25;
  } 
  else 
  {
    pwmLevel = 250;
  }
  analogWrite(pwmPin, pwmLevel);
}

// Функция для прикрепления к объекту pwm_line.
void pwm_down() 
{
  if (pwmLevel > 25) 
  {
    pwmLevel -= 25;
  } 
  else 
  {
    pwmLevel = 0;
  }
  analogWrite(pwmPin, pwmLevel);
}

void setup() 
{
  Serial.begin(250000);

  pinMode(analogPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(pwmPin, OUTPUT);

  lcd.begin(16, 2);

  // Прикрепить функции к объектам LiquidLine.
  pwm_line.attach_function(1, pwm_up);
  pwm_line.attach_function(2, pwm_down);

  menu.add_screen(welcome_screen);
  menu.add_screen(screen2);
  menu.add_screen(pwm_screen);
}

void loop() {

  // Проверить все кнопки
  if (right.check() == LOW) 
  {
    Serial.println(F("RIGHT button clicked"));
    menu.next_screen();
  }
  if (left.check() == LOW) 
  {
    Serial.println(F("LEFT button clicked"));
    menu.previous_screen();
  }
  if (up.check() == LOW) 
  {
    Serial.println(F("UP button clicked"));
    // Вызвать функцию, идентифицированную номером 1
    // для выделенной строки.
    menu.call_function(1);
  }
  if (down.check() == LOW) 
  {
    Serial.println(F("DOWN button clicked"));
    menu.call_function(2);
  }
  if (enter.check() == LOW) 
  {
    Serial.println(F("ENTER button clicked"));
    // Переключить фокус на следующую строку.
    menu.switch_focus();
  }


  // Периодически переключать состояние светодиода.
  static unsigned long lastMillis = 0;
  static unsigned int period = 2000;
  if (millis() - lastMillis > period) 
  {
    lastMillis = millis();

    Serial.print("LED turned ");
    if (ledState == LOW) 
    {
      ledState = HIGH;
      // Изменить текст, который напечатан на дисплее.
      ledState_text = (char*)"ON";
      Serial.println(ledState_text);
      menu.update();
    } 
    else 
    {
      ledState = LOW;
      ledState_text = (char*)"OFF";
      Serial.println(ledState_text);
      menu.update();
    }
    digitalWrite(ledPin, ledState);

    // Значение 'analogValue' обновляется каждую секунду.
    analogValue = analogRead(analogPin);
    static unsigned short lastAnalogValue = 0;
    if (analogValue != lastAnalogValue) 
    {
      lastAnalogValue = analogValue;
      menu.update();
    }
  }
}

Для более подробной информации смотрите документацию на библиотеку LiquidMenu.

Теги

ArduinoLCD дисплейКнопкаМенюПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.