Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Меню в stm32 & LCD

Пн ноя 06, 2023 22:40:47

Как правильно создать меню на указателях и в чём его суть?

Re: Меню в stm32 & LCD

Пн ноя 06, 2023 22:52:27

Указатель суть есть адрес вызываемой функции обработчика меню. По нажатию кнопки вызывается соответствующая функция, где уже прописана реакция.

Re: Меню в stm32 & LCD

Вт ноя 07, 2023 11:41:56

Указатель суть есть адрес вызываемой функции обработчика меню. По нажатию кнопки вызывается соответствующая функция, где уже прописана реакция.

вы имеете ввиду что на любую кнопку нужна функция?Или как?

Re: Меню в stm32 & LCD

Вт ноя 07, 2023 12:06:33

если подобное условие возникло, то это и есть суть - решение этого условия.
как правильно программировать - слишком общий вопрос

Re: Меню в stm32 & LCD

Вт ноя 07, 2023 12:33:56

ioan dobrev писал(а): на любую кнопку нужна функция

На любое состояние нужна функция. Наверное, проще будет показать пример. Попозже старый проект отрою.

Re: Меню в stm32 & LCD

Вт ноя 07, 2023 20:48:57

Ну если можете покажите пример .И как допустим одна кнопка допустим в режиме UP и "+".

Добавлено after 2 minutes 4 seconds:
И любое состояние функция .И вывод информации.

Re: Меню в stm32 & LCD

Вт ноя 07, 2023 21:53:43

Тэээк-с, ну допустим. Вот один из вариантов реализации. Оно было скорее как эксперимент, но тем не менее.

Итак. Во-первых, надо объявить тип, который будет отвечать за один элемент меню.
Код:
typedef struct menuitem {
   char      name[17];  //выводимое имя пункта
   int32_t      min;          //минимальное значение параметра, который настраивается в меню
   int32_t      max;         //максимальное значение
   int32_t      value;       //текущее значение, Меняется кнопками "вверх" и "вниз"
   int32_t      oldvalue;  //значение до сохранения
   int32_t      step;          //шаг изменения значения
   struct   menuitem   *left;           //соседнее меню слева
   struct   menuitem   *right;        //соседнее меню справа
   int32_t (* action)();                          //действие пункта меню. Может быть как просто применение текущего значения параметра, так и целая подпрограмма.
   uint8_t      id;                           //просто номер
   } menuitem;


