Меню для LCD 2004 с прокруткой пунктов.

ergeykl
Offline
Зарегистрирован: 20.04.2017

Коллеги, добрый день!

Дошли руки до создания меню для своего проекта на 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;
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Разбор неправильностей того, что у Вас написано тянет не десяток страниц. Я говорю не о мелких ошибках, а об идеологических неправильностях. Единственный способ это исправить - переписать с нуля.

У меня к Вам вопрос. если Вы не умеете программировать, почему не хотите воспользоваться готовой библиотекой, написанной людьми, которые умеют?

Этого добра настолько навалом, что даже как-то неудобно за Вас ссылки искать.

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

У меня к Вам вопрос. если Вы не умеете программировать, почему не хотите воспользоваться готовой библиотекой, написанной людьми, которые умеют?

Ну скучно же, я вот тоже сам пытаюсь велосипеды изобретать. С течением времени из пяти колес три остаются.))))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:
я вот тоже сам пытаюсь велосипеды изобретать
Так одно дело пытаться самому, и совсем другое чуть что, бежать на форум с криком "Памагите!".

bwn
Offline
Зарегистрирован: 25.08.2014

"Памагите", соглашусь здесь лишнее. В качестве помощи предложил бы следующее: взять эти четыре сотни строк и начать переписывать по новой, пытаясь одновременно создавать законченные структурные блоки-подпрограммы. Убавит объем программы и растащит на что-то вменяемое эту жуткую свалку из лупа. ИМХО.

5N62V
Offline
Зарегистрирован: 25.02.2016

bwn пишет:

Ну скучно же, я вот тоже сам пытаюсь велосипеды изобретать. С течением времени из пяти колес три остаются.))))

Пару дней назад я делал то же самое, тоже меню со скроллингом, тоже изобретая велосипед, т.к. организовать меню с помощью списков или структур не мог - не было понимания как это делать, а чтение теории света в конце туннеля не прибавляло. Теперь , когда ОНО работает, я бы переписал по-другому, но блин велосипед ездит, а у меня еше куча непостроенных велосипедов впереди :)

Указать где у Вас в этом длинном коде ошибка я не могу, хреново я чужой код читаю. Дать кусок своего рабочего  - могу, если Вам не лень будет разбираться. 

bwn пишет:
Ещё не понятно как избавиться от ДЕЛЕЕВ. Пробовал вместо них ставить МИЛЛИСЫ, но что-то не то выходит

Все получится!  Объемляете переменную unsigned long time глобально ( она много где Вам понадобится) 

и вместо delay(1000); пишите

time = millis();
while(millis()-time<1000);

 

bwn
Offline
Зарегистрирован: 25.08.2014

5N62V пишет:

bwn пишет:
Ещё не понятно как избавиться от ДЕЛЕЕВ. Пробовал вместо них ставить МИЛЛИСЫ, но что-то не то выходит

Вы мне чужие заслуги не приписывайте.)))

5N62V
Offline
Зарегистрирован: 25.02.2016

bwn пишет:

Вы мне чужие заслуги не приписывайте.)))

Пардон! ТС адресовывалось :)

ergeykl
Offline
Зарегистрирован: 20.04.2017

Большое спасибо за помощь с millis, попробовал, работает отлично!

А по поводу Вашего кода, с удовольствием бы глянул и изучил :)

Ещё раз спасибо!

kalapanga
Offline
Зарегистрирован: 23.10.2016

5N62V пишет:

и вместо delay(1000); пишите

time = millis();
while(millis()-time<1000);

Вы уверены, что это надо делать?

5N62V
Offline
Зарегистрирован: 25.02.2016

kalapanga пишет:

Вы уверены, что это надо делать?

Боже сохрани! 

bwn
Offline
Зарегистрирован: 25.08.2014

5N62V пишет:

kalapanga пишет:

Вы уверены, что это надо делать?

Боже сохрани! 

Но ведь работает же, если верить ТС - "отлично", а главное делает то же, что и делей, только с миллисом.)))))

5N62V
Offline
Зарегистрирован: 25.02.2016

Теоретиццки,   если между выполнением присваивания time = millis()  и следующей строчкой

while(millis()-time<1000);

произойдет обнуления millis() то цикл будет длится неожиданно долго. :) Тут кык бы да. Но вероятность такого события писец какая низкая, с практицццкой точки зрения. Но помнить надо. Возьмите меня в секту! 

5N62V
Offline
Зарегистрирован: 25.02.2016

ergeykl пишет:

А по поводу Вашего кода, с удовольствием бы глянул и изучил :)

Да пожалуйста! Немного адаптировано, показана именно менюшка. Не претендую ни разу на истину и правильность, но так - работает.

