Помогите с LCD меню
- Войдите на сайт для отправки комментариев
Втр, 22/10/2013 - 23:23
Доброго времени суток, друзья!
Недавно наткнулся на код одного из форумчан, yul-i-an. Так вот, запустил я его, всё класно, но мерцает экран, может кто смог бы подсказать где поставить перерисовку экрана, чтобы она не заставляла его постоянно мерцать.
Буду крайне благодарен, если кто сможет подсказать, как значения, которые выбираются в меню можно писать в EEPROM.
Всем откликнувшимся огромное спасибо!
Далее привожу пример кода, наверное это самое внятное меню, которое я пока встречал.
1 |
//Пример простого меню для Arduino |
002 |
//В меню используется 4 экрана |
003 |
//за номер отображаемого экрана отвечает переменная m |
004 |
//Значения переменных р1,р2 меняются циклически от 0-10 затем опять 0, р3(LED) только 0 или 1 |
005 |
006 |
#include <LiquidCrystal.h> //Библиотека LCD |
007 |
// инициализация LCD |
008 |
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); |
009 |
int m=0; //переменная для экранов меню |
010 |
int p1=0; // переменная для переменной 1 |
011 |
int p2=0; // -//- 2 |
012 |
int p3=0; // -//- 3 |
013 |
014 |
byte nextPin = 6; //кнопка NEXT на 6 входе |
015 |
byte prevPin = 7; //кнопка PREV |
016 |
byte upPin = 9; //увеличение значения (UP) отображаемого параметра |
017 |
byte downPin = 10; //уменьшение значения (DOWN) |
018 |
byte ledPin =13; //Светодиод (исполнительное устройство) |
019 |
020 |
long previousMillis = 0; //счетчик прошедшего времени для AutoMainScreen |
021 |
long interval = 3000; //задержка автовозврата к MainScreen 3сек |
022 |
023 |
void setup () { |
024 |
//Настройка входов |
025 |
pinMode(nextPin, INPUT); |
026 |
pinMode(prevPin, INPUT); |
027 |
pinMode(upPin, INPUT); |
028 |
pinMode(downPin, INPUT); |
029 |
//Настройка выходов |
030 |
pinMode(ledPin, OUTPUT); |
031 |
//Настройка дисплея |
032 |
//Установка количества столбцов и строк дисплея |
033 |
lcd.begin(16, 2); |
034 |
// Вывод приветствия при включении питания если нужно |
035 |
lcd.setCursor(3, 0); |
036 |
lcd.print( "DEMO MENU" ); |
037 |
delay (300); //Задержка приветствия |
038 |
} |
039 |
040 |
void loop () { |
041 |
unsigned long currentMillis = millis(); |
042 |
//Обработка нажатия кнопки NEXT |
043 |
if (digitalRead(nextPin)== HIGH) |
044 |
{ |
045 |
m++; //увеличиваем переменную уровня меню |
046 |
previousMillis = currentMillis; //если кнопка была нажата сбросить счетчик автовозврата к главному экрану |
047 |
delay (100); |
048 |
//lcd.clear(); |
049 |
if (m>3) //если уровень больше 3 |
050 |
{ |
051 |
m=0; // то вернуться к началу |
052 |
} |
053 |
} |
054 |
//Обработка нажатия кнопки PREV |
055 |
if (digitalRead(prevPin)== HIGH) |
056 |
{ |
057 |
m--; |
058 |
previousMillis = currentMillis; |
059 |
delay (100); |
060 |
//lcd.clear(); |
061 |
if (m<0) |
062 |
{ |
063 |
m=3; |
064 |
} |
065 |
} |
066 |
|
067 |
//Обработка нажатия UP для р1 |
068 |
if (digitalRead(upPin)== HIGH && m==1) //если находимся на экране с переменной р1 |
069 |
{ |
070 |
p1++; //то при нажатии кнопки + увеличиваем переменную р1 на единицу |
071 |
previousMillis = currentMillis; |
072 |
delay (100); |
073 |
//lcd.clear(); |
074 |
if (p1>10) //устанавливаем придел изменения переменной = 10 |
075 |
{ //если больше предела |
076 |
p1=0; //то возвращаем ее к 0 (тут код условия что делать при достижении приделов) |
077 |
} |
078 |
} |
079 |
//UP для р2 |
080 |
if (digitalRead(upPin)== HIGH && m==2) |
081 |
{ |
082 |
p2++; |
083 |
previousMillis = currentMillis; |
084 |
delay (100); |
085 |
//lcd.clear(); |
086 |
if (p2>10) |
087 |
{ |
088 |
p2=0; |
089 |
} |
090 |
} |
091 |
//UP для р3 |
092 |
if (digitalRead(upPin)== HIGH && m==3) |
093 |
{ |
094 |
p3++; |
095 |
previousMillis = currentMillis; |
096 |
delay (100); |
097 |
//lcd.clear(); |
098 |
if (p3>1) |
099 |
{ |
100 |
p3=0; |
101 |
} |
102 |
digitalWrite(ledPin, p3); |
103 |
} |
104 |
//сдесь код для уменьшения значений |
105 |
//аналогичен коду увеличения если нужно |
106 |
|
107 |
//Вывод меню |
108 |
//Описание экранов меню |
109 |
lcd.clear(); |
110 |
if (m==0) //переменная m=0 |
111 |
{ //отображаем |
112 |
lcd.setCursor(3, 0); //******************* |
113 |
lcd.print( "Main Screen" ); //*Main Screen * |
114 |
lcd.setCursor(0, 1); //*P1=p1 P2=p2 LED=0* |
115 |
lcd.print( "P1=" ); //******************* |
116 |
lcd.print(p1); |
117 |
lcd.print( " P2=" ); |
118 |
lcd.print(p2); |
119 |
lcd.print( " LED=" ); |
120 |
lcd.print(p3); |
121 |
} |
122 |
else if (m==1) //переменная m=1 |
123 |
{ //отображаем |
124 |
lcd.setCursor(0, 0); //******************* |
125 |
lcd.print( "Parametr-1" ); //*Parametr-1 * |
126 |
lcd.setCursor(0, 1); //*P1=p1 * |
127 |
lcd.print( "P1 = " ); //******************* |
128 |
lcd.print(p1); |
129 |
} |
130 |
else if (m==2) //переменная m=2 |
131 |
{ //отображаем |
132 |
lcd.setCursor(0, 0); //******************* |
133 |
lcd.print( "Parametr-2" ); //*Parametr-2 * |
134 |
lcd.setCursor(0, 1); //*P2=p2 * |
135 |
lcd.print( "P2 = " ); //******************* |
136 |
lcd.print(p2); |
137 |
} |
138 |
else if (m==3) //переменная m=3 |
139 |
{ //отображаем |
140 |
lcd.setCursor(0, 0); //******************* |
141 |
lcd.print( "LED Control" ); //LED Control * |
142 |
lcd.setCursor(0, 1); //LED = p3 * |
143 |
lcd.print( "LED = " ); //******************* |
144 |
lcd.print(p3); |
145 |
} |
146 |
//Проверка автовозврата |
147 |
if (currentMillis - previousMillis > interval) //Если счетчик |
148 |
{ |
149 |
previousMillis = currentMillis; //достиг интервала |
150 |
m=0; //то отобразить главный экран |
151 |
//lcd.clear(); |
152 |
} |
153 |
//yul-i-an@gmail.com форум allduino.forum2x2.ru |
154 |
} |
В первом посте похоже запорол исходный код, вставил криво.
Так вот, запустил я его, всё класно, но мерцает экран, может кто смог бы подсказать где поставить перерисовку экрана, чтобы она не заставляла его постоянно мерцать.
Ясно - всё хорошо, но плохо.
не вникая в суть программы можно сделать вывод, что автор пытался избавиться от мерцания(//lcd.clear();), но не осилил.
по сути:
- lcd.clear() нужно использовать, тогда когда необходимо очистить весь экран.
- применение delay (100) тоже маловразумительно, может и не влияет на мерцания, но тормозит выполнение программы, что не есть правильно.
В том то и вопрос, delay по сути подвешивает весь процесс на какое то время. Из моих догадок - надо каким то образом повесить lcd.clear только там, где у нас происходят нажатие на кнопки, в том числе и при изменении параметров.
Клапауций буду крайне благодарен если поможете асилить новичку сей код.
Код не смотрел, но, есть варианты не чистить экран, а выделить в памяти место под буфер для вывода и обновлять этот буфер, а потом его выводить, тогда и чистить экран не нужно.
А вам доводилось делать меню?
На самом деле я ищу вариант с наименее запутанной структурой и простотой использования. Может есть идеи, примеры?
Не вижу проблем, DI HALT эту тему (отображение информации на лсд экран) разжевал вполне достаточно, чтобы этим вопросом не париться.
Потому я и говорю, пишем информацию в буфер, а потом весь буфер отображаем. Чему тут моргать то?
ну, так и делайте c единственной поправкой - если вам не нужно очищать экран, то не нужно этого делать, если вам кажется, что вам нужно очистить экран, то возможно вам нужно перезаписать экран или перезаписать один или несколько символов.
все записи в экран производить не в общем теле программы, а по условию изменения чего-либо - изменения переменной, нажатия на кнопку, предыдущие состояния переменных и состояний кнопок хранить в оперативке.
можно использовать следующие конструкции - типо подпрограммы:
Спасибо большое, будем мучать.
А у вас нет примеров ваших меню из проектов?
И что можете сказать про применение EEPROM для хранения данных?
В общем получилось немного оптимизировать код на свой манер. Единственное что не нравится - как реагируют кнопки на нажатие. Иногда может пропустить значение, тоесть как двойное нажатие срабатывает. Насколько помню, это как то лечится с помощью bounce. Но я честно говоря дикий нуб в этом деле, поэтому может кто поможет поправить код. Ещё не получилось прописать кнопку down, чтобы значение можно было уменьшать :( Что ещё хочу - избавиться от delay.
Вот что вышло:
Клапауций
Может могли бы поглядеть мой код, сказать где что поправить. Спасибо заранее!
Клапауций
Может могли бы поглядеть мой код, сказать где что поправить. Спасибо заранее!
я не программист совсем - радиомонтажник
поправить могу посоветовать только аппаратно железную часть и архитектурно программый код (в меру своего понимания концепции меню девайса)
- конденсаторы 0,1 микрофарад на кнопки, что бы избавиться от паразитного дребега некачественных кнопок. двойные нажатия останутся, но не будут настолько непредсказуемыми и раздражающими, можно программно затупить ввод, но тогда будет раздражать невозможность быстрого ввода параметров/переключения меню. но лучше изначально решать эту проблему на этапе построения логической блок-схемы работы всега. к примеру - лучше, что бы некие параметры изменялись при нажатии или, наоборот, при отпускании кнопки.
- меню есть индикация работы девайса (не более), весь основной код должен работать корректно даже, если полностью закомментировать код меню. Тогда всё становится проще - на этапе тестирования кода индицируем на один экран все переменные: служебные переменные меню(номера меню и подменю), переменные программ, переменные, которые поступают на девайс, прочие. Рулите этими переменными с помощью кнопок, вылавливаете тараканов - долго, но просветляет суть своих хотелок. Только затем одеваете всё бохатство в красивые экраны - почему мигает будет понятно.
*сам лично - пока на этапе построения простого меню на двух энкодерах и одной кнопке(выбор экранов производится кручением одного энкодера при нажатой кнопке, манипуляции с переменными в пределах одного экрана производится энкодерами(простой вариант - две переменные, по одной на каждый энкодер, сложный вариант - одним энкодером выбираем переменную, вторым - ея изменяем), запоминание в оперативку изменений производим во время отпускания кнопки(одновременно пишем изменения состояния всего в ееепром). Публиковать код смысла не вижу - пока сам не знаю, чем это всё окончится - не желается, что бы пару неофитов потом мучились со странным.
Спасибо за инфу, будет интересно поглядеть ваш код, когда доведёте до ума.
*сам лично - пока на этапе построения простого меню на двух энкодерах и одной кнопке(выбор экранов производится кручением одного энкодера при нажатой кнопке, манипуляции с переменными в пределах одного экрана производится энкодерами(простой вариант - две переменные, по одной на каждый энкодер, сложный вариант - одним энкодером выбираем переменную, вторым - ея изменяем), запоминание в оперативку изменений производим во время отпускания кнопки(одновременно пишем изменения состояния всего в ееепром). Публиковать код смысла не вижу - пока сам не знаю, чем это всё окончится - не желается, что бы пару неофитов потом мучились со странным.
дружище, ты изобретаеш лисапед, причем очень кривой и страшный :)
возьми готовые решения.. когда крутиш ручку то передвигаешся по меню по кругу, а когда нажал на ручку то выбрал и першел на следующий уровень меню.. и количество кнопок уменьшится и срочки кода усохнут :)
дружище, ты изобретаеш лисапед, причем очень кривой и страшный :)
возьми готовые решения.. когда крутиш ручку то передвигаешся по меню по кругу, а когда нажал на ручку то выбрал и першел на следующий уровень меню.. и количество кнопок уменьшится и срочки кода усохнут :)
готовые решения - это где?, посоветуй топикстартеру - у него мигает халабуда.
*повторю описание своего велосипеда - пока не нашёл отличий от твоего описания невелосипеда:
аппаратно - два энкодера, одна кнопка.
когда кручу энкодер1 при нажатой кнопке, то переключаю экраны по кругу, когда просто кручу энкодер1, то переключаю выбор переменной в пределах одного экрана, энкодером2 меняю значение, выбранной энкодером1 переменной.
куда там ещё код сократить - не знаю: три служебных переменных меню(состояния энкодеров 1,2, состояние кнопки), состояния энкодеров запоминаются в еепром. согласно значениям этих трёх переменных происходит печать в индикатор.
оставь адын энкодер. нафига тебе их два то? и почему не три?
оставь адын энкодер. нафига тебе их два то? и почему не три?
точно - меню для бедных с одной кнопкой.
*я расписал подробно, зачем два энкодера - потому, что можно два, но не принципиально обязательно.
Друзья, а с моим кодом мне больше никто не поможет? Энкодер кстати интересная идея.
Друзья, а с моим кодом мне больше никто не поможет? Энкодер кстати интересная идея.
перепиши сам всё с нуля - будешь хоть понимать, что глючит.
djominov,
Похоже у вас неправильно собрана электрическая схема кнопок.
У меня нет мерцания.
Привет всем,
kisoft
помогите с этой темой, где можно почитать подробнее, можите сбросить
пару ссылок. А то облазил google и нечего не нашел.
" Не вижу проблем, DI HALT эту тему (отображение информации на лсд экран) разжевал вполне достаточно, чтобы этим вопросом не париться.
Потому я и говорю, пишем информацию в буфер, а потом весь буфер от
ображаем. Чему тут моргать то? "
Di halt lcd - в гугле.
Найдете учебный курс, там всё есть
Вот тут по смотори
Кто нибуть с таким экраном разбирался G128064-MH-R1 http://www.rcscomponents.kiev.ua/r46646.html
И что нужно знать о экране чтоб подключить к ардуино?
И что нужно знать о экране чтоб подключить к ардуино?
Нужно знать какой там контролер стоит. Дальше либо искать готовые библиотеки на данный контроллер, либо брать даташит и изучать. По вышеприведенной ссылке указан контроллер дисплея и дан даташит на сам дисплей, где приведена распиновка.
Я добавил изминение в код для своего устройства которое откривает заслонку при определенных условиях температуры и давления, и эти параметры срабатывания можно менять нажатием кнопки UP и DOWN и, то сейчас меня интересует как можно сделать чтоб при дальнейшем включении были предидущие настройки срабатывания ???
"Энергонезависимая память" она же EEPROM
какую функцию использовать если мне нужно увеличить параметр на 10 или 20 едениц одним нажатием так как при такой (P1++) только на еденицу увеличивает?
P1 = P1+10
Благодарю, но лучше создать новую переменную как по мне R1 = p1+10 или если нада больше R1 = p1*10 и подставлять R1 там где нужно изминять параметр, а то код неадекватно работает :)
А потом к новой переменной будем 10 добавлять и так до бесконечности. Р1 в этом случае ведь не изменится.
я разобрался в общем ;)
Теперь вопрос стал разобратся с сохранением настроек и заданых параметров после последнего включения ардуино с использованием EEPROM библиотеки
Раздел "Программирование" в самом низу. Там правда только для однобайтовых переменных. По многобайтовым, форум почитайте.
вот мой доработанный код. Экран не мерцает. В качестве экрана и кнопок использовал LCD Keypad Shield.
Экран обновляется по взведенному флагу. Если флаг не взведен, то экран не обновляется.
всех приветствую, у меня проблема, решить не могу, в логику не укладывается
для наладки переменных использую монитор порта, в котором выводятся значения переменных. еще стоит дисплей от нокиа 3310, который должен будет остаться в конечном варианте. в мониторе порта переменные выводяться правильные. а на дисплее переменная которая управляет шимом( переменная равна шиму) не корректна до 100, после 100 соответсвует действительности(сравниваю по результатам монитора порта и свечением диода).
ураааа. эксперементы рулят. дописал по ln и все показания корректны
lcd.println(r);
Почему в выводе на экран перед числом стоит "0"? Как исправить???
код в студию, у меня все четко
что такое кнопка
NEXT
Добрый день. Такой к вам имеется вопрос.
На сайте http://winavr.scienceprog.com/example-avr-projects/avr-lcd-menu-routine.html нашел пример меню на LCD дисплее и atmega8. Четырьмя кнопками задается режим работы 3 светодиодов. В архиве кроме файлов проекта есть файл симуляции протеуса. Проверил - работает как надо.
Решил попробывать просимулировать для ардуино - пролема в том что не происходит опроса кнопки, точнее условие по нажатию не срабатывает. Опрос в исходном коде(mega8) идет в теле обработчика прерывания таймера 0 каждые 122 раза в секунду(Гц). Таймер 0 в среде ардуино системный поэтому я сделал аналогично на таймере 2 - 100 раз в секунду. В остальном практически нет изменений.
menu.c (mega8)
Моя аналогия с ошибкой
Не совсем понимаю смысл применения макроса loop_until_bit_is_set. Зачем ждать отпускания кнопки?
И прошу не делйте мне замечаний по поводу этого, никто не запрещает тут использовать while(1) {}
Вопрос снят