Меню на LCD. Помогите разобрать код.

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
wellcom
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Чт фев 24, 2011 13:00:49

Меню на LCD. Помогите разобрать код.

Сообщение wellcom »

Нарыл в просторах Инета вот такой код реализации меню на LCD. Начинаю только программировать на С. До конца не могу понять его принцип работы. Вопросы - смотреть сам код и коментарии. Прошу помощи! :roll:

Код: Выделить всё

from: http://telesys.ru/wwwboards/mcontrol/690/messages/60113.shtml

Typedef //объявим тип как структуру
struct _menuItem   {
         char flash   *itemText; //текстовый пункт???
         void      (*itemFunction)(char); //указатель на ф-цию которая должна выполняться???????
         char      itemArg;    //параметр который должен передаваться в выполняемую ф-цию???
         }
MenuItem; //переменная

//что за масив (-ы)???
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 '+':   // следующий пункт
         if (++_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1])   //Установить указатель на последний элемент...никак не могу вкурить все эти скобки здесь
            _mptr = MenuItems; //присвоить указателю
         break;
      case '-':   // Предыдущий пункт
         if (--_mptr < MenuItems)   // Установить указатель на последний елемент
            _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); //выполнить ф-цию с параметром....???
         }
      }
Вложения
__menu (by_Bill).c
(2.06 КБ) 211 скачиваний
:solder: 32-х ядерный процессор из П213В
vovik15
Опытный кот
Сообщения: 768
Зарегистрирован: Сб ноя 08, 2008 18:32:36
Контактная информация:

Re: Меню на LCD. Помогите разобрать код.

Сообщение vovik15 »

я ентот код сам понять не могу,гораздо проще свой написать
Аватара пользователя
Olecorp
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Пт май 21, 2010 01:15:10
Откуда: Латвия

Re: Меню на LCD. Помогите разобрать код.

Сообщение Olecorp »

Код: Выделить всё

if (++_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1])   //Установить указатель на последний элемент...никак не могу вкурить все эти скобки здесь
    _mptr = MenuItems; //присвоить указателю


_mptr - указатель на структуру _menuItem, точнее на один из массива MenuItems[] состоящим из _menuItem'ов. изначально указывает на первый.

++_mptr - означает передвинуть (пре-инкрементировать) указатель на следующий _menuItem.

(sizeof MenuItems), (sizeof (struct _menuItem)) - получаем размер в байтах всего массива итемов и сколько занимает один итем.
делим (sizeof MenuItems)/(sizeof (struct _menuItem)) и получаем КОЛИЧЕСТВО итемов в массиве.
допустим, размер массива - 15, а отдельного итема - 5. делим и получаем, что в массиве 3 итема.

оператор "&" - получение адреса (указателя) на что-либо.

&MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1] - получаем адрес последнего элемента массива.
первый элемент - 0, а "кол-во элементов - 1" - последний. это такой способ узнать сколько элементов в массиве, нигде заранее не задавая это количество.

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

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


Код: Выделить всё

if (Device->_devType==UNKNOWN_TYPE && _mptr->itemFunction!=SetType) // и здесь непонятно....

где-то определенна структура Device, имеющая поле _devType.
строка проверяет, если Device->_devType равно UNKNOWN_TYPE, и функция, которая будет вызвана - не SetType, то чёто ругаемся.

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

Код: Выделить всё

__insert,   Edit,      INSERT_BUFFER,

то выполнится функция Edit(INSERT_BUFFER);
Аватара пользователя
wellcom
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Чт фев 24, 2011 13:00:49

Re: Меню на LCD. Помогите разобрать код.

Сообщение wellcom »

Огромное кошачье МЯУ ( :beer: Спасибо :) ) за толкование. Теперь все прояснилось...вроде как...
Это меню работает на одной строке (просто меняются названия пунктов). Что бы к нему такое прикрутить, чтобы оно стало на 4 строки, где было бы видно предыдущие и следующие пункты со стрелкой на текущий (выбираемый) пункт? Есть у кого какие идеи?
:solder: 32-х ядерный процессор из П213В
Мастер Ломастер
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город
Контактная информация:

