реклама на сайте
подробности

 
 
> Структура меню
sind-rom
сообщение Nov 15 2006, 17:36
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 74
Регистрация: 21-10-06
Пользователь №: 21 540



Народ, как Вы делаете меню для своих девайсов? Интересует структура. Столкнулся с проблемой: вывод на дисплей (HD44780 совместимый) меню получается малопонятной и (главное) неприспособленный для добавления новых пунктов меню. Никогда раньше не приходилось делать меню, так что научите smile.gif Может у кого есть каки-нить наработки\библиотеки?
Заранее большое спасибо...
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 29)
junoSynthesizer
сообщение Nov 15 2006, 22:00
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 83
Регистрация: 25-11-05
Из: odessa
Пользователь №: 11 397



присоединяюсь к вопросу.

тоже только начал стряпать меню для своего устройства.
организовал страничное меню. (ничего не читал на эту тему, проосто придумал сам)

Код
/*
* страницы меню
*           16 символов ::          "1234567890123456"
*/

const __flash byte str1_0[]      = "*Введите пароль*"; // password menu
const __flash byte str2_0[]      = "                "; // MENU_PAGE_0

// кнопка "опции" - затемнена
const __flash byte str1_1[]      = "**Слушаю  эфир**"; // main menu
const __flash byte str2_1[]      = "*Режим    Опции*"; // MENU_PAGE_1

//...
//... объявление строк меню
//...
// далее описываем реакцию кнопок на определённой странице меню (кнопок у меня 3 - правая,
// левая и вернуться на пункт выше

