Покритикуйте функцию меню для LCD1602

Хотелось бы узнать у знающих людей насколько жизнеспособна такая функция для меню на LCD1602.
Вроде как будто работает. Интересует мнение на сам алгоритм.
Особенность дисплея или библиотеки, при выводе строки первый символ не должен быть пробелом. иначе все рушится. Пришлось использовать строку такую “> пункт <”

 #define T_FOLDER         0 //   Тип меню - папка
#define T_APP            1 //   Функция для выполнения кода
struct menuStruct {               // создаём ярлык структуры меню
	uint8_t type;   //  тип меню папка или функция , если функция , то mode1 - номер функции, mode2 - параметры функций
	uint8_t parent; //  номер родителя, верхний уровень 0. 
	uint8_t mode1;  //  стартовый номер дочернего пункта меню в массиве MenuTable
	uint8_t mode2;  //  колличество  пунктов меню
	char name[32];  //  название пункта меню
};
//массив структуры меню
static PROGMEM  menuStruct MenuTable[] = {
	T_FOLDER,     0, 1, 3,"      МЕНЮ      ", //  Меню 0 Это MenuLevel
		T_FOLDER,   0, 2, 3,">   Промывка   <", // 1
			T_APP,    1, 2, 3,">Старт промывки<", // 2
			T_APP,    1, 2, 3,"> Стоп промывки<", // 3
      T_APP,    1, 2, 3,">    Выход     <", // 4
		T_FOLDER,   0, 6, 5,">   Настройка  <", // 5
			T_FOLDER, 5, 6, 2,">   Громкость  <",
				T_APP,  6, 6, 2,">Уровень умолч.<",
				T_APP,  6, 6, 2,">    Выход     <",
			T_FOLDER, 5, 10,3,">    Налив     <",
				T_APP,  6, 1, 3,    "Уровень",
				T_APP,  6, 2, 3,    "Проверка",
				T_APP,  6, 3, 3,    "Выход",
			T_FOLDER, 5, 14,3,">  Тип тостов  <",
				T_APP,  6, 1, 3,    "Случайно",
				T_APP,  6, 2, 3,    "По порядку",
				T_APP,  6, 3, 3,    "Выход",
			T_FOLDER, 5, 18,3,">  Тип налива  <",
				T_APP,  6, 1, 1,    "Стандартный",
				T_APP,  6, 2, 1,    "Игра",
				T_APP,  6, 3, 1,">    Выход     <",
			T_APP,    5, 1, 1,">    Выход     <",
		T_APP,      0, 2, 1,">    Выход     <"
	};

uint8_t menuLevel = 0;  //  Текущий уровень меню

//======= Функция обработки меню ==================================================================
void menuEnter(int command){            //  command - это номер родителя меню
  menuLevel = MenuTable[command].mode1; //  Устанавливает номер дочернего меню в массиве меню
  int i =0;
  int timeavtoexitstart = millis();
  lcd.clear() ;
  u_int8_t currentMenuItem = 1; //  Устанавливает номер текущего пункта меню
  while ((millis() - timeavtoexitstart < 60000) || i==2) //  автовыход из пунктов меню через 1 минуту
    {
      lcd.setCursor(0, 0);    // Устанавливает курсор в (позицию,Строка) 
      lcd.print(MenuTable[command].name);
      lcd.setCursor(0, 1);  // Устанавливает курсор в (позицию,Строка)
      lcd.print(MenuTable[menuLevel].name); 
      i = opros_encoder();   
      switch (i) {
        case 0:
        // выполнить, если значение == 0
        break; 
        case 1:
        // выполнить, если значение == 1 
          {
            if (MenuTable[menuLevel].type==0)
            {
              int menuLevelOld = menuLevel;
              menuEnter(MenuTable[menuLevel].mode1-1);  //  передали в функцию меню номер родителя
              menuLevel = menuLevelOld;
            }
            if (MenuTable[menuLevel].type==1)
            {
              // Выполнить функцию привязанную к данному меню
              menuCommand(menuLevel);
              return;
            }
          }
        break;
        case 2:
        // выполнить, если значение == 2  
        break;
        case 3:
        // выполнить, если значение == 3  
          { //Serial.println(" отработали козу Повернули вправо шаг меню вниз");
            currentMenuItem++;
            if (currentMenuItem>MenuTable[command].mode2) 
              {
                currentMenuItem --;
                menuLevel --;
              }
            do {
              menuLevel++;
            } while (command!=MenuTable[menuLevel].parent);    
            timeavtoexitstart = millis();
          }
        break;
        case 4:
        // выполнить, если значение == 4
          { //Serial.println(" отработали козу Повернули влево шаг меню вверх"); 
            currentMenuItem--;
            if (currentMenuItem<1) 
              {
                currentMenuItem ++;
                menuLevel ++;
              }
            do {
              menuLevel--;
            } while (command!=MenuTable[menuLevel].parent);    
            timeavtoexitstart = millis();
          }   
        break;
      }
    }
  lcd.clear();
  lcd.setCursor(3, 0);  // Первый аргумент позиция, второй строка
  lcd.print("Наливатор"); 
  lcd.setCursor(4, 1);
  lcd.print("Версия 1");
  menuLevel = command;  //  Устанавливает уровень меню в начальное состояние
}

