Меню для текстового LCD: помогите оптимизировать
- Войдите на сайт для отправки комментариев
Чт, 10/11/2011 - 02:01
В общем, все работает. Но хотелось бы упростить решение и оптимизировать, ибо 4кб жрет. Что то мне подсказывает - это возможно, но с сиподобными не знаком близко..
Итак, движок для меню текстового дисплея 4 строки. В нулевой приглашение тыкнуть, в остальных строки текущей позиции меню. Поддерживает подменю любых вложенностей и конфигураций.
Первая программа для ардуины! ))
#include <LiquidCrystalRus.h> LiquidCrystalRus lcd(2, 3, 4, 5, 6, 7); //Константы //пины кнопок byte KEY_UP = 27; byte KEY_DOWN = 22; byte KEY_LEFT = 26; byte KEY_RIGHT = 24; byte KEY_OK = 25; byte KEY_BACK = 23; //задержка после нажатий, мс int KEYS_DELAY = 100; //пины светодиодов byte LED_GREEN = 20; byte LED_RED = 21; //главное меню char* MainMenu[] = { "Menu 1", "Menu 2", "Menu 3", "Menu 4", "Menu 5", "Menu 6", "Menu 7", "Menu 8" }; //подменю 1 <= MainMenu char* SubMenu1[] = { "SubMenu1 1", "SubMenu1 2", "SubMenu1 3", "SubMenu1 4", "SubMenu1 5" }; //подменю 2 <= MainMenu char* SubMenu2[] = { "SubMenu2 1", "SubMenu2 2", "SubMenu2 3", "SubMenu2 4" }; //подменю 3 <= SubMenu1 char* SubSubMenu1[] = { "SbSbMnu1 1", "SbSbMnu1 2", "SbSbMnu1 3", "SbSbMnu1 4" }; //Размеры меню. Позиция в массиве должна соответствовать menu_number. //Обработка подразумевается в void menu_start() byte MenuSizes[] = { 7, //MainMenu 4, //SubMenu1 3, //SubMenu2 3, //SubSubMenu1 }; //Список родителей меню. Номер элемента в массиве соответствует номеру меню menu_num byte MenuParents[] = { 0, //MainMenu - родитель MainMenu 0, //SubMenu1 - родитель MainMenu 0, //SubMenu2 - родитель MainMenu 1 //SubSubMenu1 - родитель SubMenu1 }; //необходимые переменные byte menu_number = 0; //Номер текущего меню. Обработка подразумевается в void menu_start() byte menu_offset = 0; //Позиция в текущем меню. byte need_update = 1; //необходимость обновить дисплей char CLEAR_STRING[] = " "; //пустая строка для заливки дисплея void setup() { //Инициализация pins, кнопки замыкаются на GND pinMode(LED_GREEN, OUTPUT); //светодиод зеленый digitalWrite(LED_GREEN, LOW); //выключаем pinMode(LED_RED, OUTPUT); //светодиод красный digitalWrite(LED_RED, LOW); //выключаем pinMode(KEY_UP, INPUT); //кнопка digitalWrite(KEY_UP, HIGH); //подтягиваем резистор pinMode(KEY_DOWN, INPUT); //кнопка digitalWrite(KEY_DOWN, HIGH); //подтягиваем резистор pinMode(KEY_LEFT, INPUT); //кнопка digitalWrite(KEY_LEFT, HIGH); //подтягиваем резистор pinMode(KEY_RIGHT, INPUT); //кнопка digitalWrite(KEY_RIGHT, HIGH); //подтягиваем резистор pinMode(KEY_OK, INPUT); //кнопка digitalWrite(KEY_OK, HIGH); //подтягиваем резистор pinMode(KEY_BACK, INPUT); //кнопка digitalWrite(KEY_BACK, HIGH); //подтягиваем резистор //настройки дисплея lcd.begin(16, 4); } //*********************** //Основное тело программы void loop() { menu_start(); delay(100); } //*********************** //вызов основного модуля меню void menu_start() { //Обработка нажатий кнопок //menu key down if (digitalRead(KEY_DOWN) == LOW) { blink(LED_GREEN); if (menu_offset < MenuSizes[menu_number]) { menu_offset++; need_update = 1; delay(KEYS_DELAY); } } //menu key up if (digitalRead(KEY_UP) == LOW) { blink(LED_GREEN); if (menu_offset > 0) { menu_offset--; need_update = 1; delay(KEYS_DELAY); } } //menu key ok if (digitalRead(KEY_OK) == LOW) { blink(LED_GREEN); menu_execute(); need_update = 1; delay(KEYS_DELAY); } //menu key back if (digitalRead(KEY_BACK) == LOW) { if (menu_number != 0) { menu_number = MenuParents[menu_number]; //Возвращаемся в предыдущее меню согласно списку MenuParents menu_offset = 0; need_update = 1; blink(LED_GREEN); } else { menu_offset = 0; need_update = 1; blink(LED_RED); } delay(KEYS_DELAY); } //Если необходимо обновление экрана if (need_update == 1) { //Вызов нужного нам меню (сопоставление с массивами) switch(menu_number) { case 0: //MainMenu menu_print(MainMenu); break; case 1: //SubMenu1 menu_print(SubMenu1); break; case 2: //SubMenu1 menu_print(SubMenu2); break; case 3: //SubSubMenu1 menu_print(SubSubMenu1); break; }//switch need_update = 0; }//if need update //debug: print offset //lcd.setCursor(0,3); //lcd.print(menu_offset); // } //Рисование меню (для глючного четырехстрочного дисплея) void menu_print(char* Menu[]) { //print menu lcd.clear(); //надпись lcd.setCursor(1, 0); lcd.print("Выберите пункт"); //указатель на текущий пункт lcd.setCursor(0,2); lcd.print("*"); //пункт меню выше текущего lcd.setCursor(6,1); if ((menu_offset - 1) >= 0) lcd.print(Menu[menu_offset - 1]); else lcd.print(CLEAR_STRING); //текущий пункт меню lcd.setCursor(2,2); lcd.print(Menu[menu_offset]); //пункт меню ниже текущего lcd.setCursor(2,3); if ((menu_offset + 1) <= MenuSizes[menu_number]) lcd.print(Menu[menu_offset + 1]); else lcd.print(CLEAR_STRING); }//print_menu //действия по кнопке KEY_OK void menu_execute() { //Определение текущего меню switch (menu_number) { case 0: //Для MainMenu switch(menu_offset) { //выбор действий case 0: //Вызов подменю 1 menu_number = 1; //настройка на SubMenu1 menu_offset = 0; //сброс позиции в меню break; case 1: //Вызов подменю 2 menu_number = 2; //настройка на SubMenu2 menu_offset = 0; //сброс позиции в меню break; case 2: //блинк blink(LED_RED); break; case 3: //блинк blink(LED_RED); break; case 4: //блинк blink(LED_RED); break; case 5: //блинк blink(LED_RED); break; case 6: //блинк blink(LED_RED); break; case 7: //блинк blink(LED_RED); break; }//switch break; case 1: //Для SubMenu1 switch(menu_offset) { //выбор действий case 0: //блинк menu_number = 3; //настройка на SubSubMenu1 menu_offset = 0; //сброс позиции в меню break; case 1: //блинк blink(LED_RED); break; case 2: //блинк blink(LED_RED); break; case 3: //блинк blink(LED_RED); break; case 4: //блинк blink(LED_RED); break; }//switch break; case 2: //Для SubMenu2 switch(menu_offset) { //выбор действий case 0: //блинк blink(LED_RED); break; case 1: //блинк blink(LED_RED); break; case 2: //блинк blink(LED_RED); break; case 3: //блинк blink(LED_RED); break; }//switch break; case 3: //Для SubSubMenu1 switch(menu_offset) { //выбор действий case 0: //блинк blink(LED_RED); break; case 1: //блинк blink(LED_RED); break; case 2: //блинк blink(LED_RED); break; case 3: //блинк blink(LED_RED); break; }//switch break; } //switch MenuSelect }//menu_execute //блинк светодиодом void blink(byte LED) { //flash led digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW); }//blink
что, нет возможности выяснить размер массива? нет возможности двух-трехмерный массив сделать?
не так много народу тут, подождите маленько и Вам ответят
надеюсь, скоро станет больше :)
вообще похоже стандартных решений на ардуино нет..
может тут чего найдете : http://rln.nnov.ru/index.php?ind=reviews&op=entry_view&iden=211
Спасибо, почитаю код на досуге, посмотрю на решения
что, нет возможности выяснить размер массива? нет возможности двух-трехмерный массив сделать?
насчет размера сходу не скажу, но двумерный масив сделать легко) MainMenu[][];
MainMenu [] [] = { {"Menu1", 0},{"Menu1", 0},{"Menu1", 0} }; и доступ MainMenu[0][0], MainMenu[0][1]?
Хотел спросить как это меню можно переделать под двух строчный индикатор..............?