void key_handle(byte key_num, byte page_num)
{
  switch (page_num)
  {
    case  MENU_PAGE_0             : // password menu
    {
      switch (key_num)
      {
        case KEY_1    :
          {
            // что-то делаем
          } break; // KEY_1
        case KEY_2    :      
          {
            // что-то делаем
          } break; // KEY_2
        case KEY_BACK :      
          {
            // что-то делаем
          } break; // KEY_BACK
        default : break;        
      } // switch (key_num)
    } break; // MENU_PAGE_0
  
    case  MENU_PAGE_1             : // main menu -------------------------------
    {
      switch (key_num)
      {
        case KEY_1    :
          {
            menu_page = MENU_PAGE_1_1; // собственно вот так происходит обработка
            draw_menu(menu_page);      
          } break; // KEY_1
        case KEY_2    :      
          {
            // grayed
          } break; // KEY_2
        case KEY_BACK :      
          {
            // что-то делаем
          } break; // KEY_BACK
        default : break;        
      } // switch (key_num)
    } break; // MENU_PAGE_1 ----------------------------------------------------

//...
//...
//...
// ну и собственно отрисовка строк меню на дисплее
void draw_menu(byte page_num)
{
  switch (page_num)
  {
    case  MENU_PAGE_0             : // password menu
    {
      LCD_PrintAt(0, 0, &str1_0[0]);
      LCD_PrintAt(0, 1, &str2_0[0]);
    } break;
  
    case  MENU_PAGE_1             : // main menu
    {
      LCD_PrintAt(0, 0, &str1_1[0]);
      LCD_PrintAt(0, 1, &str2_1[0]);
    } break;
//...
//...
//...


хотелось бы услышать мнение гуру в этом вопросе - как ПРАВИЛЬНО стряпать меню? для маленького проектика мне и такая организация подходит, а вот если что-то большое...

Сообщение отредактировал junoSynthesizer - Nov 15 2006, 22:04


--------------------
Вся жизнь - ништяк, все бабы - леди, а солнце - шар дающий свет
Go to the top of the page
 
+Quote Post
bodja74
сообщение Nov 15 2006, 22:37
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984



Делал двух-координатное меню.
Создаем массив переменных Y,X1,X2,X3...Xn.
Y- значение Y от 0 до n
X1-n - перемещение по X по каждой позиции Y (X отдельные ,чтобы не переносить значения)
На все - четыре кнопки.

1 Проверяем кнопки по Y
2 По значению Y=n переходим на подпрограмму допустим SUB_Xn
3 Проверяем кнопки по X
4 Переходим на операцию соответствующую значению Х (или изменияем какие то значения)
5 Все ,у меня через менюшку проходило до 90% кода.
Go to the top of the page
 
+Quote Post
SergSit
сообщение Nov 16 2006, 07:03
Сообщение #4


Частый гость
**

Группа: Свой
Сообщений: 173
Регистрация: 9-12-05
Пользователь №: 12 031



Почитай тему на этом форуме : Отображение меня на ЖК...
electronix
Go to the top of the page
 
+Quote Post
_Bill
сообщение Nov 16 2006, 09:28
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(sind-rom @ Nov 15 2006, 20:36) *
Народ, как Вы делаете меню для своих девайсов? Интересует структура. Столкнулся с проблемой: вывод на дисплей (HD44780 совместимый) меню получается малопонятной и (главное) неприспособленный для добавления новых пунктов меню. Никогда раньше не приходилось делать меню, так что научите smile.gif Может у кого есть каки-нить наработки\библиотеки?
Заранее большое спасибо...

Я, например, так делал:
Код
/*    Global data type definitions    */

typedef
struct _menuItem    {
            char flash    *itemText;
            void        (*itemFunction)(char);
            char        itemArg;
            }
MenuItem;

static void Run(char _dummy)
    {
    }

static void Stop(char _dummy)
    {
    }


static flash char    _read[]        = "Read device     ",
            _program[]    = "Program device  ",
            _set[]        = "Set device      ",
            _insert[]    = "Insert          ",
            _edit[]        = "Edit buffer     ",
            _clear[]    = "Clear buffer    ",
            _append[]    = "Append          ",
            _run[]        = "Run             ",
            _stop[]        = "Stop            ";
static MenuItem __flash
    MenuItems[] =    {
            _set,        SetType,    0,
            _read,        0,        0,
            _program,    0,        0,
            _insert,    Edit,        INSERT_BUFFER,
            _edit,        Edit,        EDIT_BUFFER,
            _clear,        Edit,        CLEAR_BUFFER,
            _append,    Edit,        APPEND_BUFFER,
            _run,        Run,        0,
            _stop,        Stop,        0
            };
//
// ** Menu    -- the main menu fuction
//
void Menu(void)
    {
    MenuItem __flash    *_mptr = MenuItems;
    static __flash char    _unKnown[] = "Unknown device";

    for (;;)
        {
        Clear_LCD();
        puts_P(_mptr->itemText);
        switch (getchar())
            {
        case '+':    // Next item
            if (++_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1])    // Set pointer to the first item
                _mptr = MenuItems;
            break;
        case '-':    // Previous item
            if (--_mptr < MenuItems)    // Set pointer to the last item
                _mptr = &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1];
            break;
        case '!':    // Do the selected menu item
            if (Device->_devType==UNKNOWN_TYPE && _mptr->itemFunction!=SetType)
                {
                LCD_MoveCurs2(0);    // Move the LCD cursor
                puts_P(_unKnown);    // Put the message
                getchar();
                break;
                }
            (*_mptr->itemFunction)(_mptr->itemArg);
            }
        }
    }
Go to the top of the page
 
+Quote Post
zltigo
сообщение Nov 16 2006, 09:39
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



До кучи.
Код
//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
MenuState menu_state[] =
{
//  State                                    State Text          Function
    
    { ST_MAIN,                              "Main            ",    NULL             },
    { ST_MAIN_REV,                            "                ",    mf_revision     },

    { ST_TIME_FUNC,                            "Time            ", mf_showtime     },
    { ST_TIME_SET_FUNC,                        "SetTime         ", mf_settime         },

      { ST_DATE_FUNC,                            "Date            ",    mf_showdate     },

    { ST_SOUND,                              "Sound           ", NULL             },
    { ST_SOUND_SELECT_FUNC,                    NULL,                mf_selectsound     },
    { ST_SOUND_PLAY_FUNC,                      NULL,                mf_playsound     },

    { ST_TEMPERATURE,                        "Temperature     ",    NULL             },
    { ST_TEMPERATURE_FUNC,                   NULL,                mf_temperature     },

    { ST_VOLTAGE,                            "Voltage         ",    NULL             },
    { ST_VOLTAGE_FUNC,                       NULL,                mf_voltage         },

    { ST_LIGHT,                              "Light           ",    NULL             },
    { ST_LIGHT_FUNC,                         NULL,                  mf_light         },

    { ST_OPTIONS,                            "Options         ",    NULL             },
    { ST_OPTIONS_DISPLAY,                    "Display         ",    NULL             },
    { ST_OPTIONS_COMMON,                    "Common          ",    NULL             },
    { ST_OPTIONS_TEST,                        "Test            ",    NULL             },
    // End of list
    { 0,                                     NULL,                  NULL             },

};

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
MenuNavigate menu_nextstate[] =
{
//  State                           Input       NEXT State
    { ST_MAIN,                      KEY_UP,       ST_OPTIONS         },
    { ST_MAIN,                      KEY_PREV,   ST_MAIN_REV     },
    { ST_MAIN,                      KEY_NEXT,   ST_MAIN_REV     },
    { ST_MAIN,                      KEY_DOWN,      ST_TIME_FUNC    },

    { ST_MAIN_REV,                    KEY_PREV,   ST_MAIN            },
    { ST_MAIN_REV,                    KEY_NEXT,   ST_MAIN            },
        
    { ST_SOUND,                      KEY_UP,       ST_DATE_FUNC    },
    { ST_SOUND,                      KEY_NEXT,   ST_SOUND_SELECT_FUNC    },
    { ST_SOUND,                      KEY_PREV,   ST_MAIN            },
    { ST_SOUND,                      KEY_DOWN,   ST_TEMPERATURE    },

    { ST_TEMPERATURE,                KEY_UP,       ST_SOUND        },
    { ST_TEMPERATURE,                KEY_NEXT,   ST_TEMPERATURE_FUNC    },
    { ST_TEMPERATURE,                KEY_PREV,   ST_MAIN            },
    { ST_TEMPERATURE,                KEY_DOWN,      ST_VOLTAGE        },

    { ST_VOLTAGE,                    KEY_UP,       ST_TEMPERATURE    },
    { ST_VOLTAGE,                    KEY_NEXT,   ST_VOLTAGE_FUNC    },
    { ST_VOLTAGE,                    KEY_PREV,   ST_MAIN            },
    { ST_VOLTAGE,                    KEY_DOWN,      ST_LIGHT        },

    { ST_LIGHT,                      KEY_UP,       ST_VOLTAGE        },
    { ST_LIGHT,                      KEY_NEXT,   ST_LIGHT_FUNC    },
    { ST_LIGHT,                      KEY_PREV,   ST_MAIN            },
    { ST_LIGHT,                      KEY_DOWN,      ST_OPTIONS        },

    { ST_OPTIONS,                    KEY_UP,       ST_LIGHT        },
    { ST_OPTIONS,                    KEY_NEXT,   ST_OPTIONS_DISPLAY    },
    { ST_OPTIONS,                    KEY_PREV,   ST_MAIN        },
    { ST_OPTIONS,                    KEY_DOWN,      ST_MAIN        },

    
    { ST_OPTIONS_TEST,                KEY_UP,       ST_OPTIONS_COMMON    },
    { ST_OPTIONS_TEST,                KEY_PREV,   ST_OPTIONS    },
    { ST_OPTIONS_TEST,                KEY_BREAK,  ST_MAIN              },
    { ST_OPTIONS_TEST,                KEY_DOWN,   ST_OPTIONS_DISPLAY  },
    
    { ST_OPTIONS_DISPLAY,            KEY_UP,       ST_OPTIONS_TEST    },
    { ST_OPTIONS_DISPLAY,            KEY_PREV,   ST_OPTIONS    },
    { ST_OPTIONS_DISPLAY,              KEY_BREAK,  ST_MAIN              },
    { ST_OPTIONS_DISPLAY,            KEY_DOWN,      ST_OPTIONS_COMMON    },
    
        
    { ST_OPTIONS_COMMON,            KEY_UP,       ST_OPTIONS_DISPLAY    },
    { ST_OPTIONS_COMMON,            KEY_PREV,   ST_OPTIONS    },
    { ST_OPTIONS_COMMON,               KEY_BREAK,  ST_MAIN              },
    { ST_OPTIONS_COMMON,            KEY_DOWN,   ST_OPTIONS_TEST    },

    // End of list
    { 0,                             0,          0                }
};

BYTE     state;            // Helds the current Menu state
BYTE     enter = TRUE;
BYTE    enter_func = FALSE;

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void MenuProcess( void *params )
{
int rotor_cnt = 0xF7;
char tmp_str[16];
ulong rtc_time;
BYTE nextstate;
BYTE prevstate;
static char *statetext;
BYTE (*statefunc)(BYTE);
BYTE input;
char i;

    params = params;

    // Initial state variables
    prevstate = ST_DUMMY;
    state = nextstate = ST_MAIN;
    statetext = "Hello!";
    statefunc = NULL;
    
    for(;; )                            // Main Menu loop
    {
        // Plain menu text
        if( statetext )
        {   lcd_setpos( 1, 1 );
            lcd_string( statetext );                  
            statetext = NULL;
        }

        input = key_get();               // Read buttons

        if( statefunc )
        {     // When in this state, we must call the state function
            nextstate = statefunc( input );
        }
        else if( input != KEY_NULL )
        {   // Plain menu, clock the state machine
            nextstate = statemachine( state, input );
        }
        if( nextstate != state )
        {   state = nextstate;
            for( i=0; menu_state[i].state; i++ )
            {   if( menu_state[i].state == state )
                {   statetext = menu_state[i].text;
                    statefunc = menu_state[i].func;
                    break;
                }
            }
        }
        
        if( state == ST_MAIN )
        {    
            if( prevstate != ST_MAIN )
            {    prevstate = ST_MAIN;
        
                lcd_setpos( 2, 1 );
                //           1234567890123456
                lcd_string( "No Alarms       " );
            }
            
            if( xQueueReceive( RTCMSG_handle, &rtc_time, 0 ) )
            {
                sprintf( &tmp_str[0], "%02i:%02i", (BYTE)(rtc_time>>16), (BYTE)(rtc_time>>8) );
                lcd_setpos( 1, 17-8 );
                lcd_string( tmp_str );
            }    
            
            if( ++rotor_cnt > 0xF7+5 )
                rotor_cnt = 0xF7;
            lcd_setpos( 1, 16 );
            lcd_char( rotor_cnt );
            
            vTaskDelay_ms( 100 );

        }
        else
        {   prevstate = state;
            vTaskDelay_ms( 100 );
        }
    } //End Main loop
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
BYTE statemachine( BYTE state, BYTE stimul )
{
int i;
BYTE newstate = state;            // Default stay in same state

    for( i=0; menu_nextstate[i].state; i++ )
    {   if( menu_nextstate[i].state == state && menu_nextstate[i].input == stimul )
        {   newstate = menu_nextstate[i].state_next;
            break;
        }
    }
    return( newstate );
}


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Andy_F
сообщение Nov 16 2006, 09:42
Сообщение #7


Частый гость
**

Группа: Свой
Сообщений: 109
Регистрация: 27-07-06
Из: С.-Петербург
Пользователь №: 19 148



Например, вот так:

Код
struct menu_item
{    unsigned char Name[17];
    struct     menu_item    *Parent;
    struct    menu_item    *Child;
    struct    menu_item    *Prev;
    struct    menu_item    *Next;
};

struct menu_item Menu[5]={
  {"Volume         ", NULL, NULL, NULL, &Menu[1]},        // [0]
  {"Power          ", NULL, NULL, &Menu[0], &Menu[2]},    // [1]
  {"Light          ", NULL, NULL, &Menu[1], &Menu[3]},    // [2]
  {"U min of batt  ", NULL, NULL, &Menu[2], &Menu[4]},    // [3]
  {"Autotune       ", NULL, NULL, &Menu[3], NULL}         // [4]
  };


Позволяет легко описывать многоуровневое меню (в приведённом фрагменте объявлено одноуровневое) и работать с ним с достаточной степенью абстракции.
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 28 2007, 10:21
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Продолжаем разговор... Считаю, что тема организации структуры меню не исчерпана. На avrfreaks.net нашел интересный проект MicroMenu - организация иерархического меню. Написан под GCC. Как прикрутить данный проект к IAR (v.4.12A)?
Go to the top of the page
 
+Quote Post
beer_warrior
сообщение Mar 28 2007, 10:44
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380



Цитата
Как прикрутить данный проект к IAR (v.4.12A)?

Ручками. С и в Африке С. Т.е. могут возникнуть вопросы только с нестандартыми вещеми. Это преодолимо.


--------------------
Вони шукають те, чого нема,
Щоб довести, що його не існує.
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 28 2007, 12:11
Сообщение #10


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Забыл приложить файл... Я GCC не силен. Сделал следующее :
1) typedef struct {
void *Next;
void *Previous;
void *Parent;
void *Sibling;
FuncPtr SelectFunc;
FuncPtr EnterFunc;
const char Text[];
} __flash Menu_Item; //PROGMEM

2)pgm_read_word заменил на __load_program_memory. Хотя первая читает слово из памяти, а вторая байт.
В результате:

Error[Pe146]: too many initializer values D:\...\menu.c 29
Error[Pe167]: argument of type "FuncPtr __flash *" is incompatible with parameter of type "unsigned char const __flash *" D:\...\menu.c 53

Вопрос тем, кто не считает ниже своего достоинства разбираться в чужом коде. Очень нужно организовать пользовательское меню для графического индикатора.
Прикрепленные файлы
Прикрепленный файл  MicroMenu.zip ( 3.53 килобайт ) Кол-во скачиваний: 658
 
Go to the top of the page
 
+Quote Post
MRW
сообщение Mar 28 2007, 14:09
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 17-06-04
Пользователь №: 36



Используем это MicroMenu. Вещь просто супер. Легко использовать, памяти жрет мало. Работать удобно. Правда работаем под GCC. Подправили его немного под себя.
Go to the top of the page
 
+Quote Post
beer_warrior
сообщение Mar 28 2007, 14:29
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380



Цитата
Error[Pe146]: too many initializer values D:\...\menu.c 29 Error[Pe167]: argument of type "FuncPtr __flash *" is incompatible with parameter of type "unsigned char const __flash *" D:\...\menu.c 53

А сказать, каким это строкам соответсвует слабо?


--------------------
Вони шукають те, чого нема,
Щоб довести, що його не існує.
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 28 2007, 18:45
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(beer_warrior @ Mar 28 2007, 14:29) *
А сказать, каким это строкам соответсвует слабо?

Вот листинг. Что еще необходимо для портирования этого проекта на ИАР?


Вот листинг...
to MRW. А можно посмотреть на Вашу практическую реализацию данного меню?
Прикрепленные файлы
Прикрепленный файл  menu_listing.rar ( 881 байт ) Кол-во скачиваний: 297
 
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 28 2007, 19:25
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(alux @ Mar 28 2007, 18:45) *
Вот листинг. Что еще необходимо для портирования этого проекта на ИАР?
Вот листинг...
to MRW. А можно посмотреть на Вашу практическую реализацию данного меню?

По первой ошибке...
Количество аргументов при определении Menu_Item меньше, чем Вы пытаетесь впихнуть.

И общее замечание - люди готовы помочь, но заставлять их кликать столько раз, чтобы распаковать и посмотреть листинг ? Так можно отбить эту готовность ohmy.gif


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 28 2007, 20:01
Сообщение #15


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(Dog Pawlowa @ Mar 28 2007, 19:25) *
По первой ошибке...
Количество аргументов при определении Menu_Item меньше, чем Вы пытаетесь впихнуть.

При определении структура Menu_Item имеет 7 членов, при инициализации - тоже 7. Очевидно, что проблема связана с инициализацией cons char Text[] = {0x00}. Почему GCC это схавал, а IAR - плюется?
Цитата(Dog Pawlowa @ Mar 28 2007, 19:25) *
И общее замечание - люди готовы помочь, но заставлять их кликать столько раз, чтобы распаковать и посмотреть листинг ? Так можно отбить эту готовность ohmy.gif

Почему-то мне не удалось присоединить файлы с расширением .с Поэтому прилагаю оригинальный архив с исходником для GCC.
Господа "знающие", может проще и быстрее будет проверить данный исходник на IAR, дабы избежать ненужных вопросов. Уверен, данный проект интересен многим.
Прикрепленные файлы
Прикрепленный файл  MicroMenu.rar ( 3.4 килобайт ) Кол-во скачиваний: 394
 
Go to the top of the page
 
+Quote Post
MRW
сообщение Mar 28 2007, 20:38
Сообщение #16


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 17-06-04
Пользователь №: 36



// Menus define:
void KeySC (void); // Прототипы фуекций
void TimeMenu1 (void);
void TimeMenu0 (void);
void FPout (void);
void Fauto (void);
void Fstop (void);
void FPr0 (void);
void FPr1 (void);
void FPr2 (void);
void FPr3 (void);
// Главное меню
MAKE_MENU(POUT,STAT,PARAM,NULL_ENTRY,NULL_ENTRY,FPout,TimeMenu0,"Pout");
MAKE_MENU(STAT,PARAM,POUT,POUT,AUTO,KeySC,TimeMenu1,"Stat");
MAKE_MENU(PARAM,POUT,STAT,POUT,PR1,KeySC,TimeMenu1,"Prtr");
// Подменю STAT
MAKE_MENU(AUTO,STOP,HAND,STAT,okAUTO,KeySC,TimeMenu0,"Auto");
MAKE_MENU(okAUTO,NULL_ENTRY,NULL_ENTRY,NULL_ENTRY,NULL_ENTRY,KeySC,Fauto,"end ");
MAKE_MENU(STOP,HAND,AUTO,STAT,okSTOP,KeySC,TimeMenu0,"Stop");
MAKE_MENU(okSTOP,NULL_ENTRY,NULL_ENTRY,NULL_ENTRY,NULL_ENTRY,KeySC,Fstop,"end ");
MAKE_MENU(HAND,AUTO,STOP,STAT,NULL_ENTRY,KeySC,TimeMenu0,"Hand");
// Подменю PARAM
MAKE_MENU(PR1,NULL_ENTRY,NULL_ENTRY,PARAM,SetParam,FPr1,FPr0,"Pr ");
MAKE_MENU(SetParam,NULL_ENTRY,NULL_ENTRY,PR1,NULL_ENTRY,FPr3,FPr2,"__ ");

Это основное описание. Как я уже говорил, работаем на GCC. Изменения незначительны. Из всех вариантов, которые мы использовали, это самый удобный в использовании, пасширении/изменении, и наименьший по объему памяти.
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 29 2007, 10:28
Сообщение #17


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Первую ошибку можно обойти, указав размер массива Text[6] при определении Menu_Item.
А вот со второй ошибкой не могу справится. В чем же дело?
Go to the top of the page
 
+Quote Post
Kolia
сообщение Mar 30 2007, 13:59
Сообщение #18


Частый гость
**

Группа: Свой
Сообщений: 188
Регистрация: 28-09-06
Из: Minsk
Пользователь №: 20 762



Выкладываю исходник простого и удобного меню для HD44780.
Новигация осуществляется при помощи 3 клавиш, плюс добавлена процедура редактирования переменных этими же клавишами. В общем при помощи этого меню и трех клавиш можно сорать полноценное устройство.
Прикрепленные файлы
Прикрепленный файл  Menu.zip ( 2.83 килобайт ) Кол-во скачиваний: 653
 
Go to the top of the page
 
+Quote Post
beer_warrior
сообщение Mar 30 2007, 14:44
Сообщение #19


Профессионал
*****

Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380



Цитата
А вот со второй ошибкой не могу справится. В чем же дело?

Поблема в разной реализации доступа к чтению констант. Неоспоримым преимуществом ИАРа есть свободное использование инструкции LPM в к любой константе с модификатором _flash.
В gcc это обходится с помошью специальных процедур чтения байтов. ИМХО в макросах затерялся модификатор _flash используемый некорректно. Для исправления можно объявить все простыми константами и работать с ними в памяти. Потом найти лишний _flash или PROGMEM


--------------------
Вони шукають те, чого нема,
Щоб довести, що його не існує.
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Apr 1 2007, 22:10
Сообщение #20


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(alux @ Mar 29 2007, 10:28) *
Первую ошибку можно обойти, указав размер массива Text[6] при определении Menu_Item.
А вот со второй ошибкой не могу справится. В чем же дело?

Очевидно, что в параметрах некой функции вместо указателя на функцию используется указатель на unsigned char const. Или наоборот.
В любом случае полезно локализовывать место ошибки. Если в одной строке несколько мест, вызывающих сомнение, то такую строку полезно разбить на несколько, благо С это позволяет.
Go to the top of the page
 
+Quote Post
Яrik
сообщение Jul 13 2007, 14:44
Сообщение #21


Частый гость
**

Группа: Новичок
Сообщений: 110
Регистрация: 8-01-07
Из: Украина
Пользователь №: 24 216



Только сильно не ругайте:
Решил попробывать код предложеный Andy_F:
Код
struct menu_item
{    unsigned char Name[17];
    struct     menu_item    *Parent;
    struct    menu_item    *Child;
    struct    menu_item    *Prev;
    struct    menu_item    *Next;
};

struct menu_item Menu[5]={
  {"Volume         ", NULL, NULL, NULL, &Menu[1]},        // [0]
  {"Power          ", NULL, NULL, &Menu[0], &Menu[2]},    // [1]
  {"Light          ", NULL, NULL, &Menu[1], &Menu[3]},    // [2]
  {"U min of batt  ", NULL, NULL, &Menu[2], &Menu[4]},    // [3]
  {"Autotune       ", NULL, NULL, &Menu[3], NULL}         // [4]
  };

но чего то ругается, пишет undefined symbol 'Menu' в строке {"Volume ", NULL, NULL, NULL, &Menu[1]}, // [0]
Go to the top of the page
 
+Quote Post
IceS
сообщение Jul 16 2007, 21:43
Сообщение #22


Участник
*

Группа: Свой
Сообщений: 43
Регистрация: 17-10-06
Из: Санкт Петербург
Пользователь №: 21 387



Цитата(Яrik @ Jul 13 2007, 18:44) *
но чего то ругается, пишет undefined symbol 'Menu' в строке {"Volume ", NULL, NULL, NULL, &Menu[1]}, // [0]

У меня IAR 4.30 скомпилил без проблем.

Вернее у меня не был определен NULL, после
Код
#define NULL 0

все скомпилировалось нормально

Сообщение отредактировал IceS - Jul 16 2007, 21:44
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 7 2007, 10:58
Сообщение #23


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



По поводу Micro-Menu... При попытке вызова SET_MENU(Level1Item1); как указано в псевдокоде (MicroMenu.zip) программа вылетает. Пробовал определить структуру меню в ОЗУ. Не помогает. Вот мой пример:
Код
#include <inavr.h>        
#include "defines.h"
#include "i2c.h"
#include "tic154.h"
#include "Menu.c"

// Prototypes:
void Level1Item1Sub1_Text(void);
void Level1Item1Sub1_Func(void);


const char Buffer[]="OPTIONS";

// Menus:
MAKE_MENU(Level1Item1, Level1Item2, Level1Item3, NULL_ENTRY, Level1Item1Sub1, NULL_FUNC, NULL_FUNC, "ITEM 1");
MAKE_MENU(Level1Item2, Level1Item3, Level1Item1, NULL_ENTRY , NULL_ENTRY, NULL_FUNC, NULL_FUNC, "ITEM 2");
MAKE_MENU(Level1Item3, Level1Item1, Level1Item2, NULL_ENTRY, NULL_ENTRY, NULL_FUNC, NULL_FUNC, "ITEM 3");

MAKE_MENU(Level1Item1Sub1, NULL_ENTRY , NULL_ENTRY , Level1Item1, NULL_ENTRY,Level1Item1Sub1_Func, Level1Item1Sub1_Text, NULL_TEXT);

// Functions:
void Level1Item1Sub1_Text(void)
{
    char Buffer[] = "*YNAMIC MENU TEXT";

    Buffer[0] = 'D';

        LCD_Put_Str(Buffer);

//    LCD_Write_SRAM_String(Buffer);
}

void Level1Item1Sub1_Func(void)
{
//    Shutdown_App();
}

//..........................................

void main (void)
{
  // Initialise
  TWI_Init(100);        // set TWI bit rate to 100KHz    
  LCD_Init();

  SET_MENU_WRITE_FUNC(Buffer);
  SET_MENU(Level1Item1);
  SET_MENU(PARENT);
  SET_MENU(SIBLING);    
  SET_MENU(PREVIOUS);
  SET_MENU(NEXT);    
  GO_MENU_FUNC(SELECTFUNC);    
}

//################################
// Menu.c

#include "Menu.h"
#include <string.h>

Menu_Item        Null_Menu = {(void*)0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0, {0x00}};
Menu_Item*       CurrMenuItem;
WriteFuncPtr*    WriteFunc;

void MenuChange(Menu_Item* NewMenu)
{
    if ((void*)NewMenu == (void*)&NULL_ENTRY)
      return;

    CurrMenuItem = NewMenu;
    
    #if defined(MENU_USE_SRAM_BUFFER)
        #if (MENU_USE_SRAM_BUFFER < 1)
          #error Menu SRAM Buffer Size not Defined!
        #endif
        
        char Buffer[MENU_USE_SRAM_BUFFER];
        strcpy(Buffer, CurrMenuItem->Text);  //strcpy_P

        ((WriteFuncPtr)WriteFunc)((const char*)Buffer);
    #else
        ((WriteFuncPtr)WriteFunc)((const char*)CurrMenuItem->Text);    
    #endif

    GO_MENU_FUNC(ENTERFUNC);
}

void MenuFunc(FuncPtr* Function)
{
    if ((void*)Function == (void*)NULL_FUNC)
      return;

    ((FuncPtr)Function)();
}

//#####################################################
//Menu.h

#ifndef MENU_H
#define MENU_H

//#include <pgmspace.h>

// Typedefs:
typedef void (*FuncPtr)(void);
typedef void (*WriteFuncPtr)(const char*);

typedef struct {       // __flash
    void       *Next;
    void       *Previous;
    void       *Parent;
    void       *Sibling;
    FuncPtr     SelectFunc;
    FuncPtr     EnterFunc;
    const char  Text[6];
} Menu_Item;

// Externs:
extern WriteFuncPtr*    WriteFunc;
extern Menu_Item        Null_Menu;
extern Menu_Item*       CurrMenuItem;

// Defines and Macros:
#define NULL_ENTRY Null_Menu
#define NULL_FUNC  (void*)0
#define NULL_TEXT  0x00
#define MENU_USE_SRAM_BUFFER 32


#define PREVIOUS   *((Menu_Item*)(&CurrMenuItem->Previous))
#define NEXT       *((Menu_Item*)(&CurrMenuItem->Next))
#define PARENT     *((Menu_Item*)(&CurrMenuItem->Parent))
#define SIBLING    *((Menu_Item*)(&CurrMenuItem->Sibling))
#define ENTERFUNC  *((Menu_Item*)(&CurrMenuItem->EnterFunc))
#define SELECTFUNC *((Menu_Item*)(&CurrMenuItem->SelectFunc))

#define MAKE_MENU(Name, Next, Previous, Parent, Sibling, SelectFunc, EnterFunc, Text) \
        extern Menu_Item Next;     \
    extern Menu_Item Previous; \
    extern Menu_Item Parent;   \
    extern Menu_Item Sibling;  \
    Menu_Item Name = {(void*)&Next, (void*)&Previous, (void*)&Parent, (void*)&Sibling, (FuncPtr)SelectFunc, (FuncPtr)EnterFunc, { Text }}

#define SET_MENU_WRITE_FUNC(x) \
    WriteFunc = (WriteFuncPtr*)&x;

#define SET_MENU(x) \
    MenuChange((Menu_Item*)&x);
    
#define GO_MENU_FUNC(x)  \
    MenuFunc((FuncPtr*)&x)
    
#define EXTERN_MENU(Name) \
    extern Menu_Item Name;

// Prototypes:
void MenuChange(Menu_Item* NewMenu);
void MenuFunc(FuncPtr* Function);

#endif

Помогите, пожалуйста, разобраться с этим меню.
Go to the top of the page
 
+Quote Post
id_Alx
сообщение Aug 28 2007, 18:13
Сообщение #24


Частый гость
**

Группа: Участник
Сообщений: 79
Регистрация: 12-08-06
Из: Минск
Пользователь №: 19 504



Цитата(alux @ Mar 29 2007, 13:28) *
Первую ошибку можно обойти, указав размер массива Text[6] при определении Menu_Item.
А вот со второй ошибкой не могу справится. В чем же дело?

Для IAR получилось так...
Прикрепленные файлы
Прикрепленный файл  umenu.rar ( 1.44 килобайт ) Кол-во скачиваний: 321
 
Go to the top of the page
 
+Quote Post
Unknown_User
сообщение Sep 9 2007, 18:18
Сообщение #25





Группа: Новичок
Сообщений: 11
Регистрация: 9-09-07
Пользователь №: 30 404



Очень интересная, а главная злободневная для меня тема, жаль что раньше не набрёл на этот форум )).
Меня интересует как вы решаете проблему размещения меню в памяти ? У меня сейчас всё меню создаётся при включении девайса и так там в памяти и висит. Для этих целей в прикрученой внешней оперативке под меню отведен килобайт памяти.
Ну и приведу схематично то что сделано у меня.
Требовалось создать иерархическое меню, причём в пунктах меню может быть что угодно от логотипа прибора и его настроек до отображения сигнала.
Первым делом объявляеться структурка. Эта структура сама по себе не используеться, но все остальные типы меню содержат точно такие же поля, объявленые в той же последовательности:
struct CustomMenu{
unsigned int ID;//номер, уникальный для каждого экземпляра меню
unsigned char Count;//количество подменю
unsigned char State;//текущее состояние меню
struct CustomMenu *Prev;//указатель на предыдущее меню, у главного меню равен NULL
struct CustomMenu **SubMenus;//массив указателей на подменю, на какое из этих подменю нужно //переходить видно по полю State
void ( *OnDraw )( struct CustomMenu *Menu );//указатель на функцию отрисовки
void ( *OnEvent )( struct CustomMenu *Menu, unsigned char Event );//указатель на функцию реакции на события
};
////////////
///
///////////
Далее создаются "потомки" этой структуры, например строчное меню:
struct StringMenu{
//поля "унаследованые" от CustomMenu:
unsigned int ID;//номер, уникальный для каждого экземпляра меню
unsigned char Count;//количество подменю
unsigned char State;//текущее состояние меню
struct CustomMenu *Prev;//указатель на предыдущее меню, у главного меню равен NULL
struct CustomMenu **SubMenus;//массив указателей на подменю, на какое из этих подменю нужно //переходить видно по полю State
void ( *OnDraw )( struct StringMenu *Menu );//функция отрисовки
void ( *OnEvent )( struct StringMenu *Menu, unsigned char Event );//функция реакции на события

//собственные поля
unsigned char **TextStrings;//строки меню; Текущая строка в меню определяеться полем State
};

