|
Структура меню |
|
|
|
Nov 15 2006, 17:36
|
Участник

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

|
Народ, как Вы делаете меню для своих девайсов? Интересует структура. Столкнулся с проблемой: вывод на дисплей (HD44780 совместимый) меню получается малопонятной и (главное) неприспособленный для добавления новых пунктов меню. Никогда раньше не приходилось делать меню, так что научите  Может у кого есть каки-нить наработки\библиотеки? Заранее большое спасибо...
|
|
|
|
|
Nov 15 2006, 22:00
|
Частый гость
 
Группа: Свой
Сообщений: 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
--------------------
Вся жизнь - ништяк, все бабы - леди, а солнце - шар дающий свет
|
|
|
|
|
Nov 16 2006, 09:28
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(sind-rom @ Nov 15 2006, 20:36)  Народ, как Вы делаете меню для своих девайсов? Интересует структура. Столкнулся с проблемой: вывод на дисплей (HD44780 совместимый) меню получается малопонятной и (главное) неприспособленный для добавления новых пунктов меню. Никогда раньше не приходилось делать меню, так что научите  Может у кого есть каки-нить наработки\библиотеки? Заранее большое спасибо... Я, например, так делал: Код /* 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); } } }
|
|
|
|
|
Nov 16 2006, 09:39
|

Гуру
     
Группа: Свой
Сообщений: 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
|
|
|
|
|
Nov 16 2006, 09:42
|
Частый гость
 
Группа: Свой
Сообщений: 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] }; Позволяет легко описывать многоуровневое меню (в приведённом фрагменте объявлено одноуровневое) и работать с ним с достаточной степенью абстракции.
|
|
|
|
|
Mar 28 2007, 12:11
|
Знающий
   
Группа: Свой
Сообщений: 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 Вопрос тем, кто не считает ниже своего достоинства разбираться в чужом коде. Очень нужно организовать пользовательское меню для графического индикатора.
|
|
|
|
|
Mar 28 2007, 14:09
|
Участник

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

|
Используем это MicroMenu. Вещь просто супер. Легко использовать, памяти жрет мало. Работать удобно. Правда работаем под GCC. Подправили его немного под себя.
|
|
|
|
|
Mar 28 2007, 18:45
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(beer_warrior @ Mar 28 2007, 14:29)  А сказать, каким это строкам соответсвует слабо? Вот листинг. Что еще необходимо для портирования этого проекта на ИАР? Вот листинг... to MRW. А можно посмотреть на Вашу практическую реализацию данного меню?
|
|
|
|
|
Mar 28 2007, 19:25
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(alux @ Mar 28 2007, 18:45)  Вот листинг. Что еще необходимо для портирования этого проекта на ИАР? Вот листинг... to MRW. А можно посмотреть на Вашу практическую реализацию данного меню? По первой ошибке... Количество аргументов при определении Menu_Item меньше, чем Вы пытаетесь впихнуть. И общее замечание - люди готовы помочь, но заставлять их кликать столько раз, чтобы распаковать и посмотреть листинг ? Так можно отбить эту готовность
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Mar 28 2007, 20:01
|
Знающий
   
Группа: Свой
Сообщений: 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)  И общее замечание - люди готовы помочь, но заставлять их кликать столько раз, чтобы распаковать и посмотреть листинг ? Так можно отбить эту готовность  Почему-то мне не удалось присоединить файлы с расширением .с Поэтому прилагаю оригинальный архив с исходником для GCC. Господа "знающие", может проще и быстрее будет проверить данный исходник на IAR, дабы избежать ненужных вопросов. Уверен, данный проект интересен многим.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|