Далее описываются конкретные пункты. Для каждого пункта прописываются все эти поля. То есть громкость, допустим, регулируется от 5 условных единиц до 100 с шагом 5. Тогда переменная volume типа menuitem должна иметь volume.min=5, volume.max=100, volume.step=5. Ну и так далее со всеми элементами.
Код:
menuitem mainmenu={{0x41, 0xBC, 0xBE, 0xBB, 0xB8, 0xBF, 0x79, 0xE3, 0x61, 0x20, 0x79, 0xE3, 0x61, 0x70, 0x61, 0x3A, 0x00}, 0, 65000, 0, 0, 0, NULL, NULL, NULL, 0};
menuitem cortres={{0xA8, 0x6F, 0x70, 0x6F, 0xB4, 0x20, 0x4B, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, 0, 100000, 5000, 5000, 100, NULL, NULL, NULL, 1};
menuitem voltres={{0xA8, 0x6F, 0x70, 0x6F, 0xB4, 0x20, 0x48, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, 1, 4000, 500, 500, 50, NULL, NULL, NULL, 2};
menuitem blanktime={{0x42, 0x70, 0x65, 0xBC, 0xC7, 0x20, 0xB4, 0xBB, 0x79, 0x78, 0x6F, 0xBF, 0xC3, 0x3A, 0x20, 0x20, 0x00}, 0, 1000, 30, 30, 1, NULL, NULL, NULL, 3};
menuitem dynamic={{0xE0, 0xB8, 0xBD, 0x61, 0xBC, 0xB8, 0xBA, 0x61, 0x20, 0xB8, 0xB4, 0x70, 0xC3, 0x3A, 0x20, 0x20, 0x00}, 0, 1, 0, 0, 1, NULL, NULL, NULL, 4};
menuitem channels={{0x4B, 0x61, 0xBD, 0x61, 0xBB, 0x6F, 0xB3, 0x20, 0xB3, 0x78, 0x6F, 0xE3, 0x61, 0x3A, 0x20, 0x20, 0x20}, 1, 2, 1, 1, 1, NULL, NULL, NULL, 5};
menuitem learn={"Start learning? ", 0, 1, 0, 0, 1, NULL, NULL, NULL, 6}; //запас
menuitem soundsample={"Sound sample №:", 0, 1, 0, 0, 1, NULL, NULL, NULL, 7};
menuitem *curitem;

Curritem это, собственно, текущий активный элемент меню.
Далее описываем необходимые функции для каждого пункта меню. У меня эти функции вызывается по нажатию на кнопку ОК. Например
Код:
int32_t save()
{
   curitem->oldvalue=curitem->value;
   FramStoreValue(curitem->value, curitem->id);
   LedOn(3, 1000);
   return 0;
};

Вот эта функция выполняет сохранения выбранного значения во внешнюю энергонезависимую память и зажигает красный светодиод на секунду.
И так любые функции, которые надо выполнять по нажатию кнопки ОК.
Дальше начинается само формирования структуры меню. Само меню не древовидное, а в виде двусвязного списка. А можно и ещё связей добавить, сколько хватит кнопок и фантазии. То есть, для, так сказать, главного экрана присваиваем соответствующим полям ссылки на прочие элементы меню. Остальные поля не назначаются, поскольку прочих функций там не предусмотрено.
Код:
mainmenu.left=&cortres;
mainmenu.right=&blanktime;


И для всех остальных та же
Код:
cortres.left=&channels;
cortres.right=&blanktime;
cortres.action=&save;
cortres.oldvalue=FramLoadValue(cortres.id);
cortres.value=cortres.oldvalue;

blanktime.right=&dynamic;
blanktime.left=&cortres;
blanktime.action=&save;
blanktime.oldvalue=FramLoadValue(blanktime.id);
blanktime.value=blanktime.oldvalue;

И так далее для всех прочих пунктов. На этом же этапе происходит загрузка ранее сохранённых значений. Проверки нет, но было бы неплохо это предусмотреть. Ну да ладно, это дело завтрашнего дня.
Ну и собственно, антидребезг и реакция на каждую кнопку. Можно это дело хоть в прерывания засунуть. Для кнопок влево и вправо предусмотрено просто переключение пунктов, вверх и вниз изменяют параметры, ОК чаще всего просто сохраняет и применяет параметры, ВЫХ не делает ничего, просто возвращает в главное меню.
Код:
   while(millis<presstime+PRESSDELAY){};      //антидребезг
   delay(100);
   if(up()){
      curitem->value+=curitem->step;
      if(curitem->value > curitem->max){curitem->value = curitem->max;};
      presstime=millis;
      redraw=1;
      };
   if(down()){
      curitem->value-=curitem->step;
      if(curitem->value < curitem->min){curitem->value = curitem->min;};
      presstime=millis;
      redraw=1;
      };
   if(ok()){
      curitem->action();
      };
   if(esc()){
      curitem->value=curitem->oldvalue;
      curitem=&mainmenu;
      redraw=1;
      };
   if(left()){
      curitem->value=curitem->oldvalue;
      curitem=curitem->left;
      redraw=1;
      };
   if(right()){
      curitem->value=curitem->oldvalue;
      curitem=curitem->right;
      redraw=1;
      };

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

Re: Меню в stm32 & LCD

Вт ноя 07, 2023 22:06:42

>TEHb< писал(а):Во-первых, надо объявить тип, который будет отвечать за один элемент меню.
Точнее, за каждый элемент. И это и есть ответ на вопрос
ioan dobrev писал(а):в чём его суть?
. И чтобы окончательно понять преимущество такого подхода, необходимо изучить, что есть ООП (объектно-ориентированное программирование).

Re: Меню в stm32 & LCD

Ср ноя 08, 2023 19:46:35

ООП-а что это такое и с чем его едят.А то у меня меню какое то примитивное хочется пограммотнее

Re: Меню в stm32 & LCD

Ср ноя 08, 2023 20:06:04

Ну типа каждый пункт меню это такой объект со своими свойствами и функциями.
Да пофигу, код-то вполне С-шный.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 10:30:05

Меня заинтересовал 1 код и 2 код.Вопрос 1 структура есть а в структуре есть две структуры .А что в этих структурах?.2 код Это пункты меню? В скопках что указано код для регулировки ? Или что А где же вывод на экран?

Добавлено after 7 minutes 33 seconds:
Код:
menuitem mainmenu={{0x41, 0xBC, 0xBE, 0xBB, 0xB8, 0xBF, 0x79, 0xE3, 0x61, 0x20, 0x79, 0xE3, 0x61, 0x70, 0x61, 0x3A, 0x00}, 0, 65000, 0, 0, 0, NULL, NULL, NULL, 0};
menuitem cortres={{0xA8, 0x6F, 0x70, 0x6F, 0xB4, 0x20, 0x4B, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, 0, 100000, 5000, 5000, 100, NULL, NULL, NULL, 1};
menuitem voltres={{0xA8, 0x6F, 0x70, 0x6F, 0xB4, 0x20, 0x48, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, 1, 4000, 500, 500, 50, NULL, NULL, NULL, 2};
menuitem blanktime={{0x42, 0x70, 0x65, 0xBC, 0xC7, 0x20, 0xB4, 0xBB, 0x79, 0x78, 0x6F, 0xBF, 0xC3, 0x3A, 0x20, 0x20, 0x00}, 0, 1000, 30, 30, 1, NULL, NULL, NULL, 3};
menuitem dynamic={{0xE0, 0xB8, 0xBD, 0x61, 0xBC, 0xB8, 0xBA, 0x61, 0x20, 0xB8, 0xB4, 0x70, 0xC3, 0x3A, 0x20, 0x20, 0x00}, 0, 1, 0, 0, 1, NULL, NULL, NULL, 4};
menuitem channels={{0x4B, 0x61, 0xBD, 0x61, 0xBB, 0x6F, 0xB3, 0x20, 0xB3, 0x78, 0x6F, 0xE3, 0x61, 0x3A, 0x20, 0x20, 0x20}, 1, 2, 1, 1, 1, NULL, NULL, NULL, 5};
menuitem learn={"Start learning? ", 0, 1, 0, 0, 1, NULL, NULL, NULL, 6}; //запас
menuitem soundsample={"Sound sample №:", 0, 1, 0, 0, 1, NULL, NULL, NULL, 7};
menuitem *curitem;

Вот этот пункт. А также последняя строка.

Добавлено after 15 minutes 33 seconds:
Код:
int32_t save()
{
   curitem->oldvalue=curitem->value;
   FramStoreValue(curitem->value, curitem->id);
   LedOn(3, 1000);
   return 0;
};

Указатель без"&" ,будет ли он работать.И функция внутри функции а где она?

Добавлено after 8 minutes 52 seconds:
Код:
cortres.left=&channels;
cortres.right=&blanktime;
cortres.action=&save;
cortres.oldvalue=FramLoadValue(cortres.id);
cortres.value=cortres.oldvalue;

blanktime.right=&dynamic;
blanktime.left=&cortres;
blanktime.action=&save;
blanktime.oldvalue=FramLoadValue(blanktime.id);
blanktime.value=blanktime.oldvalue;

Я не спец по указателям по меню.Вот эти две структуры я не вижу.

Добавлено after 14 minutes 31 second:
Код:
mainmenu.left=&cortres;
mainmenu.right=&blanktime;

И вот разименование структуры элемента .А где сами структуры.
Код:
struct
{
   volatile uint16_t Ua;
   volatile  uint16_t Ub;
   volatile  uint16_t Uc;
   volatile  uint16_t Ia;
   volatile  uint16_t Ib;
   volatile  uint16_t Ic;
}par,*par_p;
   par_p=&par;
   

или я не так понимаю .Это мой пример.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 10:35:33

>TEHb< писал(а):   struct   menuitem   *left;           //соседнее меню слева
   struct   menuitem   *right;        //соседнее меню справа

Вот это? Это не сами структуры, это лишь поле, содержащее ссылку на другой элемент того же типа. Указатель. По факту просто адрес другого экземпляра структуры. Собственно, в этом и заключается
ioan dobrev писал(а):меню на указателях




ioan dobrev писал(а):В скопках что указано

ioan dobrev писал(а):{0x41, 0xBC, 0xBE, 0xBB, 0xB8, 0xBF, 0x79, 0xE3, 0x61, 0x20, 0x79, 0xE3, 0x61, 0x70, 0x61, 0x3A, 0x00}

Вот это? Это поле
>TEHb< писал(а):char      name[17];  //выводимое имя пункта

А в шестнадцатеричном виде потому что это номера кириллических символов в знакосинтезирующем экранчике 1602. А сам вывод это совершенно отдельная независимая функция. Она берёт значения из curitem и выводит уже их.
А вот сам *curitem это ссылка на текущий пункт меню. И эта ссылка подменяется по мере надобности.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 10:46:25

Ну хорошо я как аматор спрошу вас.Вот эта строчка.
Код:
cortres.right=&blanktime;

Я имею ввиду с правой стороны что это функция или переменная? если переменная то у меня.
Код:
/nastroyki.flag_obriv_a=&c;

Пишет Cubeide ошибку.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 10:57:14

Справа это фактически указатель на пункт меню (структура) blanktime. То есть даже и не переменная как таковая, а адрес в памяти. Чтобы такое присвоение получалось элемент right структуры menuitem объявлен как
Код:
struct   menuitem   *right;

То есть мы сразу говорим, что это ссылка на структуру типа menuitem. Потом берём blanktime, который имеет тип menuitem, и присваиваем его адрес полю right.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 11:04:34

Код:
char      name[17];

Так это у вас буфер Для LCD?.
А то пункты меню?.Но я не увидел Какие кнопки какие уменьшают или увеличивают параметры в меню?Покажите.Если это буфер то как он выводит пункты меню?

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 11:16:02

Функция вывода на экран это совершенно отдельная независимая функция. К организации меню она не относится. name это по сути просто строка с выводимым названием меню.
ioan dobrev писал(а):какие уменьшают или увеличивают параметры в меню

Так вот же:
>TEHb< писал(а):   if(up()){
      curitem->value+=curitem->step;
      if(curitem->value > curitem->max){curitem->value = curitem->max;};
      presstime=millis;
      redraw=1;
      };

Если каким-либо способом пришла команда на увеличение параметра (кнопка, ДУ, генератор случайных чисел, не столь важно), то происходит увеличение value в указанных пределах с указанным шагом. Конкретно в данном случае функция UP проверяет состояние ножки. Так что кнопки одновременно нажимать в таком алгоритме нельзя. Но правильный опрос кнопок это опять-таки отдельная задача.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 11:34:59

Код:
UP - верх .Doun- вниз

Это шагаете вниз и вверх? А допустим есть какой то параметр G в меню как бы вы записали G++; G--?.А эти символы .Покажите как вы выводите на LCD?Много вопросов.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 11:51:37

ioan dobrev писал(а):какой то параметр G

Объявил бы ещё одну переменную menuitem Gtune и уже внутри неё Gtune.value и устанавливал. И в любом месте программы где надо было бы использовать это значение уже брал бы Gtune.value .
ioan dobrev писал(а):Покажите как вы выводите на LCD?

Так это же вообще отдельная задача. Ну вот так
Код:
      utoa(curitem->value, string2, 10);
      stringlenght=0;
      while(string2[stringlenght]){stringlenght++;};
      for(stringcounter=16; stringcounter>=0; stringcounter--)
         {
         if (stringlenght>=0){string2[stringcounter]=string2[stringlenght]; stringlenght--;}
         else {string2[stringcounter]=20;};
         };
      LCD1602_PrintStringOfPosition(0, curitem->name);
      LCD1602_PrintStringOfPosition(16, string2);

Вначале преобразование числа в десятичную строку, потом что-то про выравнивание строк или вроде того. Не помню уже. А потом вывод библиотечной функцией. Первой строкой название пункта меню (то самое поле name), а второй строкой текущее значение параметра.

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 12:00:13

Код:
utoa
а sprintf как вывести.?

Re: Меню в stm32 & LCD

Чт ноя 09, 2023 12:04:01

Не имею ни малейшего понятия.
Ответить