Далее объявляем функции

void StringMenuOnDraw( struct StringMenu *Menu )//функция отрисовки StringMenu
{
}

void StringMenuOnEven( struct StringMenu *Menu, unsigned char Event );//функция реакции на события //StringMenu
{
}

При создании экземпляра StringMenu присваиваем его полям - указателям на функции соответствующие обработчики.

Здесь удобно то, что можно ко всем экземплярам меню обращаться так же, как к CustomMenu. Если теперь объявим переменную CustomMenu* CMenu и присвоим ей адрес созданного StringMenu *SMenu, то при выполнении кода СMenu->OnDraw( SMenu ); вызовется StringMenuOnDraw.

Добавление нвых элементов можно реализовать так:

void AddMenu( CustomMenu *Menu, unsigned char ID_Parent, unsigned char N_Child, unsigned char ID_Child );

где *Menu - указатель на главное меню; ID_Parent - ID экземпляра меню, в который хотим добавить новое меню: N_Child - номер нового меню в родительском ( по сути индекс нового экземпляра в массиве SubMenus родителя ); ID_Child - ID нового экземпляра меню.

В общем я привёл основную идею, в коде могут попасться и некоторые ошибки и очепятки, но думаю, вполне понятно что я имею в виду )).
Просьба большими кирпичами в меня не кидать и по голове не бить ; - ))
Go to the top of the page
 
