Реквестирую помощь с меню

Борис Евгеньевич

✩✩✩✩✩✩✩
20 Авг 2020
6
0
Взываю к помощи высших сущностей в мире Arduino IDE!!!
Решил на базе примера Гайвера сделать меню для своего проекта и почти преуспел в богопротивной химеризации))))
Вот только имеется следующий поганый эффект: Экраны листать можно, но в случае внесения правок их отображение отстает от совершаемых действий. Более того, попытки переключать стрелку с использование функции isClick вообще не несет видимых изменений, а они от части происходят: после пары поворотов энкодера курсор-таки перемещается на одно деление (вне зависимости от того, сколько раз мы на него кликнули) и уже начинает менять значения. Но изменения значений опять-таки запаздывают.
Мой текущий (недалекий от начального) уровень владения Arduino-колдовством уже не позволяет найти причину неподконтрольных процессов, протекающих при исполнении данного скетча, потому решил обратиться к здесь присутствующим. Скетч, не дающий покоя мне уже три ночи прикрепляю файлом ниже. Заранее благодарю вас за помощь и уделенное время данной проблеме)
 

Вложения

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
Между тиками и проверками енкодера очень много функций, которые выполняются медленно. Вероятно они и дают такой эффект.
 

Борис Евгеньевич

✩✩✩✩✩✩✩
20 Авг 2020
6
0
Попробовал воткнуть опрос энкодера (enc.tick()) внутрь функции printAtmosphere, но ничего не изменилось(
Между тиками и проверками енкодера очень много функций, которые выполняются медленно. Вероятно они и дают такой эффект.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
Я это вижу так, кстати, ардуина видит это так же.
Начальный экран, поворот энкодера, тик его поймал поймал, сменил экран на printAtmosphere (это к примеру). Что то написал темным по зеленому, вывел стрелку, а далее пулюнул слюной на все условия опроса энкодера. потому как 1) я его уже опросил в лупе и значение поворота считалось. А потом я вышел из printAtmosphere. И ! Опять тик ловит поворот энкодера и что я буду менять ? правильно! d
Вывод! в основном цикле loop мало менять d, надо в зависимости от выведенного экрана еще и менять ту же arrowPos.
В целом как то так.
Для примера можно посмотреть видео с теплицеконтроллером. Там повороты и перемещения меняются местами от клика энкодера.
 

Борис Евгеньевич

✩✩✩✩✩✩✩
20 Авг 2020
6
0
Так, человека со знанием как решить проблему, как мне кажется нашел. Осталось сформировать понимание этого решения у себя))))
Вы предлагаете менять помимо d еще значение arrowPos в цикле loop... Но ведь arrowPos это положение стрелки. И оно будет для каждого случая определяться в зависимости от того на какой экран мы перешли. Как его запихнуть в loop?
Пример с Теплицеконтроллером в моем случае не является удачным, так как код для меня сложноват, я его не понимаю. Потому решил делать сам отталкиваясь от понятного более-менее примера с шахматным меню.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
Можно хранить положение стрелки отдельно для каждого экрана, можно сбрасывать в нулевую позицию когда переключаешься на экран. Тут много вариантов, все от личных предпочтений зависит.
Далее программа как то должна понять что делать в данный момент , менять экраны или положение курсора. Я предлагал посмотреть не код теплицы , а видео. И еще можно почитать инструкцию - что бы понять как сделана логика переходов по меню

А в loop примерно так
тик энкодера
если было изменение :
меняем экран ? да , нет
если да , то меняем d
меняем положение стрелки ? да, нет
если да, то
на каком экране находимся ?
экран 1
изменение положения стрелки для этого экрана
экран 2
изменение положения стрелки для этого экрана
...
 

Борис Евгеньевич

✩✩✩✩✩✩✩
20 Авг 2020
6
0
Для понимания программы "что делать в данный момент" я как раз решил сделать все действия на разные функции из библиотеки энкодера: поворот с нажатым энкодером - смена экрана, клик - перемещение стрелки, поворот энкодера - изменение величин текущих показателей.

Относительно предложенных изменений в loop:

я понял так, что мне просто надо убрать функции типа printAtmosphere и прописать все действия в кейсах. Если я понял правильно, то это не сработало.
Если я понял не правильно, то попрошу подробнее рассказать, если вас это не затруднит
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
Вот пример как можно сделать. Это то, что первое пришло в голову для такого случая.
Коменты к тексту
1) Это скелет программы, рабочий , с визуализацией в монитор порта на скорости 115200
2) 5 воображаемых экранов, в каждом по 11 положений курсора.
3) С нажатием меняется номер отображаемого (воображаемого!) экрана. Без нажатия положение курсора. Положение курсора сохраняется для каждого экрана.
4) if ((old_cur_screen != cur_screen) or arrow_f) это подразумевает, что перерисовка экрана происходит в любом случае поменялось ли положение курсора или номер экрана. Если разделить обработчик на 2 части, что я надеюсь не составит труда, то можно при изменении экрана менять весь экран, с очисткой, а во втором случае только положение курсора, что ускорит работу.
5) При простом клике на энкодере меняется режим отработки поворота на изменение значения в этом положении. Повтороно - обратно, на изменение курсора. При смене экрана режим всегда переходит на изменение положения.

