Помогите создать меню

Тема в разделе "Arduino & Shields", создана пользователем Gastozavr, 31 авг 2018.

  1. Gastozavr

    Gastozavr Нерд

    Имеется i2c дисплей , энкодер.Помогите создать меню с подменю на ардуино.
     
  2. parovoZZ

    parovoZZ Гуру

    А у меня есть штурвал, кусок доски и яхтный лак. Поможешь яхту сделать?

    Тебе в закажу проект. Там бывает бесплатно делают.
     
  3. Gastozavr

    Gastozavr Нерд

    эмм я просто попросил помочь с кодом
     
  4. Daniil

    Daniil Гуру

  5. Airbus

    Airbus Радиохулиган Модератор

    И что оно должно делать?
     
    Igor68 нравится это.
  6. Gastozavr

    Gastozavr Нерд

    при нажатии на энкодер переходить на следующий уровень
     
  7. Igor68

    Igor68 Гуру

    А Вы считывать энкодер умеете? Если да... то в чём проблема вообще? Вы же сказали "помочь с кодом" т.е. подсказать...
     
  8. parovoZZ

    parovoZZ Гуру

    Эмм а я просто попросил помочь с яхтой.
     
  9. Daniil

    Daniil Гуру

    А моя ссылка чем не помогла?
     
  10. parovoZZ

    parovoZZ Гуру

    ну я в ссылку не хочу....
     
  11. Gastozavr

    Gastozavr Нерд

    умею считовать
     
  12. Gastozavr

    Gastozavr Нерд

    яхта и меню разные вещи
     
  13. b707

    b707 Гуру

    "помочь" означает, что большую часть работы сделаете вы сами, а мы лишь поможем. Ну, типа, когда напишете 90% меню - приходите, подскажем, как написать остальное...
    А у вас пока просьба "сделайте за меня" - так что аналогия с яхтой очень даже к месту.
     
    Igor68, Daniil, Mitrandir и ещё 1-му нравится это.
  14. parovoZZ

    parovoZZ Гуру

    Что делать?
     
  15. Igor68

    Igor68 Гуру

    Ну так инкрементируйте и декрементируйте значение номера меню в зависимости от направления поворота энкодера да и анализируйте типа:
    Код (C++):
    ...
    int num;  //номер меню - определено где-то и энкодером изменяется в + и  в -
    switch(num)
    {
        case 1: //меню 1
            .... //формируете меню 1
            break;
        case 2:
            ....//формируете меню 2
            break;
        .... //для остальных мню
        default:
            //а тут можете сделать "закольцовку" или ограничение
            break;
    }
    ... //далее выводите готовое меню
    ...
    И что помогать-то?
     
    DetSimen и Сусемьбек нравится это.
  16. SergeiL

    SergeiL Оракул Модератор

    Присоединяюсь к тем, кто уже написал, вопрос не понятен. Как помочь?
    Могу скинуть свой обработчик действий для меню и подменю.
    Но ведь все равно придется разбираться. ;)
    Готовое, под конкретную задачу, ведь все равно только в закажу проект.

    Писал для термостата на Меге 8, лет 10 назад.
    На первом уровне меню показываются: текущее значение температуры, плюсом/минусом можно прибавить убавить значение термостата.
    Enter позволяет листать: максимум, минимум температуры с временем и датой; максимум, минимум напряжения питания, время работы нагревателя. Их можно сбросить удержав + и -.

    При длительном удержании кнопки "Enter" попадаем в подменю. Там задаются дополнительные параметры типа: контрастность, яркость подсветки, гистерезис термостата, температуру режима "анти заморозки", адрес RS-485, разрешение выключения подсветки с диммированием при отсутствии нажатия кнопок.

    Файл <menu.c>:
    Код (C++):

       // SubMenu
    #define KEY_1 2   // Back
    #define KEY_2 3      // Enter
    #define KEY_3 0      // UP
    #define KEY_4 1      // Down
    #define KEY_5 5      // Power

    typedef struct _menuItem    {            // Структура подменю
                char flash     * itemText;    // Текст
                signed char   * Cur_Val;     // Указатель на значение
                signed char     Esc_Val;     // Значение в случае выхода без изменений
                signed char     Min_Val;     // Минимально возможное значение
                signed char     Max_Val;     // Максимально возможное значение
                signed char   * eep_addr;    // Адрес для сохранения значения в EEPROM_WRITE
                void            (*itemFunction)(void);  // Функция вызываемая для обработки нового значения.
                }
    MenuItem;

    void MenuProcess(char key);
    void MenuOpen(void);
    void MenuClose(void);

    static flash char    _Contrast_str[]        = "Contrast",
                         _Backlight_str[]    = "LED Ligh",
                        _Gisteresis_str[]    = "Gisteres",
                        _NetAddr_str[]        = "Net Addr",
                        _AntiFrTemp_str[]    = "AF Temp.",
                        _AntiFrOnOff_str[]    = " A.F.On ",
                        _KeyBeepOnOff_str[]    = "Key Beep",
                        _AutoDimOnOff_str[]    = "Auto Dim",
                        _Date_Year_str[]    = "  Year  ",
                        _Date_Month_str[]    = "  Month ",
                        _Date_Day_str[]        = "  Day   ",
                        _Time_Hour_str[]    = "  Hour  ",
                        _Time_Min_str[]        = " Minute "
                        ;

    void Key_1_1(void)
    {
          Mode=0;
    }

    void Key_1_2(void)
    {
         if (Heating_ON_OFF==HEATING_ON)
            Heating_ON_OFF=HEATING_OFF;
        else
            Heating_ON_OFF=HEATING_ON;
                                           
        ChangeDataFlag|=CHG_TERMOSTAT;
        EEPROM_WRITE((int)&eep_Heating_ON_OFF, Heating_ON_OFF);
    }
    void Key_2_1(void)
    {
       if (Mode<NUM_OF_MODE-1)
             Mode++;
       else
          Mode=0;

       ChangeDataFlag|=CHG_MENUMODE;
    }
    void Key_2_2(void)
    {
       if (Mode>0)
             Mode--;
       else
          Mode=NUM_OF_MODE-1;
       MenuOpen();  // активизируем подменю установок
       ChangeDataFlag|=CHG_MENUMODE;
    }
    void Key_3_1(void)
    {
       if (Mode==0 && Heating_ON_OFF == HEATING_ON)
             IncTermostatVal();
    }
    void Key_4_1(void)
    {
       if (Mode==0 && Heating_ON_OFF == HEATING_ON)
             DecTermostatVal();
    }
    void Key_4_2(void)
    {
        switch(Mode)
        {
            case 1:
                TempMinVal=125;       // сбросим минимальное значение температуры
            break;
            case 2:
                TempMaxVal=-55;       // сбросим максимальное  значение температуры
            break;
            case 3:
                 Min_Voltage=Cur_Voltage;  // сбросим минимальное значение напряжения
                 Max_Voltage=Cur_Voltage;  // сбросим максимальное значение  напряжения
            break;
            case 4:
                HeaterTime.Year=0;        // сбросим время наработки нагревателя
                HeaterTime.Month=0;
                HeaterTime.Day=0;
                HeaterTime.Hour=0;
                HeaterTime.Min=0;
                HeaterTime.Sec=0;

            break;
        }
    }
                   
    //MainMenu  обработчики кнопок    элемент 0 - короткое нажатие, 1 - длинное нажатие.

    void  (*MMFTab[5][2])(void)= {   {Key_3_1, NULL},
                                        {Key_4_1, Key_4_2},
                                       {Key_1_1, Key_1_2},
                                       {Key_2_1, Key_2_2},
                                       {Key_1_2, NULL}  };

                   
    void SetContrast(void)
    {
       OCR1AL=(Contrast*5)+155;  // при 20 в  OCR1AL заносим 255
    }                  
    void SetBacklight()
    {
       OCR1BL =((21-LED)*12)+3;     // при 0 в  OCR1BL заносим 255
    }                


    void SetTime()
    {
            // После установки времени сбросим макс и мин температуры.
         TempMinVal=125;
         TempMaxVal=-55;
    }                
    void SetTimeMin()
    {
        CurTime.Sec=0;
        SetTime();
    }
               
    static MenuItem
        MenuItems[] =    {
                _Contrast_str,      &Contrast,       0,0,   20,  &eep_Contrast,       &SetContrast,
                _Backlight_str,   &LED,            0,0,   20,  &eep_LED,            &SetBacklight,
                _Gisteresis_str,  &Gister,           0,0,   10,  &eep_Gister,         NULL,
                _NetAddr_str,      &NetAddr,        0,2,   99,  &eep_NetAddr,        NULL,
                _AntiFrTemp_str,  &AntiFrTemp,     0,0,      20,  &eep_AntiFrTemp,     NULL,
                _AntiFrOnOff_str, &AntiFrOnOff,    0,0,       1,  &eep_AntiFrOnOff,    NULL,
                _KeyBeepOnOff_str,&KeyBeepOnOff,   0,0,    1,  &eep_KeyBeepOnOff,   NULL,
                _AutoDimOnOff_str,&AutoDimOnOff,   0,0,       1,  &eep_AutoDimOnOff,   NULL,
                _Date_Year_str,   &CurTime.Year,   0,1,      99,  NULL,                  &SetTime,
                _Date_Month_str,  &CurTime.Month,  0,1,      12,  NULL,                  &SetTime,
                _Date_Day_str,    &CurTime.Day,    0,1,      31,  NULL,                  &SetTime,
                _Time_Hour_str,   &CurTime.Hour,   0,0,      23,  NULL,                  &SetTime,
                _Time_Min_str,    &CurTime.Min,    0,0,      59,  NULL,                  &SetTimeMin,
                };

       
    MenuItem     *_mptr = MenuItems;
    MenuItem     *_mptr_choiced = NULL;    
    unsigned char SubMenu_choiced = 0;


    void MenuOpen(void)
    {
    SubMenu_choiced=1;
    _mptr_choiced = NULL;
    }

    void MenuClose(void)
    {
    Mode=0;
    SubMenu_choiced=0;
    _mptr_choiced = NULL;
    }

    void MainMenuProcess(char key)
    {
        unsigned char num=Key_Mode[key];
        void (*function)(void);

         ChangeDataFlag |= CHG_MENUMODE;

        function=MMFTab[key][num-1];
     
        if (*function)
           (*function)();
    }

    void MenuProcess(char key)
    {
         ChangeDataFlag |= CHG_MENUMODE;
        switch (key)
        {
            case  KEY_1:    // Key 1 presed (назад)
                  if(_mptr_choiced)   // выход в подменю из выбранного пункта
                  {
                      *(_mptr->Cur_Val) = _mptr->Esc_Val;
                 
                      if(_mptr->itemFunction)
                              (*_mptr->itemFunction)();

                      _mptr_choiced = NULL;

                  }
                  else if (SubMenu_choiced)  // выход из меню устоновок в idle
                  {
                   MenuClose();
                  }
             
            break;

            case  KEY_2:    // Key 2 presed (выбор)
                  if(_mptr_choiced)   // принимаем значение и выходим
                  {
                       if (_mptr->itemFunction)
                       (*_mptr->itemFunction)();
             
                    if (_mptr->eep_addr)
                        EEPROM_WRITE((int)(_mptr->eep_addr), *(_mptr->Cur_Val));
                    _mptr_choiced = NULL;
                  }
                  else if (SubMenu_choiced)  // Переходим в подменю изменения параметра
                  {
                          _mptr_choiced = _mptr;
                       _mptr->Esc_Val= *(_mptr->Cur_Val);
                  }

            break;

            case  KEY_3:    // Key 2 presed (+)
                  if(_mptr_choiced)   // увеличиваем значение параметра (если еще можно)
                  {
                         if (*(_mptr->Cur_Val) < _mptr->Max_Val)
                      {
                           (*(_mptr->Cur_Val))++;
                         if(_mptr->itemFunction)
                              (*_mptr->itemFunction)();
                      }
                  }
                  else if (SubMenu_choiced)
                  {            // переходим на предыдуший пункт меню
                          if (--_mptr < MenuItems)    // если первый то переходим на последний.
                             _mptr = &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1];
                  }

            break;
            case  KEY_4:    // Key 2 presed (-)
                  if(_mptr_choiced)   // уменьшаем значение параметра
                  {
                         if (*(_mptr->Cur_Val) > _mptr->Min_Val)
                      {
                           (*(_mptr->Cur_Val))--;
                         if(_mptr->itemFunction)
                               (*_mptr->itemFunction)();
                      }
                  }
                  else if (SubMenu_choiced)
                  {        // переходим на следующий пункт меню
                          if (++_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1])    // если последний
                       _mptr = MenuItems;   // то переходим на первый
                  }
            break;

        }
    }
     
    Последнее редактирование: 2 сен 2018
    parovoZZ, DIYMan, ИгорьК и 2 другим нравится это.
  17. SergeiL

    SergeiL Оракул Модератор

    Сейчас посмотрел, есть что оптимизировать - нужно просто переписать. ;)
    Станет и понятней, и правильней и короче. :)
    Но как всегда, писалось для себя и на скорую руку - комментариев минимум.

    Идея была упростить добавление пунктов в подменю.
    Просто добавляется элемент структуры, указывается текст, переменная, отвечающая за параметр, макс/мин значения параметра, ячейка EEPROM для сохранения, и функция, если нужно сделать что-то после изменения этого параметра, кроме обновления переменной.
    И все, появился и работает новый элемент настроек.;)

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

    Сделано 6 штук, работают по дачам, глюков, сбоев зависаний - не замечено.
     
    Последнее редактирование: 2 сен 2018