+Quote Post
alux
сообщение Sep 27 2007, 15:19
Сообщение #26


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата
Для IAR получилось так...

У меня не получается вызвать меню через символические имена:
Код
void menu_Init(void)
{
  Level1Item1Sub1_Text();
  SET_MENU_WRITE_FUNC(Level1Item1Sub1_Text);
  SET_MENU(Level1Item1);
    delay_ms(1000);
    SET_MENU(PARENT);
    delay_ms(1000);
    SET_MENU(SIBLING);
    delay_ms(1000);
    SET_MENU(PREVIOUS);
    delay_ms(1000);
    SET_MENU(NEXT);
}

Если вызывать через имя меню :
Код
void menu_Init(void)
{
  Level1Item1Sub1_Text();
  SET_MENU_WRITE_FUNC(Level1Item1Sub1_Text);
  SET_MENU(Level1Item1);
    delay_ms(1000);
    SET_MENU(Level1Item2);
    delay_ms(1000);
    SET_MENU(Level1Item3);
    delay_ms(1000);
    SET_MENU(Level1Item1);
    delay_ms(1000);
    SET_MENU(Level1Item2);
}

... то все нормально, т.е. с интервалом в секунду выводятся пункты меню. В оригинальном исходнике символические имя определены так:
Код
#define PREVIOUS   *((Menu_Item*)pgm_read_word(&CurrMenuItem->Previous))
#define NEXT       *((Menu_Item*)pgm_read_word(&CurrMenuItem->Next))
#define PARENT     *((Menu_Item*)pgm_read_word(&CurrMenuItem->Parent))
#define SIBLING    *((Menu_Item*)pgm_read_word(&CurrMenuItem->Sibling))
#define ENTERFUNC  *((FuncPtr*)pgm_read_word(&CurrMenuItem->EnterFunc))
#define SELECTFUNC *((FuncPtr*)pgm_read_word(&CurrMenuItem->SelectFunc))

