Создание многоуровневого графического меню
- Войдите на сайт для отправки комментариев
Ср, 15/04/2020 - 11:03
Помогите допилить многоуровневое меню. Само меню работает, но с под меню не могу разобраться, как его реализовать. Код прилагаю
#include <SPI.h> // библиотека для работы SPI (дисплей)
#include <TFT_eSPI.h> // библиотека дисплея
#include "GyverEncoder.h" // библиотека энкодера
#import "menu1.h" // иконка 1 пункта меню
#import "menu2.h" // иконка 2 пункта меню
#import "menu3.h" // иконка 3 пункта меню
#import "menu4.h" // иконка 4 пункта меню
#import "menu5.h" // иконка 5 пункта меню
#import "menu6.h" // иконка 6 пункта меню
#import "menu11.h" // иконка подменю 1 1
#import "menu12.h" // иконка подменю 1 2
// ---------------------------------------- МОДУЛЬ ДИСПЛЕЯ -----------------------------------------------------------
#define lightOFF 5 // пин подсветки дисплея
uint16_t selectcolor = 0xFEC0; // цвет выделения пункта меню
TFT_eSPI tft = TFT_eSPI(); // создаем объект tft
TFT_eSprite timespriteON = TFT_eSprite(&tft); // создаем спрайт для обновления настройки времени включения освещения
TFT_eSprite timespriteOFF = TFT_eSprite(&tft); // создаем спрайт для обновления настройки времени включения освещения
TFT_eSprite luxspriteON = TFT_eSprite(&tft); // создаем спрайт для обновления настройки включения освещения по датчику освещенности
TFT_eSprite luxspriteOFF = TFT_eSprite(&tft); // создаем спрайт для обновления настройки выключения освещения по датчику освещенности
TFT_eSprite waterspriteONm = TFT_eSprite(&tft);
TFT_eSprite waterspriteONHUMa = TFT_eSprite(&tft);
TFT_eSprite waterspriteONa = TFT_eSprite(&tft);
// ---------------------------------------- МОДУЛЬ ЭНКОДЕРА -----------------------------------------------------------
#define CLK 14 // пины энкодера
#define DT 27 // пины энкодера
#define SW 26 // пины энкодера
Encoder enc1(CLK, DT, SW); // настраиваем пины энкодера
byte menu =1; // обозначаем переменную пунктов меню
byte menuu =1;
//***************************************НАЧАЛО ПРОГРАММЫ***************************************************************
void setup () {
enc1.setType(TYPE2); // устанавливаем тип энкодера
enc1.setTickMode(AUTO); // устанавливаем режим энкодера AUTO
tft.init(); // запускаем дисплей
tft.setRotation(1); // поворачиваем изображение на дисплее
tft.fillScreen(TFT_BLACK); // закрашиваем дисплей в черный цвет
tft.setSwapBytes(true);
updateMenu(); // выполняем меню
}
//-------------------------------------ЦИКЛИЧЕСКАЯ ЧАСТЬ ПРОГРАММЫ-----------------------------------------------------------
void loop() {
if (enc1.isRight()) { // если энкодер вправо
menu++; // то выбираем следующий пункт меню ++
updateMenu(); // отрисовываем меню заново
while (enc1.isRight());
}
if (enc1.isLeft()) { // если энкодер влево
menu--; // то выбираем предыдущий пункт меню --
updateMenu(); // отрисовываем меню заново
while (enc1.isLeft());
}
if (enc1.isPress()) { // при нажатии на энкодер включаем дисплей
executeAction(); // переходим в блок выполнения
updateMenu();
while (enc1.isPress());
}
}
//-------------------------------------------ФУНКЦИЯ ВЫДЕЛЕНИЯ ЭЛЕМЕНТА МЕНЮ--------------------------------------------------
void select (uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t selectcolor) {
tft.drawRect(x0, y0, w, h, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга
tft.drawRect(x0+1, y0+1, w-2, h-2, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга
tft.drawRect(x0+2, y0+2, w-4, h-4, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга
tft.drawRect(x0+3, y0+3, w-6, h-6, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга
tft.drawRect(x0+4, y0+4, w-8, h-8, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга
}
//------------------------------------------------ ФУНКЦИЯ ОТРИСОВКИ МЕНЮ --------------------------------------------------
void updateMenu(){
switch (menu) {
case 0:
menu = 1;
break;
case 1:
tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню
tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню
tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню
tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню
tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню
select(1, 8, 50,52, selectcolor); // выделяем 1 пунет меню
break;
case 2:
tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню
tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню
tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню
tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню
tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню
select(56, 8, 50,52, selectcolor); // выделяем 2 пунет меню
break;
case 3:
tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню
tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню
tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню
tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню
tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню
select(110, 8, 50,52, selectcolor); // выделяем 3 пунет меню
break;
case 4:
tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню
tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню
tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню
tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню
tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню
select(1, 68, 50,52, selectcolor); // выделяем 4 пунет меню
break;
case 5:
tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню
tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню
tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню
tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню
tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню
select(56, 68, 50,52, selectcolor); // выделяем 5 пунет меню
break;
case 6:
tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню
tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню
tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню
tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню
tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню
select(110, 68, 50,52, selectcolor); // выделяем 6 пунет меню
break;
case 7:
menu = 6;
break;
}
}
//----------------------------------ПОДМЕНЮ 1--------------------------------------------------------
void submenu1(){
tft.fillScreen(TFT_BLACK);
switch (menuu) {
case 0:
menuu = 1;
break;
case 1:
tft.pushImage(1, 8, 50, 52, menu11); // 1й пункт подменю
tft.pushImage(56 ,8, 50, 52, menu12); // 2й пункт подменю
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт подменю
select(1, 8, 50,52, selectcolor); // выделяем 1 пунет подменю
break;
case 2:
tft.pushImage(1, 8, 50, 52, menu11); // 1й пункт подменю
tft.pushImage(56 ,8, 50, 52, menu12); // 2й пункт подменю
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт подменю
select(56, 8, 50,52, selectcolor); // выделяем 2 пунет подменю
break;
case 3:
tft.pushImage(1, 8, 50, 52, menu11); // 1й пункт подменю
tft.pushImage(56 ,8, 50, 52, menu12); // 2й пункт подменю
tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт подменю
select(110, 8, 50,52, selectcolor); // выделяем 3 пунет подменю
break;
case 4:
menuu = 3;
break;
if (enc1.isRight()) { // если энкодер вправо
menuu++; // то выбираем следующий пункт подменю ++
submenu1(); // отрисовываем меню заново
while (enc1.isRight());
}
if (enc1.isLeft()) { // если энкодер влево
menuu--; // то выбираем предыдущий пункт подменю --
submenu1(); // отрисовываем меню заново
while (enc1.isLeft());
}
if (enc1.isPress()) { // при нажатии на энкодер включаем дисплей
// executeAction(); // переходим в блок выполнения
tft.fillScreen(TFT_BLACK);
tft.drawString("Execute sub 1 1",5,5);
delay(5000);
submenu1();
while (enc1.isPress());
}
}
}
//*****************************БЛОК ВЫПОЛНЕНИЯ*********************************************************
void executeAction() { // фунция выполнения пунктов меню
switch (menu) {
case 1:
submenu1(); // переход в подменю 1 1
break;
case 2:
action2(); // выполнение 2го пункта меню
break;
case 3:
action3(); // выполнение 3го пункта меню
break;
case 4:
action4(); // выполнение 4го пункта меню
break;
case 5:
action5(); // выполнение 5го пункта меню
break;
case 6:
action6(); // выполнение 6го пункта меню
break;
}
}
// ********************************** БЛОКИ ИСПОЛНЕНИЯ ПУНКТОВ МЕНЮ ******************************************************
// ------------------------------------------ 1й Пункт меню --------------------------------------------------------------
void action1() {
tft.fillScreen(TFT_BLACK);
tft.setCursor (10, 10);
tft.print(">Executing #1");
digitalWrite(13, HIGH);
delay(2000);
digitalWrite(13, LOW);
tft.fillScreen(TFT_BLACK);
}
// ------------------------------------------ 2й Пункт меню --------------------------------------------------------------
void action2() {
tft.fillScreen(TFT_BLACK);
tft.setCursor (10, 10);
tft.print(">Executing #2");
digitalWrite(13, HIGH);
delay(2000);
digitalWrite(13, LOW);
tft.fillScreen(TFT_BLACK);
}
//------------------------------------------------------------------------------------------------------------------------------------
void action3() {
tft.fillScreen(TFT_BLACK);
tft.setCursor (10, 10);
tft.print(">Executing #3");
digitalWrite(13, HIGH);
delay(2000);
digitalWrite(13, LOW);
tft.fillScreen(TFT_BLACK);
}
void action4() {
tft.fillScreen(TFT_BLACK);
tft.setCursor (10, 10);
tft.print(">Executing #4");
delay(2000);
tft.fillScreen(TFT_BLACK);
}
void action5() {
tft.fillScreen(TFT_BLACK);
tft.setCursor (10, 10);
tft.print(">Executing #5");
delay(2000);
tft.fillScreen(TFT_BLACK);
}
void action6() {
tft.fillScreen(TFT_BLACK);
tft.setCursor (10, 10);
tft.print(">Executing #6");
delay(2000);
tft.fillScreen(TFT_BLACK);
}
https://ibb.co/m8DrRs3
выглядит так. Проблема в том, что при переходе в под меню 1.1 программа вываливается в основное меню.
с под меню не могу разобраться
А оно так не делается. С таким походом Вы его на 99,99% не сделаете, а на оставшиеся 0,01% программа получится получится такой огромной, сложной и запутанной, что вероятность отладки до приемлемой надёжности практически неотличима от 0. По крайней мере, я бы не справился и даже браться бы не стал.
Многоуровневое меню делается не в лоб, а через дерево элементов. Тогда код остаётся в разумных размерах, разумной понятности, и всё получается. дерево элементов можно делать по-разному, но по-любому это должно быть дерево.
Хотел создавать отдельную тему тоже с многоуровневым меню, но меня опередили. В сети я нашел очень простой, на мой взгляд, вариант одноуровневого меню, самое главное что оно уже функциональное. Но опыта мало и не знаю как правильно сделать навигацию вверх/вниз в подменю. Возможно здесь то что тебе нужно.
#include <LiquidCrystal_I2C.h> // подключаем библиотеку дисплея #include <Wire.h> // подключаєм библиотеку LiquidCrystal_I2C lcd (0x3F,16,2); // указиваем тип дисплея (конвектора) int m=0; // переменная для экранов меню int p1=0; // переменная 1 int p2=0; // переменная 2 int p3=0; // переменная 3 #define nextPin 46 // кнопка меню на 6 входе ENTER #define prevPin 42 // кнопка возврата ESC #define upPin 48 // увеличение значения отображаемого параметра + #define downPin 44 // уменьшение значения - #define enterPin 52 #define escPin 50 boolean buttonnextWasUp = true; boolean buttonprevWasUp = true; boolean buttonupWasUp = true; boolean buttondownWasUp = true; boolean buttonenterWasUp = true; boolean buttonescWasUp = true; boolean ledEnabled = false; void setup() { // Установка пинов как входов pinMode(nextPin, INPUT_PULLUP); pinMode(prevPin, INPUT_PULLUP); pinMode(upPin, INPUT_PULLUP); pinMode(downPin, INPUT_PULLUP); pinMode(enterPin, INPUT_PULLUP); pinMode(escPin, INPUT_PULLUP); Serial.begin(9600); lcd.init(); // инициализация LCD lcd.backlight(); // включаем подсветку // Вывод приветствия lcd.print( "MY PROGECT" ); // задержка delay (1000); } void loop () { boolean buttonnextIsUp = digitalRead(nextPin); boolean buttonprevIsUp = digitalRead(prevPin); boolean buttonupIsUp = digitalRead(upPin); boolean buttondownIsUp = digitalRead(downPin); boolean buttonenterIsUp = digitalRead(enterPin); boolean buttonescIsUp = digitalRead(escPin); //обработка нажатия кнопки enter if (buttonenterWasUp && !buttonenterIsUp) { delay(10); buttonenterIsUp = digitalRead(enterPin); if (!buttonenterIsUp) { if (m==3) { m=30; } delay(100); lcd.clear(); } } // обработка нажатия кнопки esc if (buttonescWasUp && !buttonescIsUp) { delay(10); buttonescIsUp = digitalRead(escPin); if (!buttonescIsUp) { if (m==30) { m=3; } else if(m==31) { m=3; } else if(m==32) { m=3; } delay(100); lcd.clear(); } } //Обработка нажатия кнопки вниз if (buttonnextWasUp && !buttonnextIsUp) { delay(10); buttonnextIsUp = digitalRead(nextPin); if (!buttonnextIsUp) { m++; if (m>4) { m=0; } delay(100); lcd.clear(); } } //Обработка нажатия кнопки вверх if (buttonprevWasUp && !buttonprevIsUp) { delay(10); buttonprevIsUp = digitalRead(prevPin); if (!buttonprevIsUp) { m--; if (m<0) { m=4; } delay(100); lcd.clear(); } } // Обработка нажатия для р1 + if (buttonupWasUp && !buttonupIsUp) { delay(10); buttonupIsUp = digitalRead(upPin); if (!buttonupIsUp && m==1) { p1++; if (p1>10) { p1=0; } delay (100); lcd.setCursor(5, 1); lcd.print(" "); } } // Обработка нажатия для р1 - if (buttondownWasUp && !buttondownIsUp) { delay(10); buttondownIsUp = digitalRead(downPin); if (!buttondownIsUp && m==1) { p1--; if (p1<0) { p1=10; } delay (100); lcd.setCursor(5, 1); lcd.print(" "); } } // Обработка нажатия для р2 + if (buttonupWasUp && !buttonupIsUp) { delay(10); buttonupIsUp = digitalRead(upPin); if (!buttonupIsUp && m==2) { p2++; if (p2>10) { p2=0; } delay (100); lcd.setCursor(5, 1); lcd.print(" "); } } // Обработка нажатия для р2 - if (buttondownWasUp && !buttondownIsUp) { delay(10); buttondownIsUp = digitalRead(downPin); if (!buttondownIsUp && m==2) { p2--; if (p2<0) { p2=10; } delay (100); lcd.setCursor(5, 1); lcd.print(" "); } } //вывод меню if (m==0) { lcd.setCursor(0, 0); lcd.print( "Time" ); lcd.setCursor(14, 0); lcd.print( "<-" ); lcd.setCursor(0, 1); lcd.print( "Measurement" ); } else if (m==1) { lcd.setCursor(0, 0); lcd.print( "Measurement" ); lcd.setCursor(14, 0); lcd.print( "<-" ); lcd.setCursor(0, 1); lcd.print( "Setpoint trip" ); } else if (m==2) { lcd.setCursor(0, 0); lcd.print( "Setpoint trip" ); lcd.setCursor(14, 0); lcd.print( "<-" ); lcd.setCursor(0, 1); lcd.print( "Configuration"); } else if (m==3) { lcd.setCursor(0, 0); lcd.print( "Configuration" ); lcd.setCursor(14, 0); lcd.print( "<-" ); lcd.setCursor(0, 1); lcd.print( "Registration"); } else if (m==4) { lcd.setCursor(0, 0); lcd.print( "Registration"); lcd.setCursor(14, 0); lcd.print( "<-" ); } if (m==30) { lcd.setCursor(0, 0); lcd.print( "MOTOR1" ); lcd.setCursor(14, 0); lcd.print( "<-" ); lcd.setCursor(0, 1); lcd.print( "MTZ2" ); } else if (m==31) { lcd.setCursor(0, 0); lcd.print( "MOTOR2" ); lcd.setCursor(14, 0); lcd.print( "<-" ); lcd.setCursor(0, 1); lcd.print( "MTZ3" ); } else if (m==32) { lcd.setCursor(0, 0); lcd.print( "MOTOR3" ); lcd.setCursor(14, 0); lcd.print( "<-" ); } buttonupWasUp = buttonupIsUp; buttondownWasUp = buttondownIsUp; buttonnextWasUp = buttonnextIsUp; buttonprevWasUp = buttonprevIsUp; buttonenterWasUp = buttonenterIsUp; buttonescWasUp = buttonescIsUp; }Можете ткнуть пальцем, хоть куда копать. примеры или еще что...
Oscar. поправте меня, но по-моему понятия "одноуровневое меню" не предполагает никаких "подменю"... или я не прав?
Что касается кода, судя по огромному числу операторов delay() - вряд ли его писал продвинутый автор...
Oscar. поправте меня, но по-моему понятия "одноуровневое меню" не предполагает никаких "подменю"... или я не прав?
мм.. впринципе Вы правы, но в конце есть последние три m=30 ... 32. Это я пытался прикрутить второй уровень что бы сделать его многоуровневым, но не получается сделать прокрутку вверх/вниз. Я пытался сделать по аналогии как и для первого уровня, но не работает.
Что касается кода, судя по огромному числу операторов delay() - вряд ли его писал продвинутый автор...
Я так понимаю что автор это использовал для борьбы с дребезгом контактов, но в любом случае контроллер это не грузит.
Я так понимаю что автор это использовал для борьбы с дребезгом контактов, но в любом случае контроллер это не грузит.
delay(100) уже ПОСЛЕ обработки КАЖДОГО нажатия? - а что оно делает кроме загрузки контроллера, по вашему?
Второй delay да, лишний, я его не увидел.
Так у меня тоже меню работает, а вот под меню в данном варианте Нет. В цикле программы идет привязка к основному меню. Здесь действительно нужен другой подход.
Выглядеть должно примерно так:
void loop(){ switch(menu_item){ case MAIN_SCREEN: draw_main(); //Сюда интерфейс } break; case SETUP_SCREEN: draw_setup(); break; case TIME_MENU: set_time(); break; case TEMP_MENU: set_temp(); break; case HEAT_MENU: set_heat(); break; case VENT_MENU: set_vent(); break; case HUM_MENU: set_hum(); break; case MOIST_MENU: set_moist(); break; case CLOCK_MENU: set_clock(); break; }//end switch menu_item }Внутри каждого подменю такой же интерфейс и switch с вариантами .
Т.е. когда menu_item =MAIN_SCREEN, мы видим главный экран и кнопками(энкодером и тп) меняем значение курсора и переменную. По кнопке ОК изменяем значение menu_item и соответственно видим другую отрисовку и уже в другом, вложенном switch меняем значение другой переменной(положение курсора)
Можете ткнуть пальцем, хоть куда копать. примеры или еще что...
Странный Вы человек. Я же Вам написал, что это делается на деревьях. Куда Вам ещё тыкать? Ну, ладно, если так хотите - пожалуйста.
Kakmyc
Как в вашем случае выглядит цикл программы? с опросом кнопок. Просто если кнопка вниз то осн меню --. Если вверх, то осн меню ++. дальше выбрали подменю. вверх под меню++, вниз под меню --. Как вы в void loop будете опрашивать кнопки? Сразу для меню и подменю и под подменю? Вы привели аналог моего кода.
Тихо. Тут религиозные фанатики "правильного кода" сейчас нас с тобой заклюют, но я попробую тебе помочь.
Добавь переменную, напр. SubMenu
void loop() { if (enc1.isRight()) { // если энкодер вправо if (SubMenu == 0) {// то выбираем следующий пункт меню ++ menu++; updateMenu(); // отрисовываем меню заново } else { SubMenu++; updateSubMenu(); // отрисовываем меню заново } while (enc1.isRight()); } .... }Дальше, думаю ты догадаешься что и как поправить.
Дальше, думаю ты догадаешься что и как поправить.
Ну, да. А у подменю могут быть свои подменю. А одно меню (одного уровня) может содержать как терминальные элементы, так и подменю. И так на каждый случай добавляем переменные. Если меню содержит хотя бы два десятка элементов, то отладить такое будет невозможно.
Зачем обязательно придумывать костыли, если можно сделать системно и правильно? Это спорт такой?
Зачем обязательно придумывать костыли, если можно сделать системно и правильно? Это спорт такой?
ждем выступление вавгата "а ТС именно так и заказывал" :)
Kakmyc
Как в вашем случае выглядит цикл программы? с опросом кнопок. Просто если кнопка вниз то осн меню --. Если вверх, то осн меню ++. дальше выбрали подменю. вверх под меню++, вниз под меню --. Как вы в void loop будете опрашивать кнопки? Сразу для меню и подменю и под подменю? Вы привели аналог моего кода.
Я не знаю, как у вас опрашиваются кнопки.
Но в моем варианте, как обычно.
Только вот результаты используются в одном меню , в том которое на данный момент является активным.
int _key; int menu_page; enum MAIN_MENU {main_menu,menu1,menu2,menu3}; enum SUBMENU1{main_submenu1,submenu11,submenu12,submenu13,submenu1_exit}; enum SUBMENU2{main_submenu2,submenu21,submenu22,submenu23,submenu2_exit}; int key(){//опрос кнопки int val=0;//абсурдное значение , на самом деле тут результат опроса кнопки return val ; } void f_menu1(){ static byte menu_subpage=1; switch(menu_subpage){ case main_submenu1: static byte val=0; //опустим подробности опроса, пусть входящие значения будут трех типов +/-/ок if('+')val++; if('-')val--; val=constrain(val,1,4); if("ok")menu_subpage=val; break; case submenu11: //submenu11 func break; case submenu12: //submenu12 func break; case submenu13: //submenu13 func break; case submenu1_exit: menu_page=main_menu; break; } } void f_menu2(){ } void f_menu3(){ } void setup(){ } void loop(){ int _key=key(); switch(menu_page){ case main_menu: static byte val=0; //опустим подробности опроса, пусть входящие значения будут трех типов +/-/ок if('+')val++; if('-')val--; val=constrain(val,1,3); if("ok")menu_page=val; break; case menu1: f_menu1(); break; case menu2: f_menu2(); break; case menu3: f_menu3(); break; } }ну раз все побежали показывать свой г... код :) то я тоже продемонстрирую
Я в одном из проектов описывал все строчки меню единообразно
typedef struct PROGMEM { const char Text[MENU_NAME_SIZE]; const uint8_t Next; const uint8_t Type; } menuItem;и потом собирал из таких строчек все меню со всеми вложениями:
const menuItem menustack[] PROGMEM = { {"Settings menu:", 0, SUB_MENU}, {"Select shunt", 1, MENU_LINE}, {"Tune shunt", COM_TUNE,MENU_LINE}, {"Save settings", 2 ,MENU_LINE}, {"Clear settings", 3 ,MENU_LINE}, {"Exit", COM_EXIT,MENU_LINE}, {"Shunt list:",1, SUB_MENU}, {"1 Ohm",COM_SEL_SHUNT, MENU_LINE}, {"0.1 Ohm",COM_SEL_SHUNT, MENU_LINE}, {"0.05 Ohm",COM_SEL_SHUNT, MENU_LINE}, {"0.01 Ohm",COM_SEL_SHUNT, MENU_LINE}, {"0.005 Ohm",COM_SEL_SHUNT, MENU_LINE}, {"<< back", 0 ,MENU_LINE}, {"Save current shunt & tune?", 2, SUB_MENU}, {"Save", COM_SAVE, MENU_LINE}, {"Cancel", 0 ,MENU_LINE}, {"Clear current shunt & tune?", 3, SUB_MENU}, {"Clear", COM_CLEAR, MENU_LINE}, {"Cancel", 0 ,MENU_LINE}, {"",0,MENU_END} };для наглядности вставил пустые строки между подменю.
Цифра после текста означает id элемента, на который указывает строчка. Если такому id соответвует строка с типом SUB_MENU -значит переходим на уровень ниже (или выше). Если для такого id подменю нет - значит это просто действие.
Например, строчка
{"Select shunt", 1, MENU_LINE},указывает на подменю
{"Shunt list:",1, SUB_MENU},а строка
{"Cancel", 0 ,MENU_LINE},указывает на меню с ID =0, то есть выход на верхнй уровень
Топорно конечно, зато любое кол-чество дополнительный уровней и строчек меню можно добавить независимо от других.
В своё время прочитал http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html проникся, адаптировал под себя и с тех пор использую во всех местах, где нужно многоуровневое меню. Перегружено конечно, но за то очень легко сделать любой глубины и ширины, при этом вставить в любую точку дополнительный пункт даже не надо ничего переделывать. Потом появилось micromenu V2 https://github.com/abcminiuser/micromenu-v2 обещали что легче, но руки посмотреть не дошли.
typedef struct PROGMEM { const char Text[MENU_NAME_SIZE]; const uint8_t Next; const uint8_t Type; } menuItem;любое кол-чество дополнительный уровней и строчек меню можно добавить независимо от других.
Вот и я ж про тоже. Деревья - они такие.
Я бы еще в дополнение к next, добавил бы ещё prev - тогда удаление на лету - как два пальца получается.
ЕвгенийП не совсем пойму, этот пример для построения текстового меню. У меня графическое.
этот пример
Какой? Я не давал никаких примеров.
этот пример для построения текстового меню. У меня графическое.
С точки зрения организации данных разницы нет никакой от слова совсем. У любого меню есть терминальные элементы и подменю. У любого элемента (кроме корневого) есть "родитель". У большинства элементов есть "братья и сёстры". Организация данных всегда одинаковая. А уж как Вы там его показываете, командой "showText" или "showImage" - это вопрос №321.
Если хотите грамотно делать меню, изучите работу с деревьями. Так в лоб, с какими-то бессистемными переменными-флагами Вы этого не сделаете.
Сорри за тупость, но я не понял. дерево своего меню нарисовал:
дальше как я понял, мы описываем меню.
typedef struct PROGMEM{ void *Next; void *Previous; void *Execute; } menuItem;А вот дальше я нифига не понял.
дальше как я понял, мы описываем меню.
typedef struct PROGMEM{ void *Next; void *Previous; void *Execute; } menuItem;А вот дальше я нифига не понял.
Этого маловато. Я сейчас Вам набросаю общих идей в виде псевдокода, но именно "псевдо". Уж простите, запускать и отлаживать сейчас некогда, а кроме того, я тут за ужином немного поборолся с вирусом (дезинфицирующего срецтва принял), но идейно как это делать покажу (на примере Вашего дерева). Щас ... , возвращайтесь через часик.
Ну, вот, смотрите.
Я сделал некое универсальное меню, в которое напихал всё, что спьяну вспомнил. Для любого реального проекта, здесь много лишнего и ненужного, но я хотел показать как делаются разные вещи.
Здесь можно создавать меню, показывать его с любым уровнем вложенности, на лету добавлять и удалять элементы.
На все эти возможности есть комментарии и примеры. Читайте комментарии, запускайте примеры, если чего – спрашивайте. Для примера взято Ваше меню, но я добавил ещё один уровень.
Сразу предупреждаю, не проверял, т.к. в данный момент не могу, но на UNO по идее должно работать, разве что опечатка какая – тогда поправим.
Запускайте. смотрите примеры, как сделано, разбирайтесь, если что - спрашивайте, но не обещаю насчёт сегодня - что-то я сегодня перебрал с дезинфекцией :-(
struct SMenuItem { int id; // уникальный идентификатор данного элемента SMenuItem * prev; // следующий элемент данного урвоня (nullptr - если этот - последний) SMenuItem * next; // предыдущий элемент данного урвоня (nullptr - если этот - первый) SMenuItem * parent; // адрес родительского элемента (nullptr - если нет родителей) SMenuItem * children; // адрес списка элементов "подменю" (nullptrll - если это лист) const char * itemText; // Название данного элемента (тут может быть не текст, а адрес картинки. Функция show знает, что с этим делать) // // Показать данный элемент void show(void) { for (SMenuItem * ptr = parent; ptr; ptr = ptr->parent) { if (ptr->parent) Serial.print(" "); } Serial.println(itemText); } // // Показать всех детей данного элемента // Параметр: глубина показа "внуков". // Если 1 - только дети, если 2 - то и внуик и т.д. void showChildren(const int showGrandChilren = 1) { if (! showGrandChilren) return; for (SMenuItem * ptr = children; ptr; ptr = ptr->next) { ptr->show(); ptr->showChildren(showGrandChilren - 1); } } // // выполнить действие, когда этот элемент выбран void action(void) { Serial.print("*** The menu \""); Serial.print(itemText); Serial.print("\" is executed"); } // // Удаление данного элемент из меню void removeMe(void) { // // Если есть следующий элемент, то // делаем мой предыдущий, его предыдущим if (next) next->prev = prev; // // Если есть предыдущий // то делаем наш следущий, его следущим // Иначе говорим родителю, что наше next - его первый ребёнок. if (prev) prev->next = next; else parent->children = next; } // // Вставить себя как первого ребёнка объекта _parent void insertAsFirstChild(SMenuItem & _parent) { // // Вставляем первого ребёнка после себя, а себя делаем первым ребёнком next = _parent.children; prev = nullptr; _parent.children = this; } // // Вставить себя после объекта _prev void insertAfter(SMenuItem & _prev) { // // Ставим себя следующим объекту _prev, а его следующего - своим следующим next = _prev.next; _prev.next = this; } // // Конструктор - создать элемент SMenuItem(const char * const _itemText, SMenuItem * _prev = nullptr, SMenuItem * _parent = nullptr) { itemText = _itemText; prev = _prev; parent = _parent; children = nullptr; next = nullptr; // // Если у нас есть родитель if (parent) { // если у родителя пока нет детей, записываемся началом списка детей. if (parent->children == nullptr) parent->children = this; } // // Если у нас есть предыдущий элемент if (prev) { // записываемся ему в "следующие" prev->next = this; } } }; // Корневой элемент всего меню. Он обычно невидимый. // он родитель элементов верхнего уровня! SMenuItem m0(""); // у этого нет ни предыдущего, ни родителя SMenuItem m1("Menu1", nullptr, & m0); // у этого нет ни предыдущего SMenuItem m2("Menu2", & m1, &m0); SMenuItem m3("Menu3", & m2, &m0); SMenuItem m4("Menu4", & m3, &m0); SMenuItem m5("Menu5", & m4, &m0); SMenuItem m6("Menu6", & m5, &m0); SMenuItem m11("Menu11", nullptr, & m1);// у этого нет предыдущего, но есть родитель SMenuItem m12("Menu12", & m11, & m1); // у этого есть и предыдущий, и родитель SMenuItem m41("Menu41", nullptr, & m4);// у этого нет предыдущего, но есть родитель SMenuItem m42("Menu42", & m41, & m4); // у этого есть и предыдущий, и родитель SMenuItem m411("Menu411", nullptr, & m41); SMenuItem m412("Menu412", & m411, & m41); SMenuItem m413("Menu413", & m412, & m41); void prompt(const char * const title) { Serial.println (title); while(!Serial.available()); // Ждём ввода while(Serial.available()) Serial.read(); // Вычитываем всё, что есть } void setup() { Serial.begin(115200); Serial.println("Веселье начинается!"); prompt("Печатаем меню целиком. Дави ENTER"); m0.showChildren(1000); prompt("Печатаем три уровня (это тоже, что целиком). Дави ENTER"); m0.showChildren(3); prompt("Печатаем два уровня. Дави ENTER"); m0.showChildren(2); prompt("Печатаем один уровень. Дави ENTER"); m0.showChildren(1); prompt("Удаляем Menu412. Дави ENTER"); m412.removeMe(); m0.showChildren(1000); prompt("Удаляем Menu3. Дави ENTER"); m3.removeMe(); m0.showChildren(1000); prompt("Удаляем Menu1 вместе с детьми. Дави ENTER"); m1.removeMe(); m0.showChildren(1000); prompt("Вставляем Menu3 - в самое начало. Дави ENTER"); m3.insertAsFirstChild(m0); m0.showChildren(1000); prompt("Вставляем Menu1 после Menu3. Дави ENTER"); m1.insertAfter(m3); m0.showChildren(1000); } void loop() { }ЕвгенийП ого! лихо. спасибо, буду разбираться. надеюсь разберусь. Скетч без ошибок, все работает. Я так же по Вашим рекомендациям смотрел в нете построение меню древом. После графического представления меню, идет построение матрицы, которую Вы реализовали в коде. Дети, внуки, правнуки только не понятны. Меню11 и меню12 это дети родителя меню1 или дети родителей меню1-меню6 ?
SMenuItem m0(""); --- согласен, это нулевое меню бога, которое не отображается и служит типа контрольной точки отсчета, у которого нет ни предыдущего ни последующего соседаSMenuItem m1("Menu1", nullptr, & m0); ----- до него ничего нет, справа по идее от него должен быть m2 ??Родитель всегда только один - третий параметр конструктора
SMenuItem m4("Menu4", & m3, &m0); // Родительm4 -> это m0SMenuItem m412("Menu412", & m411, & m41);// Родительm412 -> это m41Вообще, схема ТОЧНО ТАКАЯ как на Вашей картинке с единственной разницей - я добавил три элемента, которых у Вас не было - m411, m412 и m413 - все трое - дети 41.
Поэтому, если Вам непонятно кто чей родитель, смотрите свою картинку или же то, что печатается - там же ясно кто чьи дети - они со сдвигом печатаются - дети под родителем со сдвигом вправо..
SMenuItem m1("Menu1", nullptr, & m0); ----- до него ничего нет, справа по идее от него должен быть m2 ??Перед ним - никого, т.к. у него второй параметр nullptr. А за ним тот, у кого второй параметр m1. Вообще, второй параметр - это имя того, кто перед этим элементом. Вы смотрите на печать и на свою картинку.
Понятно с детьми изложили. Я думал строится все слоями: вначале все пункты меню, 2й слой пункты ПОДменю, 3 слой пункты ПОДпод меню и тд и точка перехода между слоями.
intid; непонятно где этот идентификатор используется.И главное, это вызов.Начало программы. Рисую все пункты меню. Курсор ставлю в позицию меню1. Вызывать так: SMenuItem m1; ??intid; непонятно где этот идентификатор используется.Нигде. Это на вырост. Почти наверняка пригодится в будущем.
И главное, это вызов.
Начало программы. Рисую все пункты меню. Курсор ставлю в позицию меню1. Вызывать так: SMenuItem m1; ??На самом деле, это тоже делается единообразно (всегда одинаково). Рисуете меню. Заводите специальный указатель currentItem и настраиваете его на текущее активное меню:
currentItem = & m1
Через него делаете все переходы и вызовы.
.... блин, перечитал ... сам не понимаю давайте-ка я сейчас тот пример расширю.
Только я не буду добавлять никаких экранов, а сделаю так. Текущий элемент меню будет всегда показываться "звёздочкой". Вместо ENTER вводим цифирь. Означает она следующее:
1 - продвинуться по меню вверх, если есть куда (на том же уровне)
2 - продвинуться вниз, если есть куда (на том же уровне)
3 - перейти на уровень вверх (к родителю)
4 - если это не листик, то перейти на уровень вниз, а если листик, то выполнить этот пункт
Другие числа (и знаки) игнорируются.
Походите по меню туда сюда, убедитесь, что всё работает. Потом попробуйте что-то менять и смотрите, правильно ли Вы поняли программу (адекватно ли она реагирует на Ваши изменения).
И, главное, имейте в виду - любое меню, хоть текстовое, хоть графическое. хоть голосовое - любое делается примерно также. Разница только в функция показа (у меня они называются show).
struct SMenuItem { int id; // уникальный идентификатор данного элемента SMenuItem * prev; // следующий элемент данного урвоня (nullptr - если этот - последний) SMenuItem * next; // предыдущий элемент данного урвоня (nullptr - если этот - первый) SMenuItem * parent; // адрес родительского элемента (nullptr - если нет родителей) SMenuItem * children; // адрес списка элементов "подменю" (nullptrll - если это лист) const char * itemText; // Название данного элемента (тут может быть не текст, а адрес картинки. Функция show знает, что с этим делать) // // Показать данный элемент void show(void) { // ДОПОЛНЕНИЕ - если мы активны, печатаем звёздочку, иначе - пробел Serial.print(iAmActive ? '*' : ' '); for (SMenuItem * ptr = parent; ptr; ptr = ptr->parent) { if (ptr->parent) Serial.print(" "); } Serial.println(itemText); } // // Показать всех детей данного элемента // Параметр: глубина показа "внуков". // Если 1 - только дети, если 2 - то и внуик и т.д. void showChildren(const int showGrandChilren = 1) { if (! showGrandChilren) return; for (SMenuItem * ptr = children; ptr; ptr = ptr->next) { ptr->show(); ptr->showChildren(showGrandChilren - 1); } } // // выполнить действие, когда этот элемент выбран void action(void) { Serial.println("***********************************************"); Serial.print("***** The menu \""); Serial.print(itemText); Serial.println("\" is executed"); Serial.println("***********************************************"); } // // Удаление данного элемент из меню void removeMe(void) { // // Если есть следующий элемент, то // делаем мой предыдущий, его предыдущим if (next) next->prev = prev; // // Если есть предыдущий // то делаем наш следущий, его следущим // Иначе говорим родителю, что наше next - его первый ребёнок. if (prev) prev->next = next; else parent->children = next; } // // Вставить себя как первого ребёнка объекта _parent void insertAsFirstChild(SMenuItem & _parent) { // // Вставляем первого ребёнка после себя, а себя делаем первым ребёнком next = _parent.children; prev = nullptr; _parent.children = this; } // // Вставить себя после объекта _prev void insertAfter(SMenuItem & _prev) { // // Ставим себя следующим объекту _prev, а его следующего - своим следующим next = _prev.next; _prev.next = this; } // // Конструктор - создать элемент SMenuItem(const char * const _itemText, SMenuItem * _prev = nullptr, SMenuItem * _parent = nullptr) { itemText = _itemText; prev = _prev; parent = _parent; children = nullptr; next = nullptr; // // Если у нас есть родитель if (parent) { // если у родителя пока нет детей, записываемся началом списка детей. if (parent->children == nullptr) parent->children = this; } // // Если у нас есть предыдущий элемент if (prev) { // записываемся ему в "следующие" prev->next = this; } // // ДОПОЛНЕНИЕ - мы неактивны iAmActive = false; } // // ДОПОЛНЕНИЯ // bool iAmActive; // Активировать (параметр - true) или деактивировать // Возвращает адрес себя SMenuItem * activate(const bool actDeact) { iAmActive = actDeact; return this; } // Перейти к следующему (если есть) // Возвращает адрес нового (или старого, если не перешли) активного элемента SMenuItem * goNext(void) { // Если есть следующий, то активируем его if (next) { activate(false); // деактивируем себя return next->activate(true); } return this; } // Перейти к предыдущему (если есть) // Возвращает адрес нового (или старого, если не перешли) активного элемента SMenuItem * goPrev(void) { // Если есть предыдущий, то активируем его if (prev) { activate(false); // деактивируем себя return prev->activate(true); } return this; } // Перейти к родителю (если есть) // на самом деле переходим только в том случае, если у родителя есть // ещё и свой родитель, т.к. нам не нужно переходиь к общему прародителю // (в нашем случае к m0) // Возвращает адрес нового (или старого, если не перешли) активного элемента SMenuItem * goParent(void) { // Если есть родитель и у того тоже есть родитель, то активируем родителя if (parent && parent->parent) { activate(false); // деактивируем себя return parent->activate(true); } return this; } // Если нет детей, то выполнить данный пункт // А если есть дети, то перейти к первому ребёнку // Возвращает адрес нового (или старого, если не перешли) активного элемента SMenuItem * goChildOrRun(void) { // Если нет детей, то выполняем данный элемент if (! children) action(); else { activate(false); // деактивируем себя return children->activate(true); } return this; } }; // Корневой элемент всего меню. Он обычно невидимый. // он родитель элементов верхнего уровня! SMenuItem m0(""); // у этого нет ни предыдущего, ни родителя SMenuItem m1("Menu1", nullptr, & m0); // у этого нет ни предыдущего SMenuItem m2("Menu2", & m1, &m0); SMenuItem m3("Menu3", & m2, &m0); SMenuItem m4("Menu4", & m3, &m0); SMenuItem m5("Menu5", & m4, &m0); SMenuItem m6("Menu6", & m5, &m0); SMenuItem m11("Menu11", nullptr, & m1);// у этого нет предыдущего, но есть родитель SMenuItem m12("Menu12", & m11, & m1); // у этого есть и предыдущий, и родитель SMenuItem m41("Menu41", nullptr, & m4);// у этого нет предыдущего, но есть родитель SMenuItem m42("Menu42", & m41, & m4); // у этого есть и предыдущий, и родитель SMenuItem m411("Menu411", nullptr, & m41); SMenuItem m412("Menu412", & m411, & m41); SMenuItem m413("Menu413", & m412, & m41); // // Ввод числа от 1 до 4 // int prompt(void) { int res = 0; while (res < 1 || res > 4) { Serial.println ("Введи число от 1 до 4: "); Serial.println (" 1 - к предыдущему;"); Serial.println (" 2 - к следующему;"); Serial.println (" 3 - к родителю;"); Serial.println (" 4 - к ребёнку или (если нет детей, то выполнить)"); res = Serial.parseInt(); // Вводим число while(Serial.available()) Serial.read(); // Вычитываем всё, что осталось } return res; } void setup() { Serial.begin(115200); Serial.setTimeout(0xFFFFFFFF); Serial.println("Веселье начинается!"); } void loop() { static SMenuItem * activeElement = m1.activate(true); Serial.println("----------------------------------"); m0.showChildren(1000); // Печатаем меню // Обрабатываем комнду // 1 - продвинуться по меню вверх, если есть куда (на том же уровне) // 2 - продвинуться вниз, если есть куда (на том же уровне) // 3 - перейти на уровень вверх (к родителю) // 4 - если это не листик, то перейти на уровень вниз, а если листик, то выполнить этот пункт switch (prompt()) { case 1: activeElement = activeElement->goPrev(); break; case 2: activeElement = activeElement->goNext(); break; case 3: activeElement = activeElement->goParent(); break; case 4: activeElement = activeElement->goChildOrRun(); break; } }Пробуйте. Следите за звёздочкой - она означает активный (выбранный) в данный момент элемент. Как видите, можно ходить по меню и исполнять терминальные элементы.
Кстати, можно на лету добавлять и удалять элементы (как мы делали в прошлом примере), всё продолжает адекватно работать (можете попробовать), однако ... ВНИМАНИЕ!!! Тут есть грабли. Если Вы попытаетесь удалить элемент, который в настоящий момент активен - всё поломается. Чтобы такого не было, надо проверять при удалении не активен ли удаляемый элемент и либо отказываться удалять, либо переводить активность на другой элемент. Но это Вы уж сами. Как переводить активность в этом примере показано (кнопки 1 и 2).
ЕвгенийП
Огромное спасибо. Это почти готовая операционка. Неплохо было бы модеру в шапку приклеить. Если не секрет, сколько осваивали язык?
Если не секрет, сколько осваивали язык?
Пишет, что за день в новом языке разобраться может. Думаю, что он - энопланетянин.
Многие языки по синтаксису и структуре похожи. Мне для того, чтобы перейти с Бейсика на Паскаль тоже немного времени понадобилось. Тк очень похожи.
Если не секрет, сколько осваивали язык?
Я по работе язычник, т.е. я занимаюсь наукой в области языков программирования (кстати, Ворота - тоже). Правда, если смотреть на более узкую специализацию, то языками несколько другого типа, но в контексте любительского форума это совсем несущественно.
Ппц я тупой похоже. Целый день въезжал в то как это дерево структурное работает. Ладно хоть дошло в итоге. Ещё два дня ушло на то, что бы понять, как прикрутить туда функции. Грёбаный синтаксис, какое то написание не совсем очевидное if(curItem->Handler){(*curItem->Handler)();}
Зато теперь понял, что если прикрутить туда какой-нить идентификатор действия, типа :
typedef struct menuItem{ //Blablabla byte identify_num; //blablabla }menuItem; if(currentItem->ok){ switch (currentItem->identify_num){ case 1: //do1 break; case 2: (*currentItem->Handler)(); break; case 3: //do3 break; }можно делать вообще что угодно одним энкодером или тремя кнопками.
Ещё немного и лямбда-функции начнут зохватывать мозг.
Ещё немного и лямбда-функции начнут зохватывать мозг.
Мозг такими темпами не доживёт.
Долго искал причину, почему скачет по меню программа. Оказалось энкодер какашный, программно не фильтруется толком.
лямбда-функции начнут зохватывать мозг.
Ну, уж нет! Эта корова коронавируса и он её доит! И никаким функциям он её не отдаст, будь они хоть лямбда, хоть дзета.
Скоро всем в мозги внедрят интерпретаторы машинного кода. И в мире закончится срачЪ какой язык лучше. И с компьютером мы все будем на "ты".
Скоро всем в мозги внедрят интерпретаторы машинного кода. И в мире закончится срачЪ какой язык лучше. И с компьютером мы все будем на "ты".
Вряд ли.
Подавляющее большинство людей диссонируют с понятием логики. Там любой интерпретатор загнётся
Очередной затык приключился.
//структура такого типа typedef struct menuItem { char *name; menuItem *prev; menuItem *next; menuItem *ok; byte func_num; void (*Handler)(); int value; } menuItem; menuItem m1; //И переменная int myInt=2; //Не могу понять как правильно написать. m1={"Setup",&m4,&m2,&m11,1,NULL, ?????? }; //Что бы при изменении значений так: if(нужно убавить){m1->value--;} Что бы менялось значение myIntНичего не понял.
Ничего не понял.
Есть переменная, как структуре на нее передать ссылку ?
Ну, не знаю, есть 100500 способов. Можно в структуре завести поле - ссылку или указатель на эту переменную. Но, проще завести эту переменную как статическое поле структуры - тогда она будет одна на все экземпляры структуры, но при этом оставаться её внутренним полем.
m111={"setup_volume",NULL,NULL,&m1,2,NULL,*myInt}; На такое компилятор ругаетсяНу, не знаю, есть 100500 способов. Можно в структуре завести поле - ссылку или указатель на эту переменную. Но, проще завести эту переменную как статическое поле структуры - тогда она будет одна на все экземпляры структуры, но при этом оставаться её внутренним полем.
В общем то я про это и спрашиваю.
Как будет выглядеть правильный синтаксис, для передачи указателя структуре
В ардуине посмари исходник attachInterrupt(), там ссылка на функцию-хендлер сейвится в массив.
Handler по указателю у меня работает.
У меня на int матом ругается
Приводите код полностью. Откуда мне знать на что он ругается?
Как будет выглядеть правильный синтаксис, для передачи указателя структуре
Ну, для начала нужно передавать именно указатель, а не его разыменование, т.е., разумеется не *myInt, а хотя бы & myInt, но, повторяю, приводите код полностью.
Только на 100500% более грамотно не передавать указатель, а завести статическое поле. Расход памяти будет меньше на 2 * <количество экземпляров>. Да и вообще, если класс работает с внешними указателями - это признак неграмотного проектирования программы.
Хорошо, попробуем с другой стороны:
int x=5; typedef struct myStruct{ int a; byte b; long c; }; myStruct abc={10,20,x}; void setup(){ Serial.begin(9600); } void loop(){ delay(500); abc.c=abc.c+=1; Serial.println(x);//так всегда выводит '5' Serial.println(abc.c);//так инкрементируется //как сделать, что бы инкрементировался "х" }