Будут вопросы - велкам! 


#define PRESS_EVENT 120//Длительность нажатия SELECT
#define MENU_LINES 4// Кол-во строк, выводимых на дисплей
#define MENU_ITEMS 7//кол-во пунктов меню

bool menu_event = 0; //флаг меню
unsigned long counter = 0;
//counter - переченная, которая инкриментируется в 
//обработчике прерываний от таймера, если нажата кнопка SELECT

//Для экономии оперативной памяти
//все пункты меню , подменю, все сообщения выводимые на дисплей
//хранятся в ПРОГМЕМ в виде строковых констант. Указатели на строковые
//константы хранятся в массиве, так же в ПРОГМЕМ. Индексы этого 
//массива передается в функцию вывода конкретной строки на дисплей.
void setup() {
//чего-то тут тяп-ляп
}

void loop() {
  //чего-то тут мутим-крутим

  //если кнопка SELECT нажата не меньше чем положено
  // - переходим в меню
  if(counter>PRESS_EVENT){menu_event = 1; menu_screen();}
}

void menu_screen(){
  while (!(PIND & (1 << 5)));//ждем, пока юзер не отпустит 
  //кнопку SELECT, которая на 5м пине. Пин подтянут к питанию
  counter = 0;//обнулии
  int menu_position = 0;//положение условного курсора построчно
  int add = 0; //добавочная переменная для скроллинга

  u8g2.setFont(u8g2_font_haxrcorp4089_t_cyrillic);
  u8g2.setFontMode(0);
//начало цикла меню, который длится пока установлен флаг меню
  do {
    u8g2.firstPage();
    do {//формирование страницы на дисплее, библ. u8g2
      u8g2.setCursor(30, 7);
      u8g2.setDrawColor(1);
      u8g2.print("МЕНЮ");//заглавие страницы
      u8g2.drawHLine(0, 9, 127);
      
//цикл вывода 4 пунтов меню на страницу
//больше не помещается :(
      for (byte i = 0; i < MENU_LINES; i++) {
        if (i + add == menu_position) {//если печатуемый
 //пункт меню совпадает с положением условного курсора 
 //то строка печатается на фоне нарисованного прямоугольника
 //инверсным цветом       
          u8g2.drawBox(9, 10 + 12 * i, 80, 11);
          softPrint(10, 18 + 12 * i, 0, 7 + i + add);
//передача данных в функцию печати. 1й и 2й аргументы - 
//координаты X Y, 3й аргумент - цвет, 4й аргумент - 
//какая именно строка из массива строк печатается
        }

        else softPrint(10, 18 + 12 * i, 1, 7 + i + add);
        //остальные строки печатаются нормальным цветом
      }

    } while ( u8g2.nextPage() );//выводим страницу на экран

    menu_position += getEncoder();//опрашиваем энкодер, если были
    //изменения - ин/декрименируем условный курсор
    if (menu_position < 0)menu_position = 0;
    if (menu_position > MENU_ITEMS - 1)menu_position = MENU_ITEMS - 1;
    //смотрим, чтоб не вывалился за лимиты
    
    if (menu_position > MENU_LINES - 1 + add)add++;//скроллинг строк 
    //если мы встали на 5й пункт меню, то 1ый не печатается
    //печатаются 2,3,4,5
    if (menu_position < add)add--;// и обратно

    if (counter > PRESS_EVENT) {//если нажат SELECT
      switch (menu_position) {//в зависимости от того, куда указывал курсор
        case 0:  menu_event = 0;//сброс флага меню для выхода из него
          counter = 0; last_encoder = encoder.read(); break;
        case 1: selector_event = 1; counter = 0; selectInput(); break;
  // установка флага подменю и переход на соответствующую функцию
//рисования этого подменю
        case 2: balance_event = 1; counter = 0; balanceScreen(); break;
        case 3: tembro_event = 1; counter = 0; tembroScreen(); break;
        case 4: relay_delay_event = 1; counter = 0; relayDelay(); break;
        case 5: item1_event = 1; counter = 0; notActivated(); break;
        case 6: item2_event = 1; counter = 0; notActivated(); break;
      }

    }
  } while (menu_event);
}

ПС. Это будущий блок управления аудио усилителем. Дисплей графический 12864 ST9720, , кнопок нет ваапще, только энкодер, библиотека u8g2

ergeykl
Offline
Зарегистрирован: 20.04.2017

Спасибо!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

5N62V пишет:

Теоретиццки,   если между выполнением присваивания time = millis()  и следующей строчкой

while(millis()-time<1000);

произойдет обнуления millis() то цикл будет длится неожиданно долго. 

разберись, для начала, как поведет себя в такой ситуации unsigned long