В исправленной версии от Id_Alx опущен знак &. Добавление & приводит к перезапуску программы. Манипуляции с размерами CSTACK(0x100), RSTACK(0x40) не помогает. В чем же дело?
Go to the top of the page
 
+Quote Post
id_Alx
сообщение Oct 2 2007, 07:19
Сообщение #27


Частый гость
**

Группа: Участник
Сообщений: 79
Регистрация: 12-08-06
Из: Минск
Пользователь №: 19 504



Цитата(alux @ Sep 27 2007, 18:19) *
В исправленной версии от Id_Alx опущен знак &. Добавление & приводит к перезапуску программы. Манипуляции с размерами CSTACK(0x100), RSTACK(0x40) не помогает. В чем же дело?


Вот только не надо не надо добавлять значки ("&"), смысл которых Вам, видимо, не совсем ясен, а потом жаловаться. Вероятность того, что программа заработает корректно после подобных манипуляций очень мала. Версия из моего архива не собирается или не работает после сборки? Я пользуюсь IAR 4.20A.
Go to the top of the page
 
+Quote Post
alux
сообщение Oct 3 2007, 18:53
Сообщение #28


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



У меня меню заработало. Как теперь сделать, чтобы пункты меню выводились не последовательно в одно и то же место дисплея, а отобразить на экране пункты меню одного уровня, и навигацию осуществлять либо стрелочкой, либо инверсией пунктов меню?
Go to the top of the page
 