Естественно все можно разнести по функциям.

C++:
#define CLK 2
#define DT 3
#define SW 4

#define NUM_SCREEN  5 // общее число экранов от 1 до 5

uint8_t arrowpos[NUM_SCREEN];
#define MAX_ARROW_POS 10 // должно быть индивидуально для каждого экнара от 0 до 10!. Я сделал общее, для упрощения ускорения.

#include "GyverEncoder.h"
Encoder enc(CLK, DT, SW);

void setup() {
  Serial.begin(115200);
  enc.setType(TYPE2);    // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
}

void loop() {
  bool arrow_f = false;
  static bool pos_mode = false;
  static int8_t cur_screen = 1; // номер текущего экрана
  static int8_t old_cur_screen = 0; // номер текущего экрана

  enc.tick();
  if (enc.isTurn()) {
    //Serial.print("Поворт");
    if (enc.isRight()) {
      if (pos_mode)
      {
        Serial.print("Меняется значение экран №"); Serial.println(cur_screen);
        Serial.print("в положение курсора №"); Serial.print(arrowpos[cur_screen - 1]);
        Serial.println("на +1");
      }
      else
      {
        (arrowpos[cur_screen - 1] == MAX_ARROW_POS) ? arrowpos[cur_screen - 1] = 0 : arrowpos[cur_screen - 1]++;
        arrow_f = true;
        //Serial.println(" в право");
      }

    }
    if (enc.isLeft()) {
      if (pos_mode)
      {
        Serial.print("Меняется значение экран №"); Serial.println(cur_screen);
        Serial.print("в положение курсора №"); Serial.print(arrowpos[cur_screen - 1]);
        Serial.println("на -1");
      }
      else
      {
        (arrowpos[cur_screen - 1] == 0) ? arrowpos[cur_screen - 1] = MAX_ARROW_POS  : arrowpos[cur_screen - 1]--;
        arrow_f = true;
        //Serial.println(" в лево");
      }
    }
    if (enc.isRightH()) {
      //Serial.println(" в право с нажатием");
      pos_mode = false;
      (cur_screen == 5) ? cur_screen = 1 : cur_screen++;
    }
    if (enc.isLeftH()) {
      //Serial.println(" в лево с нажатием");
      pos_mode = false;
      (cur_screen == 1) ? cur_screen = 5 : cur_screen--;
    }
  }
  if (enc.isClick()) {
    pos_mode = !pos_mode;
    //Serial.println("Клик");
  }


  if ((old_cur_screen != cur_screen) or arrow_f)
  {
    Serial.print("Отображем экран №"); Serial.println(cur_screen);
    switch (cur_screen)
    {
      case 1: {};
      case 2: {};
      case 3: {};
      case 4: {};
      case 5: {};
    }
    Serial.print("Положение курсора №"); Serial.println(arrowpos[cur_screen - 1]);
    old_cur_screen = cur_screen;
    arrow_f = false;
  };
}
 

b707_2

★★✩✩✩✩✩
22 Июл 2020
182
51
3) С нажатием меняется номер отображаемого (воображаемого!) экрана. Без нажатия положение курсора. Положение курсора сохраняется для каждого экрана.
зачем делать специальную комбинацию на смену экранов, почему не сделать, как делается во всех известных мне меню - вращение перемещает курсор вверх-вниз по меню, нажатием выбирается текущая строчка. В зависмости от назначения строчки это либо выбор изменения параметров, либо вход в подменю. либо выход на уровень вверх
И все, никаких "вращений с нажатием" не нужно
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
Вращение с нажатием (я его тоже не люблю) было задумано автором. Я просто показал как такое можно реализовать.
 

Борис Евгеньевич

✩✩✩✩✩✩✩
20 Авг 2020
6
0
зачем делать специальную комбинацию на смену экранов, почему не сделать, как делается во всех известных мне меню - вращение перемещает курсор вверх-вниз по меню, нажатием выбирается текущая строчка. В зависмости от назначения строчки это либо выбор изменения параметров, либо вход в подменю. либо выход на уровень вверх
И все, никаких "вращений с нажатием" не нужно
Это понятно, что так во всех известных меню. Но для меня (может потому что новичек) интуитивно понятнее все разнести на разные функции энкодера. Сделал так в попытке как-то упростить написание и понимание кода... Правда пока работает не очень))))