Помогите новичку (хитрости)

Intel-xer
Offline
Зарегистрирован: 23.07.2016

Добрый день! Имеется код в котором выводится информация на дисплей в зависимости от переменной MenuS

void ScreenUp (void)
{switch (MenuS){
   case 0://menu
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(punkt+1);
        lcd.setCursor(2, 0);
        lcd.print(GUI.Menu[punkt]+" "); lcd.write(byte(0));
        lcd.setCursor(0, 1);
        lcd.print(punkt + 2);
        lcd.setCursor(2, 1);
        lcd.print(GUI.Menu[punkt+1]);
      break;
   case 1:
        lcd.clear();
        lcd.scrollDisplayRight();
        lcd.print("Test AutoScroll Text");
        
        
      break; 
   case 2:
       break; 
   case 3:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.write(byte(punkt));
        lcd.print(" "+punkt);
        lcd.setCursor(0, 1);
        lcd.write(byte(punkt+1));
        lcd.print(" "+punkt+1);
       break;
   case 20:
        lcd.clear();
        lcd.print(AlarmArrS[punkt]); 
        break;
  }
  
 }

имеется функция которая срабатывает по нажатию кнопки и в зависимости от информации на экране совершает различные действия

void buttonOn (void)
{
  switch (MenuS) {
    case -1: lcd.backlight(); MenuS = 0; ScreenUp(); break;
    case 0: 
            switch (punkt) {
              case 0: DisplayOff();
                break;
              case 1: MenuS = 2; ScreenUp(); break;
              case 3: MenuS = 3; ScreenUp(); break;
              case 6: 
                  lcd.clear(); lcd.print("Alarm Tested!"); 
                  for (int i = 0; i <= 10; i++) {
                    tone(12, 800, 40);
                    delay(42);
                    tone(12, 1200, 40);
                    delay(42);}
                  lcd.clear(); ScreenUp();
                break;
              case 9: MenuS = 1; break;
              default:
                  lcd.clear();
                  lcd.print("page not found");
                  delay(800);
                  ScreenUp(); break;
    case 1: 
            
    case 2:  //help 
            lcd.noAutoscroll();
            MenuS = 0;
            break;
    case 3: 
            MenuS = 0; ScreenUp();
            break;
    case 20:
            if (AlarmState == false){ //alarm
              if (punkt != 0) {
                lcd.clear();
                lcd.print("Timer set");
                lcd.setCursor(0,1);
                lcd.print(AlarmArrS[punkt]);
                delay(400);
                DisplayOff();
                MenuS = 1;
                delay(AlarmArr[punkt]*1000);
                AlarmState=true;
              } else {MenuS = 0; ScreenUp(); }
            } else { AlarmState = false; MenuS = 0; lcd.backlight(); ScreenUp();} break;
            break;
    }

}

И вот тут встает праблема, у нас 2 огромных свитч-кейс"а в двух разных функциях, могу ли я после выполнения функции ScreenUp (после вывода информаци на экран) изменить выполняемый код в функции buttonOn c учетом того, что функция buttonOn  будет запущена через неопределенное время (секунда, час, день) Возможно существуют какие либо хитрости?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Intel-xer пишет:

И вот тут встает праблема, у нас 2 огромных свитч-кейс"а в двух разных функциях, могу ли я после выполнения функции ScreenUp (после вывода информаци на экран) изменить выполняемый код в функции buttonOn c учетом того, что функция buttonOn  будет запущена через неопределенное время (секунда, час, день) Возможно существуют какие либо хитрости?

Гарвардская архитектура (по которой построены AVR) в принципе не предполагает возможности изменения кода программы самой программой.

Впрочем, подозреваю, что под "изменить выполняемый код в функции" Вы подразумевали что-то другое. Но что именно, мне неизвестно.

Что же касается самого кода функции buttonOn, то его IMHO следовало бы переписать, опираясь на идеологию "blink without delay". Вполне вероятно, Ваш вопрос в результате разрешится сам собой.

Intel-xer
Offline
Зарегистрирован: 23.07.2016

под изменением кода я подразумеваю тот же switch-case  только проще или быстрее... просто начинаешь путаться когда вывод информации (ScreenUp)  находится далеко от функции ButtonOn, выбора варианта 

Как вы уже поняли я пытаюсь написать эдакий GUI  только общий размер программы уже составляет 47% а это только меню и пара тестовых "страниц" Было бы "по людски" разделить GUI и часть программы, которая будет выполнять действия на 2 ардуинки, но пока немогу себе такого позволить...

В функции buttonON первый свитч-кейс определяет на какой странице находится пользователь

если MenuS = -1 то GUI выключен и при нажатии кнопки, мы попадаем в главное меню, его номер = 0, тоесть MenuS =0 там же уже основываясь, какой пункт меню мы выбрали, по нажатию кнопки производится действие...

А можно по подробнее про "blink without delay", что это такое)

 

