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 дисплейКнопкаМенюПрограммирование