Re: Меню на LCD. Помогите разобрать код.

Сообщение Мастер Ломастер »

воспользуйтесь библиотечкой TUI
битва с дураками проиграна, победители торжествуют. слава победителям!
Аватара пользователя
wellcom
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Чт фев 24, 2011 13:00:49

Re: Меню на LCD. Помогите разобрать код.

Сообщение wellcom »

Мастер Ломастер писал(а):воспользуйтесь библиотечкой TUI


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

а пока я думаю может завести еще 2 переменные что бы сохранить указатели для вывода строк меню перед и после текущего...
:solder: 32-х ядерный процессор из П213В
Аватара пользователя
wellcom
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Чт фев 24, 2011 13:00:49

Re: Меню на LCD. Помогите разобрать код.

Сообщение wellcom »

Сделал вот, мож кому пригодиться :idea:
Меню в три строки (использовал 4-х строчный ЛСД), верхняя строка указывает на предыдущее наименование меню, средняя всегда активная (для выбора), нижняя указывает на следующее наименование меню.
На самом деле, этот код очень хорош для одно строчного ЛСД, так как активное (для выбора) меню всегда находиться в одной и той же строке.

Преимущество заключается в возможности очень быстро наращивать количество пунктов меню, не меняя код обработки, а всего лишь добавив/убрав в массивах наименование пунктов меню.
управляется 4-мя кнопками (+/- (они же вверх/вниз), кнопкой выбора, назовем ее "ENTER" (исполнение какой либо ф-ции ), и кнопкой "MENU", он же "EXIT" из меню
Паял :solder: в CodeVisionAVR 2.05.3
Вот что получилось

Код: Выделить всё

typedef struct _menuItem
   {
    char flash   *itemText;                  //указатель на текстовый пункт
    void      (*itemFunction)(char); //указатель на ф-цию которая должна выполняться
    char      itemArg;                    //аргумент к ф-ции
   } MenuItem;

//масивы пунктов меню
static flash char   _menu1[]   = "MENU-1          ",
         _menu2[]   = "MENU-2          ",
         _menu3[]   = "MENU-3          ",
         _menu4[]   = "MENU-4          ",
         _menu5[]   = "MENU-5          ",
         _menu6[]   = "MENU-6          ",
         _menu7[]   = "MENU-7          ";
//пункт меню (обьявляем как масив структур)
static MenuItem MenuItems[] =   {
         _menu1,      0,           0,
         _menu2,      0,      0,
         _menu3,            0,      0,
         _menu4,           0,      0,
         _menu5,      0,      0,
         _menu6,      0,      0,
         _menu7,           0,      0
         };
//                     /текст/          /ф-ция/         /аргумент/

// ** Menu   -- the main menu fuction
//
void Menu(void)
 {
        MenuItem *_mptr = MenuItems;                   //загрузить указатель на текущий пункт (первый пункт)
        MenuItem *_next_menu = MenuItems+1;      //указатель на следующий пункт меню
        MenuItem *_previous_menu = &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1];//указатель на предыдущий пункт (в начале вычислить последний пункт меню)
        uchar input_menu=0; //флаг входа в меню
      for (;;)
                {
                  GetKEY_Event();  //проверяем кнопки (ваша ф-ция)
                   if (ucPressedKey==0x04)//если была нажата кн. МЕНЮ
                   {
                     if (input_menu==0)
                      {
                       input_menu =1; //флаг входа в меню
                      }
                      else
                      {
                       input_menu =0; //флаг вЫхода из меню
                      };
                   };
                   if (ucPressedKey&&input_menu)//если кнопка была нажата а так же перед этим была нажата кнопка меню
                   {   
                    lcd_clear();  //очистить ЛСД
                    lcd_gotoxy(5,0);
                    lcd_putsf(_previous_menu->itemText); //вывести предыдущий пункт по указателю
                    lcd_gotoxy(4,1);
                    lcd_putchar(0x3E);  //стрелочка указывающая на активный пункт меню
                    lcd_putsf(_mptr->itemText); //вывести активный пункт по указателю (выбраное меню)
                    lcd_gotoxy(5,2);
                    lcd_putsf(_next_menu->itemText);//вывести следующий пункт по указателю
                    switch (ucPressedKey)  //какая кнопка нажата?
                            {
                            case 1:  //кнопка "+"
                                    _previous_menu = _mptr;  //ПРЕДЫДУЩИЙ (НАД активным пунктом меню, станет активное меню)
                                    _mptr++;
                                    if (_mptr > &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1])//если вылезли за пределы масива...
                                    {
                                     _previous_menu = &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1];//последняя строка меню (над активной)
                                     _mptr = MenuItems;                                                              //первая строка меню (активная)
                                     _next_menu = MenuItems+1;                                                       //вторая строка меню (под активной)
                                    }
                                    if (_mptr == &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1])//если указ == посл.пункту
                                    {
                                     _next_menu = MenuItems;//показать первую строку меню
                                    }
                                    else
                                    {
                                     _next_menu = _mptr+1; //след пункт меню
                                    }
                            break;
                            case 2: // кнопка "-"
                                    _previous_menu --; //в строку над активным
                                    if(_previous_menu < MenuItems) //если вылезли поставить последнее
                                    {
                                     _previous_menu = &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1];
                                    }
                                    _mptr--;              //идем в обратную сторону от текущего пункта меню (активная строка)
                                    if (_mptr < MenuItems)//если указатель текущего пункта вылез за масив при уменьшении
                                    {                                                                      
                                     _mptr = &MenuItems[(sizeof MenuItems)/(sizeof (struct _menuItem)) - 1];//последняя строка меню (активная)
                                     _next_menu = MenuItems;                                                //первая строка меню (под активной)
                                    }
                                    else
                                    {
                                     _next_menu = _mptr+1;   //следующей строкой меню на ЛСД станет та, что была активной
                                    };

                            break;
                            case 3:   // Do the selected menu item (зайти, сделать выбранный пункт меню)
                                    (*_mptr->itemFunction)(_mptr->itemArg); //вызвать ф-цию с аргументом
                            };
                     ucPressedKey=0;
                   };
                 }
 }


