|
|
  |
Реализация меню для работы со знакосинтезирующим ЖКИ, Поделитесь опытом. Пожалуйста. |
|
|
|
Aug 6 2007, 13:34
|
Участник

Группа: Участник
Сообщений: 50
Регистрация: 20-02-07
Пользователь №: 25 515

|
Всех приветствую.
Поделитесь пожалуйста опытом, кто как организует меню для работы со занакосинтезирующим ЖКИ.
Задача: - просмотр информации о состоянии чего-либо; - внесение данных, типа калибровка и т.д.; - кофигурирование; - ну и чего-нибудь еще.... Думаю, в глубину будет уровня 3-4, не больше.
С чего начать? Как организовать иерархию?
Прошу пардон, но на этот момент вопросы только общие, более конкретные, быть может, появятся позже.
Спасибо.
|
|
|
|
|
Aug 6 2007, 14:44
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 6-08-07
Из: Moscow
Пользователь №: 29 586

|
Можно делать следующим образом: описываем структуру одного элемента меню, в которой пишем строку и указатель на функцию, которая вызывается по нажатию кнопки enter или подобной. Код typedef struct { char menu_str[LCD_WIDTH+1]; MENU_HANDLER_PROC func; } S_MENU_ITEM; MENU_HANDLER_PROC - тип-функция void func(void). описывается как typedef void (*MENU_HANDLER_PROC)(void); делаем процедуру вывода меню на экран Код void ShowMenu(S_MENU_ITEM *menu, int element0, int cursor_pos) { ... } тогда процедура самого меню будет выглядеть примерно так: Код void Menu(S_MENU_ITEM *menu) { char ret_menu = 0; int cursor = 0; int element0 = 0; while (!ret_menu) { ShowMenu(menu, element0, cursor); switch(ch) { case VK_UP: // перемещаем вверх курсор, если он не 0, либо первый выводимый элемент меню (element0) // ... break; case VK_DOWN: // то же самое, только с точностью до наоборот // ... break; case VK_ENTER: menu[element0+cursor].func(); break; case VK_EXIT: ret_menu = 1; break; } } } а в обработчиках рекурсивно запускаем эту же функцию Menu, но с другими параметрами. Можно и по-другому, но я делал так. Только структуры хранил во флэше. Отличается только запуск функции-обработчика и вывод строки (а он здесь и не описан).
|
|
|
|
|
Aug 7 2007, 03:54
|
Участник

Группа: Участник
Сообщений: 50
Регистрация: 20-02-07
Пользователь №: 25 515

|
Цитата(GDI @ Aug 6 2007, 18:01)  Смотрел. одно сообщение нашел.
|
|
|
|
|
Dec 18 2007, 10:09
|

Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317

|
Имеется мега16 с подключенными к ней двухстрочным LCD и мартицей кнопок 2х3. Нужно написать достаточно сложную иерархическую менюшку. Подскажите, как это лучше реализовать? Сейчас я это сделал целиком на case`ах, т.е. в зависимости от кадра, в котором нахожусь, я анализирую варианты нажатия кнопок, что - то вроде этого: Код switch (frame_index) { .... case FRAME_SET_TIME: case FRAME_SET_DATE: switch (button_mask) { case BTN_YES: if(systime_set(&systime_input)) {// Неправильный ввод // Если время введено неправильно, // то возвращаться следует в этот кадр stack_push(&frame_stack,frame_index); frame_index = FRAME_INVALID_DATA; } else frame_index = FRAME_SET_DONE; print_flag = 1; break; case BTN_NO: frame_index = stack_pop(&frame_stack); print_flag = 1; break; ... } Оно работает вполне неплохо, но уж слишком большого размера получается и код и прошивка. Добавить какой-то новый пункт - очень трудоемкая задача. Есть некоторые мысли, что бы сделать что-то типа шаблона меню а также некоторые более идиотские идеи. Но возникает сомнение, не сожрет ли такая обработка все ресурсы (скорее всего срам память) контроллера? Подскажите, кто сталкивался с такой задачей?
|
|
|
|
|
Dec 18 2007, 10:30
|

Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317

|
Цитата(umup @ Dec 18 2007, 13:16)  сделать массив struct-ов, в каждом - текст пункта меню, тип (unsigned/signed 8-,16-,32-bit, string, список) и адрес переменной, которая отображается в этом пункте. каждому пункту присвоить уникальный номер и номер группы (подменю), в которую входит данный пункт. навигация и редактирование в таком варианте очень простые. У меня была такая мысль. Но меня настораживает вопрос, сколько памяти съест такая реализация и как быстро это будет работать (хотя, это менее критично)?
|
|
|
|
|
Dec 18 2007, 10:57
|

Местный
  
Группа: Свой
Сообщений: 226
Регистрация: 2-06-06
Пользователь №: 17 720

|
Цитата сколько памяти съест такая реализация ну посчитайте - сколько текста и данных на каждый пункт меню, плюс логика - навигация очень немного (фактически переход на следующий/предыдущий пункт с проверкой находится ли след.пункт в одном подменю с предыдущим, и переход в другое подменю по номеру), редактирование параметров - немного больше. думаю по коду в 0.5 - 1 килобайт можно уложиться. по быстроте вообще проблем быть не должно - состояние изменяется только при нажатии клавиш редактирования.
Сообщение отредактировал umup - Dec 18 2007, 10:58
|
|
|
|
|
Feb 23 2008, 14:15
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 1-07-07
Пользователь №: 28 824

|
А как вам такой принцип реализации меню?
menu.rar ( 108.33 килобайт )
Кол-во скачиваний: 236 В приложенном файле реализация для обычного консольного приложения Windows, с целью показать принцип. Реализация для атмеги есть на работе, почти полная версия, вкупе с обработкой клавиатуры. Функция main для атмеги выглядит примерно так: Код while(1) { ....... if(MAIN_NOT_BUSY) //условие, дающие разрешение на работу терминала в этом цикле next_terminal_task(); } Ф функции next_terminal_task выполняется только один шаг из текущей задачи - или вывод одного символа на дисплей или один скан клавиатуры или обработка нажатой клавиши, или еще чего-то. Но это уже другая история. А идея само меню реализовать в виде стека, в котором хранятся указатели на активное меню, оказалась довольно удачной. Попробуйте.
Сообщение отредактировал ochkarik_ - Feb 23 2008, 14:28
|
|
|
|
|
Feb 24 2008, 09:59
|

Участник

Группа: Свой
Сообщений: 66
Регистрация: 28-01-08
Из: Николаев
Пользователь №: 34 507

|
CODE
/****************************************************************/ /* Menu */ /****************************************************************/ // Структура хранящая пункты меню typedef struct { unsigned char __flash *itemText; // Название Пункта void (*itemFunction)(char); // Вызываемая функция char itemArg; // Аргумент } _menuItem; _menuItem MenuItem;
// Названия static __flash unsigned char _max[] = {77,65,88,32,72,97,190,112,0}, _min[] = {77,73,78,32,72,97,190,112,0}, _sens[] = {171,121,179,99,191,179,184,191,0}, _timeout[] = {84,105,109,101,32,79,117,116,0}, _beep[] = {66,101,101,112,72,114,115,20,0}, _sec[] = {83,104,111,119,32,83,101,99,0}, _stime[] = {83,101,116,32,84,105,109,101,0}, _deadzone[] = {68,101,97,100,90,111,110,101,0}, _service[] = {42,42,42,42,42,42,42,42,0};
// Загрузка структуры static _menuItem __flash MenuItems[] = { _max, SetMaxV, 3, _min, SetMinV, 2, _sens, Sensitivity, 0, _timeout, SetTimeOut, 0, _deadzone, SetDead, 0, _beep, SetBeepHrs, 0, _sec, SetShowSec, 0, _stime, SetTime, 0, _service, Service, 0 }; /****************************************************************/
void Menu(char inp) { static _menuItem __flash *_mptr = MenuItems; switch (inp) { case NEXT: // Next item if (++_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (_menuItem)) - 1]) _mptr = MenuItems; OutStrFlash(_mptr->itemText,0x01); PrintSymbol(4,0x00); /* Вывод следующего пункта в след. строку */ if (++_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (_menuItem)) - 1]) { _mptr = MenuItems; } OutStrFlash(_mptr->itemText,0x40); if (--_mptr < MenuItems) // Set pointer to the last item _mptr = &MenuItems[(sizeof MenuItems)/(sizeof (_menuItem)) - 1]; Dev_State = MENU; break;
case SELECT: // Выполнение выбранного пункта Ctrl = 0; Dev_State = MENU; (*_mptr->itemFunction)(_mptr->itemArg); ClrScr(); break; } }
Где то так делал я , на примере ув. Леонида Ивановича. Для навигации использовал 2 кнопки. Меню одноуровневое, но добавить ещё уровней не проблема. Вместо указателя на исполняемую функцию нужно подставить указатель на функцию подменю. Работает это дело быстро, да и места не много занимает.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|