+Quote Post
admiral
сообщение Apr 8 2008, 11:24
Сообщение #29


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 14-12-07
Из: Беларусь, Гомель
Пользователь №: 33 305



Продолжу тему. У меня возникла необходимость создать грамотное меню с кучей подменю для своего устройства. Облазив этот форум, понял, что наилучший вариант по возможности в дальнейшем расширять меню, по требовательности к памяти... - это micro-menu.
Программирую на CVAVR для МК Мега16
Общий смысл работы этого меню примерно, точнее сказать смутно 05.gif, представляю, поэтому начал потихоньку разбираться что где и как. В интернете по нему информации почти никакой. Нашел сайт создателя с его разработками, но там по теме микроменю ссылка на сайт http://avrfreaks.net/, но туда пускают только зарегеных пользователей. Зарегится мне не получилось. Вот решил тогда здесь спросить у знающих людей.
Предупреждаю заранее, СИ я начал изучать месяц назад, но меню грамотное нужно обязательно, так что не пинайте если что за то, что я взялся за работу не по зубам. По мне так лучше день потерять, потом за пять минут долететь. (с) Как раз поможет углубленно изучит СИ.
В общем так, комментариев там нету. Поэтому первым делом я начал добавлять комментарии. Вот докуда я дошел:
Код
/ MICRO_MENU.H