Теперь было бы неплохо модернизировать этакое меню так, что бы у него было вложенное меню.....буду благодарен за подсказки и идеи :lol:
:solder: 32-х ядерный процессор из П213В
Мастер Ломастер
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город
Контактная информация:

Re: Меню на LCD. Помогите разобрать код.

Сообщение Мастер Ломастер »

подсказки и идеи я вам уже давал.
битва с дураками проиграна, победители торжествуют. слава победителям!
Аватара пользователя
wellcom
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Чт фев 24, 2011 13:00:49

Re: Меню на LCD. Помогите разобрать код.

Сообщение wellcom »

Мастер Ломастер писал(а):подсказки и идеи я вам уже давал.


согласен :) , TUI буду изучать, но может у кого еще есть какие то идеи.....и может конкретно по данному коду :roll:
:solder: 32-х ядерный процессор из П213В
Аватара пользователя
sonata
Встал на лапы
Сообщения: 87
Зарегистрирован: Пн июн 08, 2009 16:09:35

Re: Меню на LCD. Помогите разобрать код.

Сообщение sonata »

Еще один пример
Вложения
menu.c
(8.57 КБ) 600 скачиваний
[url=http://userbars.com.ua/][img]http://userbars.com.ua/img/UA/8.gif[/img][/url]
Аватара пользователя
wellcom
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Чт фев 24, 2011 13:00:49

Re: Меню на LCD. Помогите разобрать код.

Сообщение wellcom »

sonata писал(а):Еще один пример


Спасибо, посмотрим.... :tea:

.... посмотрел, разобрался и прикрутил к своему LCD 4х20. Спасибо автору за отличный кусок кода! :beer:
....единственное чего здесь не сделать для строчного LCD, так это выделение текущего пункта меню инверсией (я так понял изначально данный кусок кода был предназначен для графического LCD), но это не страшно, я нарисовал свою стрелочку на против активного меню. :)
:solder: 32-х ядерный процессор из П213В
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»