А что, привести полный код, который можно было бы запустить, не судьба?

Лучше все же использовать связные списки.

Если он до них дочитал

2 лайка

раз автор не дает тестовый код, пройдемся просто по тексту

Я правильно понимаю, что в течении 60 сек строчки меню будут непрерывно перерисовываться?

Вообще, в большинстве случаев while и millis() не стоит смешивать, а то получается ерунда.

Далее, в чем смысл цифровых параметров в строчках меню с командами (тип T_APP)?
Глядя сюда - похоже что эти параметры игнорируются (поскольку значения у двух пунктов меню совпадают):

а вот тут похоже что-то значат (цифры разные)

Ну и замечание в целом - вместо написания совершенно бессмысленных комментариев типа

лучше бы пояснили, что в этом месте происходит с меню. Чем, например, кейс 1 отличается от 2 и 3?

2 лайка

Насколько я вижу, автор их и использует. Каждый итем меню указывает на родителя и на потомки.
Реализовано “вручную”, через числовые индексы, но это именно они, списки.

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

у меня пока больше вопросов к реализации (то есть к мелочам), чем к алгоритму.

То есть к этим дурацким комментам, к использованию “магических чисел”, в то время как автор сам же! определил именованные константы… к тому что нумерация строк идет с единицы, а не с нуля…
Все это делает код запутанным и сложным для восприятия и затрудняет оценку идеи в целом (лично для меня). За всеми этими мелочами я не вижу, нафига автор это выложил

1 лайк

Одних только м̶а̶г̶н̶и̶т̶о̶ф̶о̶н̶ ̶и̶м̶п̶о̶р̶т̶н̶ы̶й̶ “выходов” 7 шт.
И прочие “промывка идёт”/“промывка завершена”, выглядят крайне ущербно.
Можно же просто завести пункт промывка, при его активации вызывать функцию, которая на время своего выполнения выведет сообщение.
Кстати, так и не нашел адекватного понимания тому, зачем нужна информация о том, что промывка завершена.

извиняюсь, выложу сегодня полный код.

Нет неправильно, 60 сек, это таймаут для выхода из меню. А список отработал только на первых двух позициях. Это тест.

Кейз 0 не используется. Кейз 1 короткое нажатие, Кейз 2 длинное нажатие на энкодер, кейз 3 и 4 поворот вправо и влево.

Нумерация главного меню(массива) идет с 0, а вот подпункты действительно идут с 1, так как проще с математикой, в одном месте было бы -1.

Почему неправильно-то?
Я вижу что перерисовка меню лежит внутри цикла while. Вы в курсе, как это цикл работает? - пока счетчик не отсчитает 60 сек, все что в цикле будет выполнятся много-много раз
Зачем вообще нужен цикл while, если у вас есть миллис?

Дело то не в названиях пунктов меню, раньше рекурсией не пользовался. Это первый опыт.

А, понял о чем, это кривизна русской библиотеки для экрана. Вот и пришлось ее перерисовать внутри цикла, в противном случае крашится все и идет перезагрузка. А в цикле идет ожидание отклика на действия энкодера.

плохому танцору :slight_smile:

1 лайк

ну я задавал по этому поводу вопрос ранее, был совет сделать так. и именно виновата была библиотека

Green

1 сент.

12

Да, есть такая проблемка с библиотекой LCD_1602_RUS_ALL. При первом проходе искажает свои, уже нарисованные, символы. Костыль был такой:

Ну и почему это не написать в комментариях, вместо абсолютно бессмысленного:

???

То, что это при 1 отлично и из кода видно, комментарий не несёт никакой (от слова никакой) новой информации, только замусоривает код. А вот написать здесь “обработка короткого нажатия” имело бы смысл, чтобы потом отдельно не пояснять (самому себе через год).

каюсь, половина комментариев подставляет помощник.