#ifndef _MENU_H_
#define _MENU_H_

//Тут указываются указатели на функции
typedef void (* FuncPtr) (void);
/*Новый тип FuncPtr - указатель на функцию,
которая ничего не принимает
и не возвращает
*/
typedef void (* WriteFuncPtr) (const char*);
/*Новый тип WriteFuncPtr - указатель на функцию,
входным параметром которой является указатель на строку в ПЗУ,
которая ничего не вовращает
*/
typedef struct PROGMEM {
        void        *Next; //Следующее меню
        void        *Previous; //Предыдущее меню
        void        *Parent; //Родительское меню
        void        *Sibling; //Дочернее меню (вложение)
        FuncPtr     SelectFunc; //Выбор фнкции при выборе меню
        FuncPtr     EnterFunc; //Выбор функции при входе в меню (Применяется после того, как текст меню отображен)
        const char  Text[22]; //Текст меню
} Menu_Item;

//Externs
extern WriteFuncPtr    *WriteFunc; //Переменная-указатель на функцию
extern Menu_Item        Null_Menu; //Переменная типа PROGMEM
extern Menu_Item       *CurrMenuItem; //Переменная-указаетль на данные типа PROGMEM

//Defines and Macros
#define NULL_ENTRY      Null_Menu
#define NULL_FUNC       0
#define NULL_TEXT       0x00

