Автор Тема: Траблики с меню  (Прочитано 17007 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Траблики с меню
« : 07 Ноября 2013, 08:01:11 »
Вообще у меня слабость к меню в контроллерах. Pumpkin как то помог сделать отличное меню на BASCOM-e, http://minilabmaster.com/cgi-bin/yabb2/YaBB.pl?num=1246889930/0 за что ему огромное спасибо. Из баскома я вырос, сейчас юзаю Си.

Есть классное меню для WinAvr, называется MicroMenu, исходники сдесь - https://github.com/abcminiuser/micromenu-v2. Отличное, компактное и быстрое меню, рекомендую, но у меня с ним небольшие проблемы, из за недостаточно глубокого знания Си.

С выводом на LCD дисплей проблем нет, само меню выглядит примерно так:

Цитировать
#ifdef LCD_DISPLAY
// Menus: уровень       следущий  предыдущий родитель  дитя      Выбор функции   Enter функция        Текст
MENU_ITEM(Lev1_It1    , Lev1_It2, Lev1_It1, Lev1_It1 , Lev1_It1 ,    NULL,         X_Report     , "   X-отчет");
MENU_ITEM(Lev1_It2    , Lev1_It3, Lev1_It1, Lev1_It2 , Lev1_It2 ,    NULL,         Z_Report     , "Z-отчет/Гашение");
MENU_ITEM(Lev1_It3    , Lev1_It4, Lev1_It2, Lev1_It3 , Lev1_It3 ,    NULL,         Setup        , "Настройка цены");
MENU_ITEM(Lev1_It4    , Lev1_It5, Lev1_It3, Lev1_It3 , Lev1_It4 ,    NULL,         Reset        , "Техобнуление");
MENU_ITEM(Lev1_It5    , Lev1_It5, Lev1_It4, Lev1_It5 , Lev1_It5 ,    NULL,         Exit         , "Выход");
#endif

Все прекрастно работает  и выводится. Но сделал проект с LED дисплеем, а там своя специфика. Во первых, недосимволы я реализовал через дефайны:

Цитировать

#ifdef LED_DISPLAY
#define _0_          0x3f      //0
#define _1_          0x06      //1
#define _2_          0x5b      //2
#define _3_          0x4f      //3
#define _4_          0x66      //4
#define _5_          0x6d      //5
#define _6_          0x7d      //6
#define _7_          0x07      //7
#define _8_          0x7f      //8
#define _9_          0x6f      //9

#define _A_          0x77      // A
#define _B_          0x7D      // B
#define _C_          0x39      // C
#define _E_          0x79      // E
#define _F_          0x71      // F
#define _G_          0x31      // Г
#define _H_          0x76      // H
#define _SL_        0x30      // /
#define _J_         0x1e      // J
#define _Pr_          0x37      // П
#define _MINUS_          0x40      // -
#define _RUB_          0xf3      // P.
#define _H_          0x76      // H
#define _U_          0x3e      // U
#define _L_          0x38      // L
#define _P_          0x73      // P
#define _T_          0x78      // T

#define _SP_      0x00      // Пробел
#define _POINT_          0xbb      // точка
#define _END_          0xff      // конец строки
#endif


Заметте, что нулевой символ используется как пробел. Хотя это можно исправить на уровне программы вывода, например сделав символ пробела 0x32 и отлавливать его при выводе и посылать вместь него на дисплей 0.

Далее из псевдосимволов формируются строки:

Цитировать
#ifdef LED_DISPLAY
  BYTE Version  [] PROGMEM = {_P_ , _L_ , _POINT_ , _1_, _0_, _END_}  ; //"PLAT.10"
  BYTE X_rep    [] PROGMEM = {_0_ , _B_ , _G_, _MINUS_,_END_ }  ; //X отчет
  BYTE Price    [] PROGMEM = {_C_ , _T_ , _0_, _MINUS_,_END_ }  ; //Печать прайса
  BYTE clr      [] PROGMEM = {_SP_ , _SP_ , _SP_,_SP_, _END_, }  ; //Очистка строки
 #endif

Так вопрос в следующем - как вставить эти строки в вышеприведенное меню? как ни пихаю их - напрямую ли либо через указатель - компилятор ругается. Можно было сделать вставить в меню на место SELECT функцию вывода строки, но поазалось не очень хорошо. Пока же сделал такой костыль:

Цитировать


#ifdef LED_DISPLAY

#define XREP_A    "@?}1я"   //{_MINUS_,_0_ , _B_ , _G_,,_END_} Z отчет
#define ZREP_A    "@?91я"   //{_MINUS_,_0_ , _B_ , _G_,,_END_} Z отчет
#define PROG_A    "@7s1я"   //{_MINUS_,_Pr_ , _P_ , _G_, _END_} Программирование цены
#define REST_A    "@9}sя"   //{_MINUS_,_C_ , _6_ , _Pr_,_END_}
#define EXIT_A    "yv0xя"   //{_MINUS_,_0_ , _B_ , _G_,_END_}



#ifdef LED_DISPLAY
// Menus: уровень       следущий  предыдущий родитель  дитя      Выбор функции   Enter функция        Текст
MENU_ITEM(Lev1_It1    , Lev1_It2, Lev1_It1, Lev1_It1 , Lev1_It1 ,    NULL,         X_Report     , XREP_A);
MENU_ITEM(Lev1_It2    , Lev1_It3, Lev1_It1, Lev1_It2 , Lev1_It2 ,    NULL,         Z_Report     , ZREP_A);
MENU_ITEM(Lev1_It3    , Lev1_It4, Lev1_It2, Lev1_It3 , Lev1_It3 ,    NULL,         Setup        , PROG_A);
MENU_ITEM(Lev1_It4    , Lev1_It5, Lev1_It3, Lev1_It3 , Lev1_It4 ,    NULL,         Reset        , REST_A);
MENU_ITEM(Lev1_It5    , Lev1_It5, Lev1_It4, Lev1_It5 , Lev1_It5 ,    NULL,         Exit         , EXIT_A);
#endif


То есть превращаю бинарные символы в строку и типа впихиваю ее в меню. Ну не красиво это как то.
Как сделать красиво?  Подскажите, плиз.

И еще один вопрос. В старой версии MicroMenu при выхождении из программы текст меню переинициализировался. С новой этой версией - нет. Вот исходник:

Цитировать
void My_Menu (void){

      wdt_disable();
      Menu_SetGenericWriteCallback(PrintLED_F);
      Menu_Navigate(&Lev1_It1);
 while(1)
 {
       switch (GetButtonPress())
                         {
                               case UP:
                                     Menu_Navigate(MENU_PREVIOUS);
                                     break;
                               case DOWN:
                                     Menu_Navigate(MENU_NEXT);
                                     break;
                               case ENTER:
                                     Menu_EnterCurrentItem();
                                     Menu_Navigate(MENU_NEXT);
                                     break;
                               default:
                                     break;
                         }
}

}
« Последнее редактирование: 07 Ноября 2013, 08:37:08 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Траблики с меню
« Ответ #1 : 07 Ноября 2013, 08:04:16 »
Так вот, после ентра, функция отрабатывает и возвращается в Menu_Navigate(MENU_NEXT), а надо чтобы возвращалась к вызывающему меню и печатала там свой текст снова.
На всякий случай функция вывода:

Цитировать
void PrintLED_F(BYTE *mass ){

      SPI_Init();

      STB_LOW;
      OutLED(DispAdressSet);

 while (pgm_read_byte(mass)!=_END_){
       if (pgm_read_byte(mass)==_POINT_){
             pgm_read_byte(mass++);
             OutLED(pgm_read_byte(mass++)|0x80); //Выводим символ с точкой
       }
       OutLED(pgm_read_byte(mass++));
 }
       STB_HI;

}

Функция вывода меню:

Цитировать
     /** Configuration for the macro or function required to read out a pointer from
       *  the memory storage space set by \\ref MENU_ITEM_STORAGE.
       *
       *  \\param[in] Addr  Address of the pointer to read
       */
      #define MENU_ITEM_READ_POINTER(Addr)   (void*)pgm_read_word(Addr)





Спасибо, Andy.
« Последнее редактирование: 07 Ноября 2013, 08:16:47 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #2 : 08 Ноября 2013, 18:54:53 »
То есть, когда ты передаешь текст в виде ссылки:
Цитировать
char Text[] = "blah-blah";
MENU_ITEM(Lev1_It1, Lev1_It2, Lev1_It1, Lev1_It1, Lev1_It1, NULL, X_Report, Text);
выдает ошибку,

А когда в виде константы:
Цитировать
MENU_ITEM(Lev1_It1, Lev1_It2, Lev1_It1, Lev1_It1, Lev1_It1, NULL, X_Report, "blah-blah");
, то всё OK?

Коли так, то надо глянуть макрос MENU_ITEM и структуры, где меню хранятся. Завтра посмотрю.
А как звучит ошибка?
« Последнее редактирование: 08 Ноября 2013, 18:55:28 от pumpkin »

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Траблики с меню
« Ответ #3 : 09 Ноября 2013, 08:15:44 »
Совершенно верно:
Цитировать
Description      Resource      Path      Location      Type
(near initialization for \'Lev1_It1.Text[0]\')      fun.c      /Game      line 364      C/C++ Problem
initializer element is not computable at load time      fun.c      /Game      line 364      C/C++ Problem
make: *** [fun.o] Error 1      Game                   C/C++ Problem


так же не принимает массив в виде {_SP_ , _SP_ , _SP_,_SP_, _END_, }
и [_SP_ , _SP_ , _SP_,_SP_, _END_, ]

Цитировать
Description      Resource      Path      Location      Type
macro "MENU_ITEM" passed 13 arguments, but takes just 8      fun.c      /Game      line 364      C/C++ Problem

Структура меню выглядит так:

Цитировать
typedef struct PROGMEM {
      void       *Next;
      void       *Previous;
      void       *Parent;
      void       *Sibling;
      FuncPtr     SelectFunc;
      FuncPtr     EnterFunc;
      const char  Text[];
} Menu_Item;

« Последнее редактирование: 09 Ноября 2013, 08:20:57 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #4 : 09 Ноября 2013, 08:52:09 »
Попробуй объявить структуру так:
Цитировать
typedef struct PROGMEM {
     void       *Next;
     void       *Previous;
     void       *Parent;
     void       *Sibling;
     FuncPtr     SelectFunc;
     FuncPtr     EnterFunc;
     const char  *Text;
} Menu_Item;
« Последнее редактирование: 09 Ноября 2013, 08:52:25 от pumpkin »

Форум проекта "Минилаб-Мастер"

Re: Траблики с меню
« Ответ #4 : 09 Ноября 2013, 08:52:09 »

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #5 : 09 Ноября 2013, 08:55:54 »
Если проблема изначально только в выводе на экран в кривой кодировке LED-индикатора, то идеологически правильно будет просто фильтровать вывод на экран. То есть обернуть функцию вывода на индикатор в свою, с предварительной перекодировкой текста.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Траблики с меню
« Ответ #6 : 09 Ноября 2013, 14:15:41 »
Не получается, я так пробовал
Цитировать
     - initialization makes integer from pointer
       without a cast
      - (near initialization for \'Lev1_It1.Text\')
      - (near initialization for \'Lev1_It1.Text[0]\')
      - initializer element is not computable at load
       time
      - missing braces around initializer

Леко сказать фильтровать, если одну переменную изменишь, придется код в нескльких местах менять.
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #7 : 09 Ноября 2013, 15:47:07 »
Я бы сделал вот так, ресурсы (строки) отделил от меню:
Цитировать
#ifdef LCD_DISPLAY
  #define sMnuXReport  "X-отчет"
  #define sMnuZReport  "Z-отчет/Гашение"
  #define sMnuSetup    "Настройка цены"
  #define sMnuReset    "Техобнуление"
  #define sMnuExit     "Выход"
#else
  #ifdef LED_DISPLAY
    #define sMnuXReport   "\\x40\\x3f\\x7d\\x31\\xff"   // Х отчет
    #define sMnuZReport   "\\x40\\x3f\\x7d\\x31\\xff"   // Z отчет
    #define sMnuSetup     "\\x40\\x37\\x73\\x31\\xff"   // Программирование цены
    #define sMnuReset     "\\x40\\x39\\x73\\x37\\xff"   // Обнуление
    #define sMnuExit      "\\x40\\x3f\\x7d\\x31\\xff"   // Выход
  #endif
#endif

MENU_ITEM( Lev1_It1, Lev1_It2, Lev1_It1, Lev1_It1 , Lev1_It1, NULL, X_Report, sMnuXReport );
MENU_ITEM( Lev1_It2, Lev1_It3, Lev1_It1, Lev1_It2 , Lev1_It2, NULL, Z_Report, sMnuZReport );
MENU_ITEM( Lev1_It3, Lev1_It4, Lev1_It2, Lev1_It3 , Lev1_It3, NULL, Setup,    sMnuSetup );
MENU_ITEM( Lev1_It4, Lev1_It5, Lev1_It3, Lev1_It3 , Lev1_It4, NULL, Reset,    sMnuReset );
MENU_ITEM( Lev1_It5, Lev1_It5, Lev1_It4, Lev1_It5 , Lev1_It5, NULL, Exit,     sMnuExit );
« Последнее редактирование: 09 Ноября 2013, 15:49:07 от pumpkin »

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Траблики с меню
« Ответ #8 : 10 Ноября 2013, 06:11:13 »
Но магические числа опять же, мало чем отличаетя от моего варианта,  хотя я в свое время пол интернета перерыл, чтобы узнать как вставить в строку бинарный код, так и не нашел, спасибо.

Но опять же вставить дефайны туда нельзя:

Цитировать
"\\_SP_ \\ _SP_ \\ _SP_\\_SP_\\ _END_" 


unknown escape sequence \'\\_\'

не работает...
« Последнее редактирование: 10 Ноября 2013, 06:23:00 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #9 : 10 Ноября 2013, 08:13:08 »
Цитировать
Но опять же вставить дефайны туда нельзя
Дефайн работает только с идентификаторами.

Цитировать
Но магические числа опять же, мало чем отличаетя от моего варианта,хотя я в свое время пол интернета перерыл, чтобы узнать как вставить в строку бинарный код, так и не нашел, спасибо. 
Но так - правильно, в одном месте задал все строки (да, значения нечитабельные, но идентификатор-то читабельный), и дальше работаешь с идентификаторам, не вспоминая про строки, кодировки и т.д. И код будет один и индикаторонезависимый.
Вдруг еще какой-нибудь тип экрана/кодировки появится - не надо будет искать строки по всему коду и снова ifdefами обильно обсыпать.

Форум проекта "Минилаб-Мастер"

Re: Траблики с меню
« Ответ #9 : 10 Ноября 2013, 08:13:08 »

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #10 : 10 Ноября 2013, 08:41:56 »
Если хочешь, можешь const из структуры убрать (чтоб он не был read only), инициализировать пустой строкой, а потом присваивать Text-у свой массив:
Цитировать
typedef struct Menu_Item {
      const struct Menu_Item *Next; /**< Pointer to the next menu item of this menu item */
      const struct Menu_Item *Previous; /**< Pointer to the previous menu item of this menu item */
      const struct Menu_Item *Parent; /**< Pointer to the parent menu item of this menu item */
      const struct Menu_Item *Child; /**< Pointer to the child menu item of this menu item */
      void (*SelectCallback)(void); /**< Pointer to the optional menu-specific select callback of this menu item */
      void (*EnterCallback)(void); /**< Pointer to the optional menu-specific enter callback of this menu item */
      const char* Text; /**< Menu item text to pass to the menu display callback function */
      } Menu_Item_t;

MENU_ITEM(Menu_1, Menu_2, Menu_3, NULL_MENU, NULL_MENU, NULL, NULL, "");
MENU_ITEM(Menu_2, Menu_3, Menu_1, NULL_MENU, NULL_MENU, NULL, NULL, "");
MENU_ITEM(Menu_3, Menu_1, Menu_2, NULL_MENU, NULL_MENU, NULL, NULL, "");

char Version[] PROGMEM = {_P_ , _L_ , _POINT_ , _1_, _0_, _END_}  ; //"PLAT.10"
char X_rep[] PROGMEM = {_0_ , _B_ , _G_, _MINUS_,_END_ }  ; //X отчет
char Price[] PROGMEM = {_C_ , _T_ , _0_, _MINUS_,_END_ }  ; //Печать прайса

int main(int argc, char *argv[]) {
  Menu_1.Text = Version;
  Menu_2.Text = X_rep;
  Menu_3.Text = Price;
  //...................................................
  //...................................................
  //...................................................
  return 0;
  }

Но лучший, по моему, способ иметь читаемые строки в коде - фильтровать вывод, как я говорил (это легко на самом деле). Пусть, например, \'^\' будет обозначать END:
Цитировать
MENU_ITEM(Menu_1, Menu_2, Menu_3, NULL_MENU, NULL_MENU, NULL, NULL, "PL.10^");
MENU_ITEM(Menu_2, Menu_3, Menu_1, NULL_MENU, NULL_MENU, NULL, NULL, "0BG-^");
MENU_ITEM(Menu_3, Menu_1, Menu_2, NULL_MENU, NULL_MENU, NULL, NULL, "CT0-^");

// Таблица преобразования нормальных Win-1251 символов в кривые LED значения.
// индекс - нормальный символ, значение - новый LED-символ.

BYTE table[256] = {0x00,0x35,0x77,0x55,0xff,0x00, ............. };

void PrintLED_F(BYTE *mass ){
  SPI_Init();
  STB_LOW;
  OutLED(DispAdressSet);

  while (pgm_read_byte(mass)!=\'^\'){
    if (pgm_read_byte(mass)==\'.\'){
      pgm_read_byte(mass++);
      OutLED(table[pgm_read_byte(mass++)]|0x80); //Выводим символ с точкой
      }
    OutLED(table[pgm_read_byte(mass++)]);
  }
  STB_HI;
}
« Последнее редактирование: 10 Ноября 2013, 08:53:43 от pumpkin »

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #11 : 10 Ноября 2013, 08:55:55 »
LED - сегментник что-ли?

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Траблики с меню
« Ответ #12 : 10 Ноября 2013, 09:08:14 »
Угу, сегментник,  буду расбиратся, спасибо!
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Траблики с меню
« Ответ #13 : 10 Ноября 2013, 09:35:58 »
По второму вопросу:
Цитировать
      switch (GetButtonPress())
                       {
                             case UP:
                                   Menu_Navigate(MENU_PREVIOUS);
                                   break;
                             case DOWN:
                                   Menu_Navigate(MENU_NEXT);
                                   break;
                             case ENTER:
                                   Menu_EnterCurrentItem();
                                   Menu_Navigate(Menu_GetCurrentMenu());
                                   break;
                             default:
                                   break;
                       }

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Траблики с меню
« Ответ #14 : 10 Ноября 2013, 14:50:08 »
Точно, забыл старое меню удалить, там видимо искал эту функцию, спасибо.

Цитировать
BYTE table[256] = {0x00,0x35,0x77,0x55,0xff,0x00, ............. };

Жалко всю таблицу в код тащить, там нужен то десяток символов, а в твоем приемере она вообще будет в озу висеть. И раскиданы они по всему полю...
« Последнее редактирование: 10 Ноября 2013, 14:53:47 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Форум проекта "Минилаб-Мастер"

Re: Траблики с меню
« Ответ #14 : 10 Ноября 2013, 14:50:08 »