Комментарии 21
Какой сильный флешбек во времена школы и квикбейсика.
+6
А я своё так и не дописал до конечного состояния. Решил что я в тупик зашёл по ресурсам из за использования динамической памяти для всего этого, да и ардуинку уже подарил другому человеку в виде midi клавиатуры. Поделиться своим велосипедным меню? Отлаживать и демонстрировать буду на эмуляторе.
Вот одна из ранних-ранних стадий, еще без дисплея, но с логикой пунктов:
Интересно как вы реализовали скролл, а то я не смог придумать как это сделать красиво и в итоге написал что то стрёмное. Думаю вечерком отпишусь когда дома буду.
Вот одна из ранних-ранних стадий, еще без дисплея, но с логикой пунктов:
Интересно как вы реализовали скролл, а то я не смог придумать как это сделать красиво и в итоге написал что то стрёмное. Думаю вечерком отпишусь когда дома буду.
0
Постраничное отображение с контролем границ.
0
Вот вам на растерзание. Требует порт vector. Перекатался я на велосипеде сегодня… Извините сил нет объяснять. Как только буду в состоянии расскажу подробнее. Я уже и не помню рабочее ли оно.
0
Ссылку потерял bitbucket.org/fishlabsoman/menuarduino
0
Так вот что у меня. У меня менюха рендерится рекурсивным перебором, а у пункта меню присутствует ссылка на функцию, которая используется при активации.
Куски кода:
Но это хавает многовато памяти, хотя и получше одной красивой менюхи (не помню как называется), но хавающей еще больше памяти. Моя хавает память с каждым пунктом меню.
Куски кода:
Скрытый текст
typedef byte ( * tCallback)(byte, byte, char * );
//prototypes NEED FOR CALLBACK
byte callback_StartTimer(byte id, byte parent, char * name);
//struct define typical menu item
struct menuItem {
byte id;
char * name;
byte parent; //id parent
tCallback callback; //callback function
bool haveChilds;//using for optimizations
};
vector<menuItem> items;//vector of menu items
int freeRam () { //display free ram memory
extern int __heap_start, * __brkval;
int v;
return (int) & v - (__brkval == 0 ? (int) & __heap_start : (int) __brkval);
}
void setup() {
menuItem root;
{
root.id = 10;
root.name = "Set octave";
root.parent = CONST_ROOT_ITEM;
root.callback = & callback_SetOcave;
items.push_back(root);
root.id = 12;
root.name = "Setup";
root.parent = CONST_ROOT_ITEM;
root.callback = NULL;
items.push_back(root);
{
root.id = 24;
root.name = "Time";
root.parent = 12;
root.callback = & callback_resetAllKeys;
items.push_back(root);
}
}
Serial.println("Free ram: " + String(freeRam()));
}
//call callback of menu item
items[i].callback(id, parent, name);
byte callback_StartTimer(byte id, byte parent, char * name) { //return true if need reprint menu
//Serial.println("Callbacked function callback_StartTimer by " + String(name));
return false;
}
//print menu recursively. return need for checking empty menu
bool printMenuRecurcive(vector<menuItem> & items, byte parent, byte level) {
if (level > CONST_MAX_LEVEL) return false;
bool haveChilds = false;//flag reports if have items
for (byte i = 0; i < items.size(); i++) {
if (parent == items[i].parent) {
haveChilds = true;//yay! his have items
String indent = "";
for (int j = 0; j < level; j++) {
indent += " ";
}
if (items[i].haveChilds) {
Serial.println(indent + String(items[i].name) + ">");
} else {
Serial.println(indent + String(items[i].name));
}
printMenuRecurcive(items, items[i].id, level + 1); //print next level
}//end if parent
}//end for
return haveChilds;
}//end func
Но это хавает многовато памяти, хотя и получше одной красивой менюхи (не помню как называется), но хавающей еще больше памяти. Моя хавает память с каждым пунктом меню.
0
Можно реализовать это следующим образом — есть несколько переменных, одна хранит максимальное количество пунктов помещающихся на экране (max_draw_num), вторая хранит номер пункта который отображается на экране первым (first_draw_num), третья хранит номер пункта выделенного на экране (select_draw_num).
Т.е. например всего на экране помещается четыре строки, при этом меню содержит 8 элементов, в текущий момент времени отображаются пункты с 3 по 6, а выделен пункт номер 4.
Тогда:
max_draw_num=4 (количество элементов на экране)
first_draw_num=3 (первый элемент меню на экране)
select_draw_num=2 (четвертый пункт при показе пунктов с 3 по 5 на экране будет находится на второй строке)
Тогда при нажатии кнопки вверх например нам надо проверить что мы не уперлись в экран, если мы не уперлись в экран то просто уменьшаем позицию на экране на единицу:
if (select_draw_num>1) {select_draw_num=select_draw_num-1);
Если всеже мы уперлись в экран то надо проверить какие элементы меню отображаются на экране, можем ли мы промотать меню ближе к началу:
if (first_draw_num>1) {first_draw_num=first_draw_num-1);
Аналогично делается и при нажатии кнопки вниз, только меняются знаки и сравнение делается не с 1, а с переменной хранящей в себе максимальное количество отображаемых на экране пунктов, соответственно если мы не уперлись в нижний край экрана:
if (select_draw_num<max_draw_num) {select_draw_num=select_draw_num+1);
Если мы не уперлись в конец меню:
if (first_draw_num+max_draw_num<max_menu_count) {first_draw_num=first_draw_num+1);
переменная max_menu_count — количество пунктов в текущем меню.
После останется только вывести на экран пункты меню с first_draw_num по first_draw_num+max_draw_num-1 и отобразить выделение вокруг пункта меню select_draw_num
Для удобства можно еще сверху отображать название родительского пункта меню, нумеровать автоматически пункты меню, прикрутить координаты к пунктам меню и отображать пункты на соответствующих координатах и т.д…
Т.е. например всего на экране помещается четыре строки, при этом меню содержит 8 элементов, в текущий момент времени отображаются пункты с 3 по 6, а выделен пункт номер 4.
Тогда:
max_draw_num=4 (количество элементов на экране)
first_draw_num=3 (первый элемент меню на экране)
select_draw_num=2 (четвертый пункт при показе пунктов с 3 по 5 на экране будет находится на второй строке)
Тогда при нажатии кнопки вверх например нам надо проверить что мы не уперлись в экран, если мы не уперлись в экран то просто уменьшаем позицию на экране на единицу:
if (select_draw_num>1) {select_draw_num=select_draw_num-1);
Если всеже мы уперлись в экран то надо проверить какие элементы меню отображаются на экране, можем ли мы промотать меню ближе к началу:
if (first_draw_num>1) {first_draw_num=first_draw_num-1);
Аналогично делается и при нажатии кнопки вниз, только меняются знаки и сравнение делается не с 1, а с переменной хранящей в себе максимальное количество отображаемых на экране пунктов, соответственно если мы не уперлись в нижний край экрана:
if (select_draw_num<max_draw_num) {select_draw_num=select_draw_num+1);
Если мы не уперлись в конец меню:
if (first_draw_num+max_draw_num<max_menu_count) {first_draw_num=first_draw_num+1);
переменная max_menu_count — количество пунктов в текущем меню.
После останется только вывести на экран пункты меню с first_draw_num по first_draw_num+max_draw_num-1 и отобразить выделение вокруг пункта меню select_draw_num
Для удобства можно еще сверху отображать название родительского пункта меню, нумеровать автоматически пункты меню, прикрутить координаты к пунктам меню и отображать пункты на соответствующих координатах и т.д…
+1
Любопытно, как раз собирался искать меню для ардуины и GLCD. Единственное как-то неуверен насчет подтяжки кнопок к питанию. А если МК запустится раньше, чем питание подтяжки преодолеет барьер логической единицы — тогда будет ложное срабатывание?
0
А я вот сижу сочиняю многоуровневое меню на одном светодиоде по мотивам менюх автосигнализаций :) Не везде можно дисплейчик вставить.
0
проще использовать связанный список:
в принципе, чтобы разрядить меню можно вынести data и do_xxxx() в отдельную структуру, поскольку не все пункты будут иметь какую-то настройку (будут директорией)
struct menu_item {
struct menu_item* parent; // указатель на родителя
struct menu_item* child; // указатель на потомка
struct menu_item* prev; // предыдущий в списке
struct menu_item* next; // следующий в списке
const char* name; // имя
void* data; // данные пункта
int (*do_left)(void*); // действие для кнопок
int (*do_right)(void*);
int (*do_up)(void*);
int (*do_down)(void*);
}
в принципе, чтобы разрядить меню можно вынести data и do_xxxx() в отдельную структуру, поскольку не все пункты будут иметь какую-то настройку (будут директорией)
0
А кто бы мне помог присосаться к жк драйверу msm5265?
0
Судя по датащиту, подключение возможно организовать по SPI, загружая 160-бит данных в сдвиговый регистр на один контроллер (каждый дает 80х2 точек, контроллеры стекируются).
Единственное что нужно знать для конкретного дисплея — сколько контроллеров на нем и в какой последовательности пронумерованы пикселы.
Изображение будет удобно хранить в формате XBM — оно будет сразу готово к загрузке.
Единственное что нужно знать для конкретного дисплея — сколько контроллеров на нем и в какой последовательности пронумерованы пикселы.
Изображение будет удобно хранить в формате XBM — оно будет сразу готово к загрузке.
0
Да уж, всё мудрено оказывается. Просто у меня в трупере висит над зеркалом бортовой компутер с компасом, барометром и температурой. Думал, если при помощи готовых библиотек текст туда выводить можно, то переделать его на что-нибудь по-подробнее.
0
В отличие от ks010, nt7534 и многих других, вашим драйвером очень просто управлять. Не надо реализовывать никакие команды настройки, достаточно просто загружать в сдвиговый регистр данные. В этом, правда, кроется его недостаток — драйвер тупой. Все нужно делать за него.
0
А никто не делал меню в виде иконок для TFT экрана? Чтобы максимально удобно было добавлять новые пункты в меню.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Многоуровневое меню для Arduino и не только