#define PREVIOUS        *((Menu_Item*)pgm_read_word(&CurrMenuItem->Previous))

Вот теперь возник затык на последней строчке.
1. pgm_read_word - то я так понимаю функция из прикрепленного <avr/pgmspace.h> в оригинальном тексте. В примере выше для IAR эта строка отсутствовала, поэтому я тоже ее удалил.
2.Теперь я попытался разобраться для чего эта строка нужна.
В примере использования было так:
Код
SET_MENU(PREVIOUS);

Смотрим что такое SET_MENU
Код
#define SET_MENU(x) \
    MenuChange((Menu_Item*)&x);


Делаем подстановку:
Код
SET_MENU(PREVIOUS); == MenuChange((Menu_Item*)&*((Menu_Item*)(&CurrMenuItem->Previous)));

Вот с этой строкой я не могу разобраться, особенно с сочетанием &*

В общем если есть знающие люди и особенно те, кто уже работал с этим меню, отзовитесь.
Go to the top of the page
 
+Quote Post
sKWO
сообщение Apr 8 2008, 12:16
Сообщение #30


Местный
***

Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530



Цитата(admiral @ Apr 8 2008, 14:24) *
Код
#define PREVIOUS        *((Menu_Item*)pgm_read_word(&CurrMenuItem->Previous))

Вот теперь возник затык на последней строчке.
1. pgm_read_word - то я так понимаю функция из прикрепленного <avr/pgmspace.h> в оригинальном тексте. В примере выше для IAR эта строка отсутствовала, поэтому я тоже ее удалил.

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


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 06:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01665 секунд с 7
ELECTRONIX ©2004-2016