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