system_menu: как на Arduino с библиотекой LiquidMenu построить систему меню

Добавлено 13 мая 2018 в 01:27

Данный пример демонстрирует, как построить систему меню.

Система меню – это коллекция меню. Чтобы построить систему меню, вам необходимо поместить меню в объект класса LiquidSystem. Методы, используемые с LiquidMenu, должны теперь вызываться напрямую от объекта LiquidSystem. Для переключения между меню используйте метод bool LiquidSystem::change_menu(LiquidMenu &p_liquidMenu). Данный метод может быть обернут внутрь функции обратного вызова и вызываться через меню. Данный пример также использует EEPROM для сохранения состояния светодиода и периода считывания.

Схема

Схема для примера system_menu
Схема для примера system_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;
};

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

#include <LiquidCrystal.h>
#include <LiquidMenu.h>
#include <EEPROM.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
const bool pullup = true;
Button left(A0, pullup);
Button right(7, pullup);
Button up(8, pullup);
Button down(9, pullup);
Button enter(10, pullup);

// Определение выводов и переменных для их состояний.
const byte pin6 = 6;
byte pin6_level = 0;

const byte pinA4 = A4;
byte pinA4_value = 0;

const byte pinA5 = A5;
byte pinA5_value = 0;

// Период считывания аналоговых отсчетов в секундах.
// Позже это значение будет перезаписано значением из EEPROM.
unsigned short sample_period = 2;

// Текст, используемый для индикации сохранения строк.
char* input_saved;
char* output_saved;

enum FunctionTypes 
{
  increase = 1,
  decrease = 2,
};


// Объект LiquidLine может использоваться более одного раза.
LiquidLine back_line(11, 1, "/BACK");


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

// Эти строки направляют к другим меню.
LiquidLine outputs_line(0, 0, "/Outputs");
LiquidLine inputs_line(0, 1, "/Inputs");
LiquidScreen io_screen(outputs_line, inputs_line);

// Это первое меню.
LiquidMenu main_menu(lcd, welcome_screen, io_screen, 1);


LiquidLine pin6_line(0, 0, "Pin 6: ", pin6_level);
LiquidScreen pin6_screen(pin6_line);

LiquidLine oSave_line(0, 0, "Save", output_saved);
LiquidScreen oSecondary_screen(oSave_line, back_line);

// Это второе меню.
LiquidMenu outputs_menu(lcd, pin6_screen, oSecondary_screen);


LiquidLine pinA4_line(0, 0, "Pin A4: ", pinA4_value);
LiquidLine pinA5_line(0, 1, "Pin A5: ", pinA5_value);
LiquidScreen pinsA4_A5_screen(pinA4_line, pinA5_line);

LiquidLine iSample_line(0, 0, "Sample: ", sample_period, "s");
LiquidLine iSave_line(0, 1, "Save", input_saved);
LiquidScreen iSecondary_screen(iSample_line, iSave_line, back_line);

// И это последнее третье меню.
LiquidMenu inputs_menu(lcd, pinsA4_A5_screen, iSecondary_screen);

/*
 * Объект LiquidSystem объединяет объекты LiquidMenu из системы меню.
 * Он обеспечивает те же функции, что и LiquidMenu, плюс добавляет
 * add_menu() и change_menu().
 */
LiquidSystem menu_system(main_menu, outputs_menu, inputs_menu);


// Проверить все кнопки.
void buttonsCheck() {
  if (right.check() == LOW) 
  {
    menu_system.next_screen();
  }
  if (left.check() == LOW) 
  {
    menu_system.previous_screen();
  }
  if (up.check() == LOW) 
  {
    menu_system.call_function(increase);
  }
  if (down.check() == LOW) 
  {
    menu_system.call_function(decrease);
  }
  if (enter.check() == LOW) 
  {
    menu_system.switch_focus();
  }
}

// Функция обратного вызова будет прикреплена к back_line.
void go_back() 
{
  // Данная функция ссылается на необходимое меню.
  menu_system.change_menu(main_menu);
}

void goto_outputs_menu() 
{
  menu_system.change_menu(outputs_menu);
}

void goto_inputs_menu() 
{
  menu_system.change_menu(inputs_menu);
}

void increase_pin6() 
{
  if (pin6_level < 225) 
  {
    pin6_level += 25;
  } 
  else 
  {
    pin6_level = 250;
  }
  analogWrite(pin6, pin6_level);
  output_saved = (char*)"  ";
}

void decrease_pin6() 
{
  if (pin6_level > 25) 
  {
    pin6_level -= 25;
  } 
  else 
  {
    pin6_level = 0;
  }
  analogWrite(pin6, pin6_level);
  output_saved = (char*)"  ";
}

void save_input() 
{
  EEPROM.put(11, sample_period);
  input_saved = (char*)" *";
}

void save_output() 
{
  EEPROM.put(9, pin6_level);
  output_saved = (char*)" *";
}

void increase_samplePeriod() 
{
  if (sample_period < 10) 
  {
    sample_period++;
    input_saved = (char*)"  ";
  }
}

void decrease_samplePeriod() 
{
  if (sample_period > 0) 
  {
    sample_period--;
    input_saved = (char*)"  ";
  }
}

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

  pinMode(pin6, OUTPUT);

  // Прочитать значения, записанные в EEPROM
  EEPROM.get(9, pin6_level);
  EEPROM.get(11, sample_period);
  analogWrite(pin6, pin6_level);

  lcd.begin(16, 2);

  back_line.set_focusPosition(Position::LEFT);

  back_line.attach_function(1, go_back);
  back_line.attach_function(2, go_back);

  outputs_line.attach_function(1, goto_outputs_menu);
  outputs_line.attach_function(2, goto_outputs_menu);
  inputs_line.attach_function(1, goto_inputs_menu);
  inputs_line.attach_function(2, goto_inputs_menu);

  pin6_line.attach_function(increase, increase_pin6);
  pin6_line.attach_function(decrease, decrease_pin6);

  oSave_line.attach_function(1, save_output);
  oSave_line.attach_function(2, save_output);
  iSave_line.attach_function(1, save_input);
  iSave_line.attach_function(2, save_input);
  iSample_line.attach_function(increase, increase_samplePeriod);
  iSample_line.attach_function(decrease, decrease_samplePeriod);

  input_saved = (char*)" *";
  output_saved = (char*)" *";

  menu_system.update();
}

void loop() 
{
  buttonsCheck();

  static unsigned long lastMillis_sample = 0;
  if (millis() - lastMillis_sample > (sample_period * 1000)) 
  {
    lastMillis_sample = millis();
    pinA4_value = analogRead(pinA4);
    pinA5_value = analogRead(pinA5);
    menu_system.update();
  }

}

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

 

Теги

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

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

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