Меню для LCD 2004 с прокруткой пунктов.
- Войдите на сайт для отправки комментариев
Коллеги, добрый день!
Дошли руки до создания меню для своего проекта на LCD 2004. Взялся за код и встретил несколько неприятных моментов.
Всего будет 5 кнопок (влево, вверх, вправо, вниз и ввод) повесил их на аналоговый пин, тема стандартная.
Вопрос первый: На главном экране очень сильно мерцает текст, который должен будет (по идее) обновляться (часы, температура и др. значения).
Вопрос второй: Если я нажимаю кнопку вниз (всего 5 пунктов меню) 5 раз, то код выполняется правильно. Т.е. стрелочка опускается до 5го пункта а потом переходит (по пятому нажатию) снова на первый пункт. НО! если нажа, к примеру, два раза кнопку вниз а потом попытаться вернуться снова на первый пункт, то тут сразу вылезают мои кривые руки в программировании. Грубо говоря, код рассчитан только на то, чтобы мы нажимали строго 5 или 4 раза вниз (спускаясь к 5му или возвращаясь с пятого к первому пункту меню) или наоборот нажимали вверх и снизу вверх попадали на первый пункт меню. ВОПРОС: Как это побороть?
Ещё не понятно как избавиться от ДЕЛЕЕВ. Пробовал вместо них ставить МИЛЛИСЫ, но что-то не то выходит
В программировании знаний не много, надеюсь на Вашу помощь :)
Спасибо!
#include <Wire.h> #include <LiquidCrystal_I2C.h> // Библиотека дисплея ///////////////////////////////ДИСПЛЕЙ 1602 I2C////////////////////////////////////////////// LiquidCrystal_I2C lcd(0x3F,20,4); // Адрес I2C (0x3F) ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////ДИСПЛЕЙ 1602 I2C////////////////////////////////////////////// byte tnv[8] = {B00100,B01010,B01010,B01110,B01110,B11111,B11111,B01110,}; // Знак температуры byte gradus[8] = {B11100,B10100,B11100,B00000,B00000,B00000,B00000,B00000,}; // Знак градуса byte vlazhnost[8] = {B00100,B00100,B01110,B01110,B11111,B11111,B11111,B01110,}; // Знак влажности byte battery[8] = {B01110,B11011,B10001,B11111,B10001,B11111,B10001,B11111,}; // Знак батарейки byte alarm[8] = {B00100,B01110,B01110,B01110,B01110,B11111,B00000,B00100,}; // Знак Аварии ///////////////////////////////////////////////////////////////////////////////////////////// byte indexmenu = 0; // индекс для входа в меню byte direct = 0; // индекс пунктов меню boolean avariya; boolean AVT_disinfection; float set_point = 46.00; byte set_menu_time = 30; // время нахождения в меню в секундах byte YR = 0; // год byte DY = 1; // день byte MN = 1; // месяц byte HO = 0; // часы byte MI = 0; // минуты int TNV; int Humidity; int T1; // Датчик температуры Т1 (подача ЦО) int T2; // Датчик температуры Т2 (обратка ЦО) int T3; // Датчик температуры Т3 (подача ЦО ТП) int T4; // Датчик температуры Т4 (обратка ЦО ТП) unsigned long currentTime; // время текущее unsigned long loopTime; // время для опроса датчиков или для времени задержки нахождения в меню unsigned long PAUZA; // время для опроса датчиков или для времени задержки нахождения в меню #include <Adafruit_ADS1015.h> // Библиотека ADS1115 Adafruit_ADS1115 ads(0x48); // Адрес I2C ADS1115 (0x48) #define xGAIN GAIN_TWOTHIRDS // делитель 1 bit = 0.1875 mV #define x1BIT 0.1875 // значение 1 бита /////////////////////////////Настройка точности///////////////////////////// // GAIN_TWOTHIRDS // 2/3x gain +/- 6.144V 1 bit = 0.1875 mV (default) // GAIN_ONE // 1x gain +/- 4.096V 1 bit = 0.125 mV // GAIN_TWO // 2x gain +/- 2.048V 1 bit = 0.0625 mV // GAIN_FOUR // 4x gain +/- 1.024V 1 bit = 0.03125 mV // GAIN_EIGHT // 8x gain +/- 0.512V 1 bit = 0.015625 mV // GAIN_SIXTEEN // 16x gain +/- 0.256V 1 bit = 0.0078125 mV //////////////////////////////////////////////////////////////////////////// int16_t sens_key; // переменная для чтения 3 пина ADS1115 void setup() { Serial.begin(115200); Wire.begin(); currentTime = millis(); // фиксируем значение текущего времени loopTime = currentTime; // приравниваем текущее время для цикла опроса датчиков температуры avariya = 1; AVT_disinfection = 1; ///////////////////////////////////ADS1115 I2C чип №0/////////////////////////////////////// ads.begin(); // инициализация библиотеки ADS1115 ads.setGain(xGAIN); ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////ДИСПЛЕЙ 2004 I2C////////////////////////////////////////// lcd.begin(); // включаем LCD 2004 ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// lcd.setCursor(0,0);lcd.print(" ");lcd.setCursor(0,1);lcd.print(" ");lcd.setCursor(0,2);lcd.print(" ");lcd.setCursor(0,3);lcd.print(" "); lcd.setCursor(6,1); lcd.print("ZDAROVKI"); lcd.setCursor(6,2); lcd.print("ver: 0.1"); delay(2000); lcd.setCursor(0,0);lcd.print(" ");lcd.setCursor(0,1);lcd.print(" ");lcd.setCursor(0,2);lcd.print(" ");lcd.setCursor(0,3);lcd.print(" "); ///////////////////////////////////////////////////////////////////////////////////////////// lcd.createChar(0, gradus); // Подключаем знак градуса lcd.createChar(1, vlazhnost); // Подключаем знак влажности lcd.createChar(2, tnv); // Подключаем знак градуса lcd.createChar(3, battery); // Подключаем знак батарейки lcd.createChar(4, alarm); // Подключаем знак Колокольчика } void loop() { /* sens_key = ads.readADC_SingleEnded(3); // читаем результат единичного преобразования */ Serial.print("Значение аналогового пина: "); Serial.print(analogRead(A0)); Serial.println(" "); Serial.print("Номер кнопки: "); Serial.print(keybyte()); Serial.println(" "); Serial.print("indexmenu: "); Serial.print(indexmenu); Serial.println(" "); Serial.print("direct: "); Serial.print(direct); Serial.println(" "); Serial.println(" "); ////////////////////////////Подключаем символы в цикл ЛУП//////////////////////////////////// lcd.createChar(0, gradus); // Подключаем знак градуса lcd.createChar(1, vlazhnost); // Подключаем знак влажности lcd.createChar(2, tnv); // Подключаем знак градуса lcd.createChar(3, battery); // Подключаем знак батарейки lcd.createChar(4, alarm); // Подключаем знак Колокольчика ///////////////////////////////////////////////////////////////////////////////////////////// currentTime = millis(); if ( keybyte() != 0 && indexmenu == 0 ){ lcd.setCursor(0,0);lcd.print(F(" "));lcd.setCursor(0,1);lcd.print(F(" "));lcd.setCursor(0,2);lcd.print(F(" "));lcd.setCursor(0,3);lcd.print(F(" ")); indexmenu = 2;} // если нажата одна из кнопок, и мы не были в меню до этого, тогда очищаем экран и попадаем в основное меню if ( keybyte() != 0 && indexmenu == 2){ loopTime = currentTime;} // если нажата кнопка, и мы находимся в меню, тогда фиксируем время последнего нажатия для того чтобы отсчитать секунды до возврата обратно if (currentTime >= (loopTime + (set_menu_time * 1000) ) ){ lcd.setCursor(0,0);lcd.print(F(" "));lcd.setCursor(0,1);lcd.print(F(" "));lcd.setCursor(0,2);lcd.print(F(" "));lcd.setCursor(0,3);lcd.print(F(" ")); indexmenu = 0; direct = 0;} // если текущее время больше чем время последнего нажатия в сумме с уставкой времени, тогда очищаем экран и выходим на главный экран if ( keybyte() == 0 && indexmenu == 0 ) { ///////////////////////////////////////////////////////////////////////////////////////////// // ГЛАВНЫЙ (Стартовый) экран ///////////////////////////////////////////////////////////////////////////////////////////// lcd.setCursor(0,1); // Ячейка 1 строка 2 lcd.print(char(2));lcd.print("="); lcd.setCursor(0,2); // Ячейка 1 строка 3 lcd.print(F("T1=")); lcd.setCursor(0,3); // Ячейка 1 строка 4 lcd.print(F("T2=")); lcd.setCursor(11,1); // Ячейка 12 строка 2 lcd.print(char(1));lcd.print("="); lcd.setCursor(11,2); // Ячейка 12 строка 3 lcd.print(F("T3=")); lcd.setCursor(11,3); // Ячейка 12 строка 4 lcd.print(F("T4=")); lcd.setCursor(2,1); // Ячейка 3 строка 2 lcd.print(TNV); // Выводим показания температуры tнв lcd.setCursor(4,1); // Ячейка 7 строка 2 lcd.print(char(0));lcd.print(F("C")); lcd.setCursor(13,1); // Ячейка 3 строка 2 lcd.print(Humidity); // Выводим показания влажности lcd.setCursor(15,1); // Ячейка 7 строка 2 lcd.print(F("%")); lcd.setCursor(3,2); // Ячейка 3 строка 2 lcd.print(T1,1); // Выводим показания температуры Т1 (1 полоска) с одним знаком после запятой lcd.setCursor(7,2); // Ячейка 7 строка 2 lcd.print(char(0));lcd.print(F("C")); lcd.setCursor(3,3); // Ячейка 3 строка 3 lcd.print(T2,1); // Выводим показания температуры Т2 (2 полосоки) с одним знаком после запятой lcd.setCursor(7,3); // Ячейка 7 строка 3 lcd.print(char(0));lcd.print(F("C")); lcd.setCursor(14,2); // Ячейка 14 строка 2 lcd.print(T3,1); // Выводим показания температуры Т3 (3 полоски) с одним знаком после запятой lcd.setCursor(18,2); // Ячейка 18 строка 2 lcd.print(char(0));lcd.print(F("C")); lcd.setCursor(14,3); // Ячейка 14 строка 3 lcd.print(T4,1); // Выводим показания температуры (4 полоски) с одним знаком после запятой lcd.setCursor(18,3); // Ячейка 18 строка 3 lcd.print(char(0));lcd.print(F("C")); ///////////////////////////////////////////////////////////////////////////////////////////// } if (indexmenu == 2) { //если мы заодим в меню - то if (direct == 0) { lcd.setCursor(0,1); lcd.print(">"); // ставим маркер в начало меню - первый пункт lcd.setCursor(3,0); lcd.print("MENU"); // Оглавление lcd.setCursor(1,1); lcd.print("1. Status"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("2. Mode select"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("3. Settings"); // объявляем пункт меню 3 direct = 1; delay(100); } if (keybyte() == 5 && direct == 5) { // Возврат на стартовый экран indexmenu = 0; } /* if (millis() - PAUZA > 200){ PAUZA = millis(); } */ // Выбор 2 пункта меню if (direct == 1 && keybyte()== 4 ) { // если нажали вниз lcd.setCursor(0,1); lcd.print(" "); // очищаем ячейку первого пункта lcd.setCursor(0,2); lcd.print(">"); // ставим маркер во вторую ячейку delay(200); direct = 2; } // конец блока // выбор 3 пункта меню if (direct == 2 && keybyte()== 4) { // если нажали вниз lcd.setCursor(0,2); lcd.print(" "); // очищаем ячейку второго пункта lcd.setCursor(0,3); lcd.print(">"); // ставим маркер в третью ячейку delay(200); direct = 3; } // конец блока // выбор 4 пункта меню if (direct == 3 && keybyte()== 4) { // если нажали вниз lcd.setCursor(1,1); lcd.print(" "); lcd.setCursor(1,2); lcd.print(" "); lcd.setCursor(1,3); lcd.print(" "); lcd.setCursor(1,1); lcd.print("2. Mode select"); // объявляем пункт меню 2 lcd.setCursor(1,2); lcd.print("3. Settings"); // объявляем пункт меню 3 lcd.setCursor(1,3); lcd.print("4. Incidents"); // объявляем пункт меню 3 delay(100); direct = 4; } // конец блока // выбор 5 пункта меню if (direct == 4 && keybyte()== 4) { // если нажали вниз lcd.setCursor(1,1); lcd.print(" "); // объявляем пункт меню 2 lcd.setCursor(1,2); lcd.print(" "); // объявляем пункт меню 3 lcd.setCursor(1,3); lcd.print(" "); // объявляем пункт меню 3 lcd.setCursor(1,1); lcd.print("3. Settings"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("4. Incidents"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("5. Exit"); // объявляем пункт меню 3 delay(100); direct = 5; } // конец блока // Возврат к пункту меню 1 из 5го if (direct == 5 && keybyte()== 4) { // если нажали вниз lcd.setCursor(0,1); lcd.print(">"); // ставим маркер в первую ячейку lcd.setCursor(0,3); lcd.print(" "); // очищаем ячейку четвертого пункта lcd.setCursor(1,1); lcd.print(" "); // объявляем пункт меню 2 lcd.setCursor(1,2); lcd.print(" "); // объявляем пункт меню 3 lcd.setCursor(1,3); lcd.print(" "); // объявляем пункт меню 3 lcd.setCursor(1,1); lcd.print("1. Status"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("2. Mode select"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("3. Settings"); // объявляем пункт меню 3 delay(100); direct = 1; } // конец блока // Возврат к пункту меню 1 из 2го if (direct == 2 && keybyte()== 2) { // если нажали вверх lcd.setCursor(0,1); lcd.print(">"); // ставим маркер во вторую ячейку lcd.setCursor(0,2); lcd.print(" "); // очищаем ячейку третьего пункта lcd.setCursor(1,1); lcd.print(" "); lcd.setCursor(1,2); lcd.print(" "); lcd.setCursor(1,3); lcd.print(" "); lcd.setCursor(1,1); lcd.print("1. Status"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("2. Mode select"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("3. Settings"); // объявляем пункт меню 3 delay(200); direct = 1; } // конец блока // Возврат к пункту меню 1 из 2го if (direct == 2 && keybyte()== 2) { // если нажали вверх lcd.setCursor(0,1); lcd.print(">"); // ставим маркер во вторую ячейку lcd.setCursor(0,2); lcd.print(" "); // очищаем ячейку третьего пункта lcd.setCursor(1,1); lcd.print(" "); lcd.setCursor(1,2); lcd.print(" "); lcd.setCursor(1,3); lcd.print(" "); lcd.setCursor(1,1); lcd.print("1. Status"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("2. Mode select"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("3. Settings"); // объявляем пункт меню 3 delay(200); direct = 1; } // конец блока // Возврат к пункту меню 2 из 3го if (direct == 3 && keybyte()== 2) { // если нажали вверх lcd.setCursor(1,1); lcd.print(" "); lcd.setCursor(1,2); lcd.print(" "); lcd.setCursor(1,3); lcd.print(" "); lcd.setCursor(1,1); lcd.print("2. Mode select"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("3. Settings"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("4. Incidents"); // объявляем пункт меню 3 delay(200); direct = 2; } // конец блока // Возврат к пункту меню 3 из 4го if (direct == 4 && keybyte()== 2) { // если нажали вверх lcd.setCursor(0,1); lcd.print(">"); // ставим маркер во вторую ячейку lcd.setCursor(0,2); lcd.print(" "); // очищаем ячейку третьего пункта delay(100); direct = 3; } // конец блока // Возврат к пункту меню 4 из 5го if (direct == 5 && keybyte()== 2) { // если нажали вверх lcd.setCursor(0,2); lcd.print(">"); // ставим маркер во вторую ячейку lcd.setCursor(0,3); lcd.print(" "); // очищаем ячейку третьего пункта delay(100); direct = 4; } // конец блока // Возврат к пункту меню 5 из 1го if (direct == 1 && keybyte()== 2) { // если нажали вверх lcd.setCursor(0,3); lcd.print(">"); // ставим маркер в третью ячейку lcd.setCursor(0,1); lcd.print(" "); // очищаем ячейку четвертого пункта lcd.setCursor(1,1); lcd.print(" "); lcd.setCursor(1,2); lcd.print(" "); lcd.setCursor(1,3); lcd.print(" "); lcd.setCursor(1,1); lcd.print("3. Settings"); // объявляем пункт меню 1 lcd.setCursor(1,2); lcd.print("4. Incidents"); // объявляем пункт меню 2 lcd.setCursor(1,3); lcd.print("5. Exit"); // объявляем пункт меню 3 delay(100); direct = 5; } // конец блока if (AVT_disinfection == 1) { // Функция дезинфекции включена lcd.setCursor(17,0); lcd.print("G"); } if (avariya == 1) { // Сработала авария lcd.setCursor(19,0); lcd.print(char(4)); } return;} // ограничение выполнения дальнейшей программы, пока мы в меню } byte keybyte () { int key = analogRead(A0); // read the value from the sensor if (key < 7) return 1; // Влево else if (key < 200) return 2; // Вверх else if (key < 380) return 3; // Вправо else if (key < 600) return 4; // Вниз else if (key < 900) return 5; // Выбор/Ввод else return 0; }
Разбор неправильностей того, что у Вас написано тянет не десяток страниц. Я говорю не о мелких ошибках, а об идеологических неправильностях. Единственный способ это исправить - переписать с нуля.
У меня к Вам вопрос. если Вы не умеете программировать, почему не хотите воспользоваться готовой библиотекой, написанной людьми, которые умеют?
Этого добра настолько навалом, что даже как-то неудобно за Вас ссылки искать.
У меня к Вам вопрос. если Вы не умеете программировать, почему не хотите воспользоваться готовой библиотекой, написанной людьми, которые умеют?
Ну скучно же, я вот тоже сам пытаюсь велосипеды изобретать. С течением времени из пяти колес три остаются.))))
"Памагите", соглашусь здесь лишнее. В качестве помощи предложил бы следующее: взять эти четыре сотни строк и начать переписывать по новой, пытаясь одновременно создавать законченные структурные блоки-подпрограммы. Убавит объем программы и растащит на что-то вменяемое эту жуткую свалку из лупа. ИМХО.
Ну скучно же, я вот тоже сам пытаюсь велосипеды изобретать. С течением времени из пяти колес три остаются.))))
Пару дней назад я делал то же самое, тоже меню со скроллингом, тоже изобретая велосипед, т.к. организовать меню с помощью списков или структур не мог - не было понимания как это делать, а чтение теории света в конце туннеля не прибавляло. Теперь , когда ОНО работает, я бы переписал по-другому, но блин велосипед ездит, а у меня еше куча непостроенных велосипедов впереди :)
Указать где у Вас в этом длинном коде ошибка я не могу, хреново я чужой код читаю. Дать кусок своего рабочего - могу, если Вам не лень будет разбираться.
Все получится! Объемляете переменную unsigned long time глобально ( она много где Вам понадобится)
и вместо delay(1000); пишите
Вы мне чужие заслуги не приписывайте.)))
Вы мне чужие заслуги не приписывайте.)))
Большое спасибо за помощь с millis, попробовал, работает отлично!
А по поводу Вашего кода, с удовольствием бы глянул и изучил :)
Ещё раз спасибо!
и вместо delay(1000); пишите
Вы уверены, что это надо делать?
Вы уверены, что это надо делать?
Вы уверены, что это надо делать?
Но ведь работает же, если верить ТС - "отлично", а главное делает то же, что и делей, только с миллисом.)))))
Теоретиццки, если между выполнением присваивания time = millis() и следующей строчкой
while(millis()-time<1000);
произойдет обнуления millis() то цикл будет длится неожиданно долго. :) Тут кык бы да. Но вероятность такого события писец какая низкая, с практицццкой точки зрения. Но помнить надо. Возьмите меня в секту!
А по поводу Вашего кода, с удовольствием бы глянул и изучил :)
Да пожалуйста! Немного адаптировано, показана именно менюшка. Не претендую ни разу на истину и правильность, но так - работает.
Будут вопросы - велкам!
ПС. Это будущий блок управления аудио усилителем. Дисплей графический 12864 ST9720, , кнопок нет ваапще, только энкодер, библиотека u8g2
Спасибо!
Теоретиццки, если между выполнением присваивания time = millis() и следующей строчкой
while(millis()-time<1000);
произойдет обнуления millis() то цикл будет длится неожиданно долго.
разберись, для начала, как поведет себя в такой ситуации unsigned long