negavoid
Offline
Зарегистрирован: 09.07.2016

Чтобы меньше путаться, можно определить все кейсы текстовыми константами и обращаться к ним по имени.

#define GUI_OFF   -1
#define MAIN_MENU 0
#define HELP_MENU 2
...
case HELP_MENU:
  lcd.noAutoscroll; MenuS=0;
  break;

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

case HELP_MENU:
  help_menu_function();  
  break;
...
void help_menu_function(void) {
  lcd.noAutoscroll; MenuS=0;
}

Blink без ожидания вот здесь: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Intel-xer пишет:

Как вы уже поняли я пытаюсь написать эдакий GUI  только общий размер программы уже составляет 47% а это только меню и пара тестовых "страниц"

Честно говоря, еще не понял.

Более того, я обнаружил у Вас только текстовый вывод. Чем по-Вашему графический интерфейс отличается от текстового?

Вообще же, IMHO Arduino не предназначена и непригодна для GUI - слишком мало операивной памяти.

Цитата:

А можно по подробнее про "blink without delay", что это такое)

Посмотрел дату регистрации на форуме - вчера. ТОгда понятно.

blink without delay - это классика: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Кстати, в Windows GUI используется та же идеология.

Intel-xer
Offline
Зарегистрирован: 23.07.2016

negavoid пишет:

Чтобы меньше путаться, можно определить все кейсы текстовыми константами и обращаться к ним по имени.

#define GUI_OFF   -1
#define MAIN_MENU 0
#define HELP_MENU 2
...
case HELP_MENU:
  lcd.noAutoscroll; MenuS=0;
  break;

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

case HELP_MENU:
  help_menu_function();  
  break;
...
void help_menu_function(void) {
  lcd.noAutoscroll; MenuS=0;
}

Blink без ожидания вот здесь: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

идея с константами значительно упрощает, спасибо большое, код я решил оставить старый

А по поводу блинк светодиодом это все знают, я подумал что это что-то другое, невстречал полного названия на английском, та и в английском я несилен

 

Intel-xer
Offline
Зарегистрирован: 23.07.2016

Согласен, это не полноценный ГУИ, но хоть какойто интерфейс))

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Что бы не городить такие вещи.

        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(punkt+1);
        lcd.setCursor(2, 0);
        lcd.print(GUI.Menu[punkt]+" "); lcd.write(byte(0));
        lcd.setCursor(0, 1);
        lcd.print(punkt + 2);
        lcd.setCursor(2, 1);
        lcd.print(GUI.Menu[punkt+1]);
     

и 

        lcd.clear();
        lcd.scrollDisplayRight();
        lcd.print("Test AutoScroll Text");

ну и так далее, содайте класс display , и напишите методы screen1,screen2 и так далее. Можете так же создать метод case_screen который уже будет переключать на нужные и созданые методы. Для чего делать так? Так модульность. Чем меньше модуль, тем легче наладить и оттестировать правильность его работы.

Logik
Offline
Зарегистрирован: 05.08.2014

следующим логичным шагом после

\\можно вынести выполнение по нескольку строк из свитча в отдельные функции.

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

#define SCREEN 1

#define BUTTON 2

void ButtonON (void)

{

arrFunc[MenuS](BUTTON);


 }
void ScreenUp (void)

{

arrFunc[MenuS](SCREEN );


 }

И соответственно в каждой функции - весь код относящийся к соответствующему действию (например к HELP_MENU) все рядом как просил ТС.  

И соответственно после этого так и просится  - убрать MenuS а вместо ее сделать переменную - указатель на ту функцию индекс которой ранее был в MenuS. Получим весьма профессиональный, быстрый и лаконичный код, без лишних идентификаторов, с ясным соответствием: каждое действие (или что там, пункт меню?) в отдельной функции. 

Такой вот ООП без ООП. Так что хитростей валом )))

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