Вообще у меня слабость к меню в контроллерах. 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;
}
}
}