Простое МЕНЮ для символьного дисплея 2
- Войдите на сайт для отправки комментариев
Вс, 27/03/2016 - 16:21
Этот пример являеться развитием примера меню которое я выкладывал тут. Т.к. в том коде было много недостатков, в часности отсутствовала защита от дребезга кнопок, мерцал экран и другие мелочи. Т.к. на форуме много кто из начинающих пытаеться его использовать например тут по причине наглядности. Я его переработал и откоментировал. Структура не изменилась.
//Пример простого меню для LCD 16x2 V2 //yul-i-an. 03.2016 //В меню используется 4 экрана //за номер отображаемого экрана отвечает переменная m #include <LiquidCrystal.h> //Библиотека LCD // инициализация LCD LiquidCrystal lcd(12, 11, 5, 4, 3, 2); int m=0; //переменная для экранов меню int p1=0; // переменная для примера 1 int p2=0; // -//- 2 int p3=0; // -//- 3 long PSTimer = 0;//таймер для обновления экрана #define nextPin 6 //кнопка меню на 6 входе #define prevPin 7 //кнопка возврата #define upPin 9 //увеличение значения отображаемого параметра #define downPin 10 //уменьшение значения byte f_key=0;//флаг для фиксации нажатия кнопки #define ledPin 13 //Светодиод void setup() { //Настройка входов pinMode(nextPin, INPUT); pinMode(prevPin, INPUT); pinMode(upPin, INPUT); pinMode(downPin, INPUT); //Настройка выходов pinMode(ledPin, OUTPUT); //Настройка дисплея lcd.begin(16, 2);//Установка количества столбцов и строк дисплея // Вывод приветствия lcd.print("DEMO MENU! V2"); delay (3000); } void loop() { key();//опрос кнопок if (PSTimer>millis()){//защита от переполнения счетчика PSTimer = 0; } if (millis()-PSTimer>=50){//вывод экрана каждые 50мсек (20к/с) PSTimer=millis(); PreentScreen(m);//выводим экран } }//end LOOP void PreentScreen(int s){//Вывод меню lcd.clear();//отчистка экрана //Описание экранов меню switch (s){ case 0: lcd.setCursor(0, 0); lcd.print("Main Menu"); lcd.setCursor(0, 1); lcd.print("P1="); lcd.print(p1); lcd.print(" P2="); lcd.print(p2); lcd.print(" LED="); lcd.print(p3); break; case 1: lcd.setCursor(0, 0); lcd.print("Parametr-1"); lcd.setCursor(0, 1); lcd.print("P1 = "); lcd.print(p1); break; case 2: lcd.setCursor(0, 0); lcd.print("Parametr-2"); lcd.setCursor(0, 1); lcd.print("P2 = "); lcd.print(p2); break; case 3: lcd.setCursor(0, 0); lcd.print("LED Control"); lcd.setCursor(0, 1); lcd.print("LED = "); lcd.print(p3); break; } } //-------------ОПРОС КНОПОК------------ void key(){ //Обработка нажатия кнопки NEXT if (digitalRead(nextPin)== HIGH && f_key==false) { action(0); f_key=true;//устанавливаем флаг } //Обработка нажатия кнопки PREV if (digitalRead(prevPin)== HIGH && f_key==false) { action(1); f_key=true;//устанавливаем флаг } //Обработка нажатия UP if (digitalRead(upPin)== HIGH && f_key==false)//если находимся на экране с переменной р1 { action(2); f_key=true;//устанавливаем флаг } //Обработка нажатия DN if (digitalRead(downPin)== HIGH && f_key==false)//если находимся на экране с переменной р1 { action(3); f_key=true;//устанавливаем флаг } //проверка на отпускание кнопки if (digitalRead(nextPin)==0 && digitalRead(prevPin)==0 && digitalRead(upPin)==0 && digitalRead(downPin)==0 && f_key==true){ f_key=false;//сброс флага } } //--------РЕАКЦИЯ НА КНОПКИ------------------- void action(int x){ switch (x){ case 0://next m=var(m, 0, 3, 1, 1, 1);//увеличиваем переменную уровня меню break; case 1://prev m=var(m, 0, 3, 1, 0, 1);//уменьшаем переменную уровня меню break; case 2://up if (m==1){//если нажали UP когда экран с переменной р1 p1= var(p1, 0, 10, 1, 1, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу } if (m==2){//если нажали UP когда экран с переменной р2 p2= var(p2, 0, 10, 1, 1, 1); } if (m==3){//если нажали UP когда экран с переменной р3 p3= var(p3, 0, 1, 1, 1, 1); digitalWrite(ledPin, p3); } break; case 3://down if (m==1){//если нажали DOWN когда экран с переменной р1 p1= var(p1, 0, 10, 1, 0, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу } if (m==2){//если нажали DOWN когда экран с переменной р2 p2= var(p2, 0, 10, 1, 0, 1); } if (m==3){//если нажали DOWN когда экран с переменной р3 p3= var(p3, 0, 1, 1, 0, 1); digitalWrite(ledPin, p3); } break; } } //--------------функция изменения переменной------------------- //х=var(переменная,минимум,максимум,шаг,направление,циклически); //переменная - переменная для изменения (int) //минимум, максимум - пределы переменной //шаг - шаг изменения переменной //направление - увеличить или уменьшить //циклически - если 0 то от мин до макс, //если 1 то при достижение мах переходим к минимуму и наоборот int var(int v, int mn, int mx, int stp, boolean pm, boolean c){ switch (pm){//pm=1 увеличение pm=0 уменьшение case 0: v -= stp;//уменьшаем на шаг break; case 1: v += stp;//увеличиваем на шаг break; } switch (c){//c-1 циклически с-0 до пределов case 1:// if (v<mn){ v=mx; } if (v>mx){ v=mn; } break; case 0: if (v<mn){ v=mn; } if (v>mx){ v=mx; } break; } return v; } //http://allduino.forum2x2.ru/t12-topic#17 //http://arduwir.netdo.ru/article/6264
Есть масса замечаний к коду, а значит есть еще куда развиваться.
1.Строка 37 очевидно от непонимания.
2.Антидребезга не увидел. Опрос кнопок оставляет желать лучшего.
3.Нет выхода из подменю без сохранения переменной.
4.Переменные разумнее организовать в виде структуры {Название, значение, max, min, шаг, цикличность}
5.В чем смысл вывода на экран каждые 50 мС? Индикация разве динамическая? Вывод нужно делать по событию.
Есть масса замечаний к коду, а значит есть еще куда развиваться.
1.Строка 37 очевидно от непонимания.
2.Антидребезга не увидел. Опрос кнопок оставляет желать лучшего.
3.Нет выхода из подменю без сохранения переменной.
4.Переменные разумнее организовать в виде структуры {Название, значение, max, min, шаг, цикличность}
5.В чем смысл вывода на экран каждые 50 мС? Индикация разве динамическая? Вывод нужно делать по событию.
1. Строка 37 - служит для того чтобы при переполнении millis() условие в 41 строке выполнилось (если устройство расчитано на непрерывнуюработу - более 50 дней).
2. Антидребезг
Я думаю что пока будет выполнятся код от 16 строки при нажатии кнопки UP до 27 строки где проверяется отпущина кнопка или нет положение контактов устаканиться. (если можете предложите лучьший варийант опроса кнопок).
3. Если переключаться между экранами не меняя переменных, то они и не изменяться.
4. Это дело сугубо личное, хоть объектом опишите.
5. Так проще, чем отслеживать изменение каждой переменной и при её изменении перирисовывать экран.
Спасибо за критику.
Это все от непонимания беззнаковой арифметики.
Я думаю что пока будет выполнятся код от 16 строки при нажатии кнопки UP до 27 строки где проверяется отпущина кнопка или нет положение контактов устаканиться. (если можете предложите лучьший варийант опроса кнопок).
Дребезг носит миллисекундный характер, за 1 мС контроллер выполняет 16 000 инструкций, в строках 16-27 явно меньше. Лучший вариант опрашивать дважды с интервалом 5-100 мС и нажатие и отпускание.
Добавил автовозврат к основному экрану через 5 сек бездействия, обновление экрана 4 раза/сек. (достаточно) и поправил код.
демо видео
Изменил код. Что-то на подобие конечного автомата (меню описано таблицей переходов)
интересно завтра попробую залить ваше меню и в коде поразбираюсь, библиотекой для меню не пробовали работать?
(//-----------Обновление экрана--------------
085
if
(millis()-PSTimer>250){
//вывод экрана каждые 250мсек 4р/сек )
для чего вы постоянно выводите на дисплей информацию ? у вас экран не мигает?
обновление экрана нужно делать только по событию- по нажатию кнопки а не в цыкле каждые 250мсек и возвращать на главное меню 1 раз и больше не трогать его если кнопка кнопка не будет снова нажата
Добавил в код ОЧЕРЕДЬ СОБЫТИЙ. События добавляются в очередь и по меревыполнения очередь продвигается.
Фаил Proteus`a
Допилил код. Теперь меню полностью работает на таблице переходов и очереди событий.
если раскоментировать 99 строку то на дисплей будет выводиться очередь заданий (использовалось для отладки). Если данная возможность не нужна то эту строку и функцию getEventLenght() можно удалить.
Добавил приоритеты событий.
вот библиотека https://cloud.mail.ru/public/KEXw/rAXWQj99V
кстати если не против в вашей теме задам вопрос знающим людям, как в этой библиотеке выводить пункт меню со значением както так VAR1= 220
к примеру пробовал так
но выдает пустую строку, и переменную не могу соединить со строкой
У меня хоть delay`ев нет)
Кому не интересно проходите мимо. В своем коде я пытаюсь объяснить просто (для тех кто совсем не понимает) саму концепцию построения меню, а то некоторые на форуме спрашивают как войти в меню или выйти из меню. Ну и за одно подход к написанию кода не в лоб.
делаи тут не нужны и скетч тестовый только напроски основных функций, а Вам стоит задматься чему учити...
и да в дальнейшем буду проходить мимо......
Удачи!
Переписал код под использование LCDKeyPad Shield. Теперь экран обновляется только при необходимости (НЕ МЕРЦАЕТ), для этого был введен флаг который указывает на необходимость перерисовки экрана.
Код максимально откоментирован. Проверен в железе, всё работает.
Видео демонстрация
Я с этим шилдом такую функцию использую:
Я с этим шилдом такую функцию использую:
Можно и так.
Для большей наглядности вместо управления светодиодом на 13 выходе реализовал регулировку яркости LCD.
У меня хоть delay`ев нет)
И что? Это заслуга? Зато, у Вас if'ы есть.
В своем коде я пытаюсь объяснить просто (для тех кто совсем не понимает) саму концепцию построения меню,
Может Вам сначала научиться писать программы, а потом кому-то что-то объяснять? Заодно и концепцию меню получше самому понять? Вы совсем недалеко ушли от тех, "кто совсем не понимает", а лезете кого-то учить, а сами, простите, с переполнением миллис боретесь. Извините, конечно, не хотел обидеть.
Код интересный.. но так не пойму очередь заданий как работает, очередь чего? на видео эту функцию не продемонстрировали. А так стабильно работает ничего не виснет.
Код интересный.. но так не пойму очередь заданий как работает, очередь чего? на видео эту функцию не продемонстрировали. А так стабильно работает ничего не виснет.
Ссылка на тему очереди. А тут более грамотный подход.
А можно для каждого из дисплеев сделать свой изменяемый
т.е. m это 4 наших дисплея, а в каждом из m находится такая же "m"