Выход из меню без перезагрузки

Sasha80
Offline
Зарегистрирован: 18.01.2016

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );

int Ledlcd = 10;                     //Номер Pin к которому подключена подсветка LCD
int brightnessLCD =0;                //Переменная в которой хранится уровень яркости LCD (От 0 до 254) 
int ekran = 0;                       // переменная для экранов меню

 byte key(){                          //// для кнопок ЛСД шилда  ////
  int val = analogRead(0);
    if (val < 50) return 5;         // кнопка назад
    else if (val < 150) return 3;   // кнопка вверх
    else if (val < 350) return 4;   // Кнопка вниз
    else if (val < 550) return 2;   // кнопка вперед
    else if (val < 800) return 1;   // кнопка входа в меню
    else return 0;  
   }
    
    
 ////////// - цикл 1 - /////////////
 
  void Submenu1(){            
  lcd.clear();
  char menuTxt[][20] = {"SET SUNRISE >>", "SET SUNSET  >>", "SET POWER   >>"};
  byte pos = 0;
  
    while(key() != 1){   //Выход из меню
    byte KEY = key();   
    delay(200);  
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 2) pos++;
    
         if (KEY == 5 && pos == 0) ;
    else if (KEY == 5 && pos == 1) ;
    else if (KEY == 5 && pos == 2) ;
  }
  lcd.clear();
  lcd.print("     -EXIT-   ");
  delay(1000);
 }  
 
    ///////////- цикл 2 -/////////////
    
    void Submenu2(){             
  lcd.clear();
  char menuTxt[][20] = {"SET SUNRISE >>", "SET SUNSET  >>", "SET POWER   >>"};
  byte pos = 0;
  
    while(key() != 1){ //Выход из меню
    byte KEY = key();   
    delay(200);  
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 2) pos++;
    
         if (KEY == 5 && pos == 0) ;
    else if (KEY == 5 && pos == 1) ;
    else if (KEY == 5 && pos == 2) ;
  }
  lcd.clear();
  lcd.print("     -EXIT-   ");
  delay(1000);
 }  
  
void menu(){
  lcd.clear();
  char menuTxt[][20] = {"Menu-1      >>", "Menu-2      >>"};
  byte pos = 0;
  
  while(1){          // вход в меню
    delay(200);  
    byte KEY = key();
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 1) pos++;
       
    if (KEY == 5 && pos == 0) Submenu1();
    else if (KEY == 5 && pos == 1) Submenu2();   
  }
  lcd.clear();
  lcd.print("     -EXIT-   ");
  delay(1000);
 }  
 
void setup(){
 lcd.begin(16, 2);   
 pinMode(Ledlcd, OUTPUT);
}

void loop()
{
  //// - обработка кнопок Экранов - ////
  
  if (key() == 1) menu();       // если не нажат селект
  else if (key() == 5) {
    ekran++;
    delay(200);
    if (ekran>2) 
    {
    ekran=0;
    }
    }
  else if (key() == 2) {
    ekran--;
    delay(200);
    if (ekran<0) 
    {
    ekran=2;
    }
    }
    
   if (ekran == 0){                       ////- 1-й ЭКРАН: Печатаем часы и дату -//////
    //lcd.clear();
    lcd.setCursor(2, 0);     // выводим инфу
    lcd.print("PROBA MENU 1");    
    }

    if (ekran == 1){                       ////- 1-й ЭКРАН: Печатаем часы и дату -//////
    //lcd.clear();
    lcd.setCursor(2, 0);     // выводим инфу
    lcd.print("PROBA MENU 2");    
    }

    if (ekran == 2){                       ////- 1-й ЭКРАН: Печатаем часы и дату -//////
    //lcd.clear();
    lcd.setCursor(2, 0);     // выводим инфу
    lcd.print("PROBA MENU 3");    
    }

    
  if (key() == 1) menu();          // если не нажата селект
    else if (key() == 3) {
      brightnessLCD += 5;     
    }
    else if (key() == 4) {
       brightnessLCD -= 5;      
    } 
  brightnessLCD = constrain(brightnessLCD, 80, 254); 
  analogWrite(Ledlcd, brightnessLCD);    // Устанавливаем состояние яркости для светодиода 
  delay(10); // Пауза 10 миллисекунд.  
    }

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Вот собственно проблема. Есть шилд 16Х2 с кнопками, есть ардуино уно. При нажатии на селект попадаем в главное меню, и затем в подмен., если так же нажать на селект. Выход из меню так же осуществляется через селек. Но из главного меню без перезагрузки не обойдешься. Вопрос как исправить приведенный выше скетч для того чтоб можно было выйти из главного меню без перезагрузки! Спасибо.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

скопировать строку 55 в строку 81

Sasha80
Offline
Зарегистрирован: 18.01.2016

Спасибо, но при таком раскладе, при нажатии на кнопку селект пишет выход из гланого экрана, причем зайти в меню первого уровня невозможно.

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

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

 byte key(){                          //// для кнопок ЛСД шилда  ////
  int val = analogRead(0);
  byte bt;
    if (val < 50) bt = 5;         // кнопка назад
    else if (val < 150) bt = 3;   // кнопка вверх
    else if (val < 350) bt = 4;   // Кнопка вниз
    else if (val < 550) bt = 2;   // кнопка вперед
    else if (val < 800) bt = 1;   // кнопка входа в меню
    else return 0;
    while (analogRead(0) < 800); // ждать пока кнопка не отпустится
    return bt;  
   }

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Спасибо добрый человек! Всавил ваш кусочек для кнопок, изменил 81-ю строку на "while(key() != 1){"

но выходит в главные экраны тоько если следуйщую строку "delay(200);" закомментировать, но при этом остальные переходы не пашут. Пожалуйста, помогите еще чуть чуть!

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Похоже проблема в этом:

    while(key() != 1){ //Выход из меню
    byte KEY = key();   

Попробуй так, в строках 27-28, 55-56, 81-83:

    byte KEY;
    while((KEY=key()) != 1){ //Выход из меню

delay() не нужны.

Sasha80
Offline
Зарегистрирован: 18.01.2016

Примногоблагодарен Andy. Реально помог. Вся структура вложенных меню работает замечательно!  Осталось решить проблему с экранами (128-143) и ручной регулировкой яркости (147-157) дисплея. Хотя это две одинаковые проблемы.

void loop()
{
    lcd.setCursor(3, 0);     
    lcd.print("PROBA MENU");    
   
    //byte KEY;
    //while((KEY=key()) != 1){

    if (key() == 1) menu();          
    else if (key() == 3) {
      brightnessLCD += 5;     
    }
    else if (key() == 4) {
      brightnessLCD -= 5;      
    } 
  brightnessLCD = constrain(brightnessLCD, 20, 254); 
  analogWrite(Ledlcd, brightnessLCD);     
  //delay(10); // Пауза 10 миллисекунд.  
    }

Прообовал разные варианты, то меню вновь не пашет, то яркость не меняется. Вобщем мозгов моих не хватило. Andy если не обременительно помоги еще немного!

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Попробуй так:

void loop()
{
  byte KEY=key();
  switch (KEY)
  {
  case 1: menu(); break;
  case 2: if (--ekran<0) ekran=2; break;
  case 3: brightnessLCD += 5; break;
  case 4: brightnessLCD -= 5; break;
  case 5: if (++ekran>2) ekran=0; break;
  default: break;
  }
  if (KEY==2 || KEY==5)
  {
    lcd.setCursor(2, 0);
    switch (ekran)
    {
    case 0: lcd.print("PROBA MENU 1"); break;
    case 1: lcd.print("PROBA MENU 2"); break;
    case 2: lcd.print("PROBA MENU 3"); break;
    }
  }
  if (KEY==3 || KEY==4)
  {
    brightnessLCD = constrain(brightnessLCD, 80, 254); 
    analogWrite(Ledlcd, brightnessLCD);    // Устанавливаем состояние яркости для светодиода 
  }
}

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Поставил часть этого кода! Почти работает. Проблема в следующем:

При сбросе черный экран, яркость на ноль кнопки регулировки яркости работают, но экран пустой. Как только начинаю листать экраны (они появляются с "PROBA MENU 2"). Т.Е со второго экрана, и затем циклично как и задумывалось. Заходит в меню тоже хороше, но выходит из главного меню "плоховато", всмысле виснет с надписью "-EXIT-" Дальше можно опять кнопками экранов щелкать, тогда он выходит в штатный режим. Как то так!

PS/ Убирал строки с 13 по 22 (экраны) вместо них одну надпись оставил, все работает как надо!

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Sasha80 пишет:
При сбросе черный экран, яркость на ноль кнопки регулировки яркости работают, но экран пустой. Как только начинаю листать экраны (они появляются с "PROBA MENU 2"). Т.Е со второго экрана, и затем циклично как и задумывалось.

В setup() надо добавить несколько строк для установки яркости и вывода первой надписи:

lcd.print("PROBA MENU 1");
brightnessLCD = constrain(brightnessLCD, 80, 254);
analogWrite(Ledlcd, brightnessLCD); 

Sasha80 пишет:
Заходит в меню тоже хороше, но выходит из главного меню "плоховато", всмысле виснет с надписью "-EXIT-" Дальше можно опять кнопками экранов щелкать, тогда он выходит в штатный режим. Как то так!

А тут можно попробовать изменить строку 13 в моем коде:

if (KEY==2 || KEY==5 || KEY==1)

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Сейчас займусь! Подскажите еще, когда кнопки работают в таком редиме (на разъединение) коректную работу блинка можно наладить. 

lcd.blink();

Ато магающий курсор видно только при зажатой кнопе.

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

В setup() забыл добавить установку позиции курсора lcd.setCursor(2, 0); перед выводом строки.

Блинк можно сделать так (добавить в loop() перед последней закрывающей скобкой):

if (millis()-time > 1000)//раз в секунду
{
  time=millis();
  lcd.blink();
}

unsigned long time;//надо объявить где-то вне loop()

Sasha80
Offline
Зарегистрирован: 18.01.2016

Все подставил, все работает. С блинком буду разбираться, пока не совсем понял. Спасибо Andy! 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Вот кусок кода, который стоит до сетапа:

//*********************************************************************************//
//***************** Цикл установки мощности MIN & MAX вентилятора *****************//
//*********************************************************************************//

  void setPower_Fan(){      
  byte pos = 5;   
    lcd.clear();
    lcd.blink();
      byte KEY;                                        // читаем состояние кнопок
      while((KEY=key()) != 1){                         // крутим   цикл   
    lcd.setCursor(0, 1);
    lcd.print(" *Set to save!* ");
    
    lcd.setCursor(0, 0);     // выводим инфу
    lcd.print("MAX=");
      if (FANPWM_MAX < 10) lcd.print("0");
      if (FANPWM_MAX < 100) lcd.print("0");
    lcd.print(FANPWM_MAX);
   
    lcd.setCursor(9, 0);
    lcd.print("MIN=");
     if (FANPWM_MIN < 10) lcd.print("0");
     if (FANPWM_MIN < 100) lcd.print("0");
    lcd.print(FANPWM_MIN);
    
    lcd.setCursor(pos, 0);                       // устанавливаем курсор согласно позиции
    
    if (KEY == 5 && pos < 14) pos += 9;           // крутим позицию
    else if (KEY == 2 && pos > 5) pos -= 9; 
    
    else if (pos == 5 && KEY == 3) FANPWM_MAX++;   // крутим значения
    else if (pos == 5 && KEY == 4) FANPWM_MAX--;
    else if (pos == 14 && KEY == 3) FANPWM_MIN++;
    else if (pos == 14 && KEY == 4) FANPWM_MIN--;    
          
    if (FANPWM_MAX > 255) FANPWM_MAX = 0;            // устанавливаем макс. значения переменной температуры
    else if (FANPWM_MIN > 255) FANPWM_MIN = 0;
        
    }  // конец цикла
    
    lcd.noBlink(); 
    lcd.clear();

    EEPROM.write(46, FANPWM_MAX);    // Зашиваем значение MAX в память
    EEPROM.write(47, FANPWM_MIN);    // Зашиваем значение MIN в память
   
    lcd.print("    -SAVING-  ");
    delay(1000);
    } 

Подставлял вместо моего блинка - ваш, нет эффекта. Водставлял ваш блинк в цикл программы, он появляется на главном экране- это хороше, но плохо то что он там мне не нужен :)  Вот как бы ваш кусочек прикрутить к тому месту, где он нужен. Строка №8

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Логично. Блинк нужен там, где нужен ввод с клавиш, стало быть ему место в функции key()

byte key()                          //// для кнопок ЛСД шилда  ////
{
  int val = analogRead(0);
  byte bt;
  if (millis()-time > 1000)//раз в секунду
  {
    time=millis();
    lcd.blink();
  }
  if (val < 50) bt = 5;         // кнопка назад
  else if (val < 150) bt = 3;   // кнопка вверх
  else if (val < 350) bt = 4;   // Кнопка вниз
  else if (val < 550) bt = 2;   // кнопка вперед
  else if (val < 800) bt = 1;   // кнопка входа в меню
  else return 0;
  while (analogRead(0) < 800); // ждать пока кнопка не отпустится
  return bt;  
}

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Собственно проблема состоит не в том что blink(); отсутствует, а в том что он появляется (мигает) только при зажатой кнопке. Например в подменю где происходит настройка параметров его не видно, пока не нажмешь кнопку, нажал и держишь ее, блинк есть и он мигает, отпустил кнопку- нет блинка! Я так понимаю это из за реверса нажатия  

while (analogRead(0) < 800); // ждать пока кнопка не отпустится

Вот собственно суть проблемы, а так то он был. 

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Выходит, пока кнопка нажата программа не бегает по циклу, ждет отпускания кнопки, в это время курсор моргает. При отпускании кнопки программа в цикле выводит символы на дисплей и меняет позицию курсора, курсор попросту не успевает моргать.

Вывод на дисплей надо делать однократно, а не в цикле, как-то так:

//*********************************************************************************//
//***************** Цикл установки мощности MIN & MAX вентилятора *****************//
//*********************************************************************************//

  void setPower_Fan(){      
  byte pos = 5;   
  lcd.clear();
  lcd.blink();
  byte KEY; 
  while(1)                         // крутим   цикл   
  {
    lcd.setCursor(0, 1);
    lcd.print(" *Set to save!* ");
    
    lcd.setCursor(0, 0);     // выводим инфу
    lcd.print("MAX=");
    if (FANPWM_MAX < 10) lcd.print("0");
    if (FANPWM_MAX < 100) lcd.print("0");
    lcd.print(FANPWM_MAX);
   
    lcd.setCursor(9, 0);
    lcd.print("MIN=");
    if (FANPWM_MIN < 10) lcd.print("0");
    if (FANPWM_MIN < 100) lcd.print("0");
    lcd.print(FANPWM_MIN);
    
    lcd.setCursor(pos, 0);                       // устанавливаем курсор согласно позиции

    while ((KEY=key()) == 0);//жду нажатия кнопки
    if (KEY == 1) break;

    if (KEY == 5 && pos < 14) pos += 9;           // крутим позицию
    else if (KEY == 2 && pos > 5) pos -= 9; 
    
    else if (pos == 5 && KEY == 3) FANPWM_MAX++;   // крутим значения
    else if (pos == 5 && KEY == 4) FANPWM_MAX--;
    else if (pos == 14 && KEY == 3) FANPWM_MIN++;
    else if (pos == 14 && KEY == 4) FANPWM_MIN--;    
          
    if (FANPWM_MAX > 255) FANPWM_MAX = 0;            // устанавливаем макс. значения переменной температуры
    else if (FANPWM_MIN > 255) FANPWM_MIN = 0;
        
  }  // конец цикла
    
  lcd.noBlink(); 
  lcd.clear();

  EEPROM.write(46, FANPWM_MAX);    // Зашиваем значение MAX в память
  EEPROM.write(47, FANPWM_MIN);    // Зашиваем значение MIN в память
   
  lcd.print("    -SAVING-  ");
  delay(1000);
} 

 

dr.lmg
dr.lmg аватар
Offline
Зарегистрирован: 07.01.2016

Подпишусь. Планирую делать похожее меню для своего TFT дисплея.

Sasha80
Offline
Зарегистрирован: 18.01.2016

Докладываю. Заготовка меню полностью функциональна. Работают кнопки, блинк, выход осуществлен без перезагрузки контроллера! Что я бы без помощи уважаемого Andy скорее всего не сделал бы. Надо учиться! Еще раз скажу - спасибо добрый человек! Может тема кому будет полезна, например для различных термостатов и т.д.

skalinas
Offline
Зарегистрирован: 13.01.2016

Sasha80 пишет:
Докладываю. Заготовка меню полностью функциональна. Работают кнопки, блинк, выход осуществлен без перезагрузки контроллера! Может тема кому будет полезна, например для различных термостатов и т.д.

Очень интересно увидеть ваш код, делаю меню для термо-гигрометра сауны.

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Код нужно под себя будет заточить!

#include <EEPROM.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );

#define FANPWM_PIN 11                //Пин порта, где будет ШИМ Охлаждения

int Ledlcd = 10;                     //Номер Pin к которому подключена подсветка LCD
int brightnessLCD =0;                //Переменная в которой хранится уровень яркости LCD (От 0 до 254) 
int ekran=0;

unsigned long time;

 float tempe = 0; 
 byte settempOn;
 byte settempOff;
 byte FANPWM_MAX;
 byte FANPWM_MIN;    
 
 byte key(){                          
 int val = analogRead(0);
 byte bt;
   if (val < 50) bt = 5;         // кнопка назад
   else if (val < 150) bt = 3;   // кнопка вверх
   else if (val < 350) bt = 4;   // Кнопка вниз
   else if (val < 550) bt = 2;   // кнопка вперед
   else if (val < 800) bt = 1;   // кнопка входа в меню
   else return 0;
   while (analogRead(0) < 800);  // ждать пока кнопка не отпустится
   return bt;  
  }
    
 ////////// - цикл 1 - /////////////
 
  void Submenu1(){            
  lcd.clear();
  char menuTxt[][20] = {"SET SUNRISE >>", "SET SUNSET  >>", "SET POWER   >>"};
  byte pos = 0;
  
  byte KEY;
  while((KEY=key()) != 1){  
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 2) pos++;
    
         if (KEY == 5 && pos == 0) ;
    else if (KEY == 5 && pos == 1) ;
    else if (KEY == 5 && pos == 2) ;
  }
  lcd.clear();
  lcd.print("     -EXIT-   ");
  delay(500);
 }  
 
//**********************************************************************************//
//********************цикл установки границ температурного коридора*****************//
//**********************************************************************************//
 
  void SetFanOnOff(){      
  byte pos = 4;   
    lcd.clear();
    lcd.blink();
      byte KEY;                     // читаем состояние кнопок
      while(1)                      // крутим   цикл  
    {                          
    lcd.setCursor(0, 1);
    lcd.print(" *Set to save!* ");
    
    lcd.setCursor(1, 0);     // выводим инфу
    lcd.print("L=");
      if (settempOn < 10) lcd.print("0");
    lcd.print(settempOn);
    lcd.print("*C");
   
    lcd.setCursor(9, 0);
    lcd.print("H=");
     if (settempOff < 10) lcd.print("0");
    lcd.print(settempOff);
    lcd.print("*C");
    
    lcd.setCursor(pos, 0);                       // устанавливаем курсор согласно позиции

    while ((KEY=key()) == 0);                   //жду нажатия кнопки
    if (KEY == 1) break;
    
    if (KEY == 5 && pos < 12) pos += 8;           // крутим позицию
    else if (KEY == 2 && pos > 4) pos -= 8; 
    
    else if (pos == 4 && KEY == 3) settempOn++;   // крутим значения
    else if (pos == 4 && KEY == 4) settempOn--;
    else if (pos == 12 && KEY == 3) settempOff++;
    else if (pos == 12 && KEY == 4) settempOff--;    
          
    if (settempOn > 40) settempOn = 0;            // устанавливаем макс. значения переменной температуры
    else if (settempOff > 40) settempOff = 0;
        
    }  // конец цикла
    
    lcd.noBlink(); 
    lcd.clear();

    EEPROM.write(44, settempOn);    // Зашиваем значение On в память
    EEPROM.write(45, settempOff);   // Зашиваем значение Off в память
   
    lcd.print("    -SAVING-  ");
    delay(1000);
    } 

//*********************************************************************************//
//***************** Цикл установки мощности MIN & MAX вентилятора *****************//
//*********************************************************************************//

  void setPower_Fan(){      
  byte pos = 5;   
  lcd.clear();
  lcd.blink();
  byte KEY; 
  while(1)                         // крутим   цикл   
  {
    lcd.setCursor(0, 1);
    lcd.print(" *Set to save!* ");
    
    lcd.setCursor(0, 0);     // выводим инфу
    lcd.print("MAX=");
    if (FANPWM_MAX < 10) lcd.print("0");
    if (FANPWM_MAX < 100) lcd.print("0");
    lcd.print(FANPWM_MAX);
   
    lcd.setCursor(9, 0);
    lcd.print("MIN=");
    if (FANPWM_MIN < 10) lcd.print("0");
    if (FANPWM_MIN < 100) lcd.print("0");
    lcd.print(FANPWM_MIN);
    
    lcd.setCursor(pos, 0);                       // устанавливаем курсор согласно позиции

    while ((KEY=key()) == 0);//жду нажатия кнопки
    if (KEY == 1) break;

    if (KEY == 5 && pos < 14) pos += 9;           // крутим позицию
    else if (KEY == 2 && pos > 5) pos -= 9; 
    
    else if (pos == 5 && KEY == 3) FANPWM_MAX++;   // крутим значения
    else if (pos == 5 && KEY == 4) FANPWM_MAX--;
    else if (pos == 14 && KEY == 3) FANPWM_MIN++;
    else if (pos == 14 && KEY == 4) FANPWM_MIN--;    
          
    if (FANPWM_MAX > 255) FANPWM_MAX = 0;            // устанавливаем макс. значения переменной температуры
    else if (FANPWM_MIN > 255) FANPWM_MIN = 0;
        
  }  // конец цикла
    
  lcd.noBlink(); 
  lcd.clear();

  EEPROM.write(46, FANPWM_MAX);    // Зашиваем значение MAX в память
  EEPROM.write(47, FANPWM_MIN);    // Зашиваем значение MIN в память
   
  lcd.print("    -SAVING-  ");
  delay(1000);
} 
 
  ///////////- Главное меню -/////////////
void menu(){
  lcd.clear();
  char menuTxt[][20] = {"Menu-1      >>", "Menu-2      >>"};
  byte pos = 0;
  
    byte KEY;
    while((KEY=key()) != 1){
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 1) pos++;
       
    if (KEY == 5 && pos == 0) Submenu1();
    else if (KEY == 5 && pos == 1) SubmenuFan();   
  }
  lcd.clear();
  lcd.print("     -EXIT-   ");
  delay(500);
 } 

  void SubmenuFan(){    // Охлаждение //
  lcd.clear();
  char menuTxt[][20] = {"SET TEMPER. >>", "SET POWER   >>"};
  byte pos = 0;
  
    byte KEY;                 // читаем состояние кнопок
    while((KEY=key()) != 1){                         // крутим   цикл                                       
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 1) pos++;
    
         if (KEY == 5 && pos == 0) SetFanOnOff();
    else if (KEY == 5 && pos == 1) setPower_Fan();  
  }
  lcd.clear();
  lcd.print("     -EXIT-   ");
  delay(1000);
 }  
 
void setup(){
 lcd.begin(16, 2);  
 lcd.setCursor(2, 0);
 lcd.print("PROBA MENU 1");
 
 pinMode(Ledlcd, OUTPUT);
 brightnessLCD = EEPROM.read(2);             // Подсветка LCD //
 analogWrite(Ledlcd, brightnessLCD);
 analogWrite(FANPWM_PIN, FANPWM_MIN);        //Пишем в порт минимальное значение 

  settempOn = EEPROM.read(44);               // Охлаждение //
  settempOff = EEPROM.read(45); 
  FANPWM_MAX = EEPROM.read(46);
  FANPWM_MIN = EEPROM.read(47);
}

void loop()
{
  byte KEY=key();
  switch (KEY)
  {
  case 1: menu(); break;
  case 2: if (--ekran<0) ekran=2; break;
  case 3: brightnessLCD += 5; break;
  case 4: brightnessLCD -= 5; break;
  case 5: if (++ekran>2) ekran=0; break;
  default: break;
  }
  if (KEY==2 || KEY==5 || KEY==1)
  {
    lcd.setCursor(2, 0);
    switch (ekran)
    {
    case 0: lcd.print("PROBA MENU 1"); break;
    case 1: lcd.print("PROBA MENU 2"); break;
    case 2: lcd.print("PROBA MENU 3"); break;
    }
  }
  if (KEY==3 || KEY==4)
  {
    brightnessLCD = constrain(brightnessLCD, 0, 254);
    analogWrite(Ledlcd, brightnessLCD);    // Устанавливаем состояние яркости для светодиода 
    EEPROM.write(2, brightnessLCD); 
  }      
  }

 

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Sasha80 пишет:

Код нужно под себя будет заточить!

Тезка, прочитай как код убирать в спойлер. Там ничего сложного....

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Sasha80 пишет:

Код нужно под себя будет заточить!

Тезка, прочитай как код убирать в спойлер. Там ничего сложного....

skalinas
Offline
Зарегистрирован: 13.01.2016

Спасибо за код!

Опишите в краце структуру меню (схему переходов по меню).

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

http://arduino.ru/forum/proekty/antidrebezg-dlya-shilda-lcd-knopki Тут я попытался решить проблему для нашего шилда по дребезгу контактов.

Когда выбираем в меню изменение значения параметра, нет режима при удержании кнопки - автоматическое изменение параметра, очень удобная штука.

Еще можно русифицировать наш шилд (заглавными буквами по русски), если нужно могу скинуть код.

 

Sasha80
Offline
Зарегистрирован: 18.01.2016

Уважаемый Andy подправил код таким образом, чтоб кнопки реагировали на отпускание кнопки, насколько я понимаю в этом случае защита от дребезга не обязательна. Режима удержания кнопки действительно нет, может общими усилиями сможем добавить? За русифицированный код буду признателен, там библиотека нужна специальная, или кодом все правиться? 

Структура меню простая: По нажатию селект попадаем в основное меню, выбираем настройку параметров какой то группы, попадаем в настройку индивидуальных параметров в группе. Например В основном меню настройка света и температуры, в подменю света настройки времени включения/выключения, яркости и цветовой температуры. В подменю температуры настраиваем срабатывание реле по определенным параметрам датчика температуры (температурный коридор). Вентиляци. И Т.Д. Ну и все ради чего это заморачивалось выход из меню без перезагрузки ардуинки!

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Sasha80 пишет:

Спасибо добрый человек! Всавил ваш кусочек для кнопок, изменил 81-ю строку на "while(key() != 1){"

но выходит в главные экраны тоько если следуйщую строку "delay(200);" закомментировать, но при этом остальные переходы не пашут. Пожалуйста, помогите еще чуть чуть!

Разбирайся....

                                                             // подключение библиотек
#include <TM1637.h>// индикатор 4 секции 7сегментов
#include <OneWire.h>// считка ТМ ключей 
#include <EEPROM.h>// работа с паматью
#include <pitches.h>// библа на звуки

// назначение пинов
#define TMread 2//TM key pin
#define LEDclk 3//LED 1637 pin CLK
#define LEDdio 4//LED 1637 pin DIO

#define SoundPin 9//Звук в динамик

#define pinKBx1 6 // 1 столбец кнопок
#define pinKBx2 7 // 2 столбец кнопок
#define pinKBx3 8 // 3 столбец кнопок
#define pinKBy1 14 // 1 строка кнопок
#define pinKBy2 15 // 2 строка кнопок
#define pinKBy3 16 // 3 строка кнопок
#define pinKBy4 17 // 4 строка кнопок
//   x1  x2  x3
//y1  1   2   3
//y2  4   5   6
//y3  7   8   9
//y4  A   B   C

const int melody[] = 
{
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
const int noteDurations[] = 
{
  4, 8, 8, 4, 4, 4, 4, 4
};

const long int TimeXX=60000;//делитель миллисекунд
int  TimeCH=15; //минуты для ЧЕМОДАНА
byte Seg_ON=0; //двоеточие на индикаторе
byte TMbuffer[8];// буфер приема
byte TMlistKEY[20][8];// 5 ключей админских и 15 игровых ключей
byte PrevCMD=0;// Предыдущая команда
byte NextCMD=0;// следующая команда
byte ChCMD=0;// буфер считывания команды
byte SetMode=0;// режим - 0 не установлен, 1 кнопки, 2 ключи
byte SetTimerMode=1;// режим - 0 таймер выключен, 1 таймер включен
unsigned long buffMillis=0;// буфер для расчетов
unsigned long PrevMillis=0;// предыдущее время в миилсах
unsigned long NextMillis=0;// следующее время в миилсах
unsigned long CMDmillis[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};// следующее время в миилсах

byte buffTM[8];// буфер приема ТМ-ключей

byte ChemodanKey[4]={0,0,0,0};

TM1637 tm1637(LEDclk,LEDdio);
OneWire ds(TMread); // выход считывателя на пин TMread

void setup() // стартовая инициализация
{
                      //Serial.begin(9600); //для отладки
                      //Serial.println("Start..."); //для отладки

    SoundSET();
    SirenaOUT();
    /* Инициализация структур */    
    pinMode(pinKBx1, INPUT);           // назначить порт ввода X1
    digitalWrite(pinKBx1, HIGH);       // включить подтягивающий резистор
    pinMode(pinKBx2, INPUT);           // назначить порт ввода X2
    digitalWrite(pinKBx2, HIGH);       // включить подтягивающий резистор
    pinMode(pinKBx3, INPUT);           // назначить порт ввода X3
    digitalWrite(pinKBx3, HIGH);       // включить подтягивающий резистор
    pinMode(pinKBy1, OUTPUT);          // назначить порт вывода Y1
    pinMode(pinKBy2, OUTPUT);          // назначить порт вывода Y2
    pinMode(pinKBy3, OUTPUT);          // назначить порт вывода Y3
    pinMode(pinKBy4, OUTPUT);          // назначить порт вывода Y4

    tm1637.init();
    tm1637.set(5);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
    tm1637.display(0,0); //в левом сегменте 0 остальные потушены

    // Читаем с хранилища ключи - 20 шт 5 админских 0-4 и 15 игровых 5-20
    for(byte TM1  = 0; TM1 < 20; TM1++)
    {
      for(byte TM2 = 0; TM2 < 8; TM2++)
      {
          TMlistKEY[TM1][TM2]=EEPROM.read(TM1*8+TM2);
      }
    }
}

void loop() //Основной цикл
{
//StartMODE3();//*********************************************************************************
    
    PrevMillis=millis();//запоминаем первый миллс
    while(1){
      byte buff=0;
      if (SetMode==3)//если режим ЧЕМОДАН
      {
        StartMODE3();
      }
      if (SetMode>0&&NextCMD>0&&PrevCMD>0)//если режим установлен в 1 или 2. Если 0 - пропускаем
      {
        buffMillis=CMDmillis[NextCMD];//вносим в буфер 
        NextMillis=millis();//читаем миллсы
        if(SetTimerMode)
        {
          CMDmillis[NextCMD]+=NextMillis-PrevMillis;//добавляем миллсы в счетчик команды
        }

        PrevMillis=NextMillis;//запоминаем время
        if (buffMillis/TimeXX!=CMDmillis[NextCMD]/TimeXX)//если число минут предыдущей записи отличается от минут текущих - выводим на экран
        {
          buffMillis=CMDmillis[NextCMD]/TimeXX;
          TimeDisplay(NextCMD,buffMillis);
        }
      }    
      // чтение ТМ-ключа
     if(ds.reset()) // если обнаружено устройттво
     {
        ds.write(0x33); // отправляем команду "считать ROM" 
        delay(10); // на всякий случай ждем
        for(int i=0;i<8;i++)
        {
           buffTM[i] = ds.read(); // считываем ключ
        }
        //проверяем ключ админа
        buff=ScanTM();//проверяем ключ в базе
        if(buff)
        {
          if(buff<6)  {AdminMode();}//если админский ключ идем в режим администрирования
          if(buff>5)//если есть номер команды
          {
            if (!SetMode||ChCMD)//режим не установлен - режим ключей 2
            {
              SetMode=2;
              PrevMillis=millis();
              ChCMD=0;
            }
            if(SetMode==2)//если режим ключей 2 запоминаем номер ключа команды
            {
              NextCMD=buff-5;
            }
          }
        }
     }

      // Чтение кнопок
      delay(500);
      buff=KBDread();//проверяем нажатие кнопок
      if (buff)//если нажата любая кнопка
      {
        if (!SetMode||ChCMD)//режим не установлен - режим кнопок 1
        {
          SetMode=1;
          PrevMillis=millis();
          ChCMD=0;
        }
        if(SetMode==1)//если режим кнопок 1 запоминаем номер кнопки - команды
        {
          NextCMD=buff;
        }
      }
      if (NextCMD!=PrevCMD)//если команда изменилась
      {
        PrevCMD=NextCMD;//запоминаем номер новой команды
        buffMillis=CMDmillis[NextCMD]/TimeXX;
        TimeDisplay(NextCMD,buffMillis);
      }
    delay(200);
    }
}

byte KBDread()//опрос клавиатуры
{
      byte KBread=0;
      byte KBx;
      byte KBy;
      for (KBx=0;KBx<3;KBx++)//цикл по столбцам
      {
        for (KBy=0;KBy<4;KBy++)//цикл по строкам
        {
          digitalWrite(pinKBy1+KBy, LOW);// 0 на столбец
          if (!digitalRead(pinKBx1+KBx))//читаем строку
          {
            KBread=KBy*3+KBx+1;//если 0 определяем кнопку
          }
          digitalWrite(pinKBy1+KBy, HIGH);//1 на столбец
        }
      }
    return KBread;//возвращаем 0 или номер кнопки 1-12
}

void AdminMode(void)
// 1 - чтение ключей из базы, 12 - выход
// 2 - стоп таймера
// 3 - старт таймера если он был включен
// 4 - управление ключами команд, 5 - запись и сл номер, 10 - стирание, 12 - выход, 2с задержка на переключениеключа
// 5 - запись ключа и сл номер
// 6 - запись ключей админов, 5 - запись и сл номер, 10 - стиранние, 12 - выход, 2с задержка на переключениеключа
// 7 - чтение времени команд, 12 - выход, 7 - следующая, 2с задержка на переключениеключа
// 8 - ВКЛ/ВЫКЛ свет ?????
// 9 - моргание света ?????
// 10 (А) - режим КНОПКИ
// 11 (В) - режим КЛЮЧИ
// 12 (С) - режим ЧЕМОДАН/ВЫХОД
{
    byte KeySave=0;
    byte numTM=0;
    byte buff=0;
    byte buffZ=0;
    byte buff1=0;
    byte Rkbd=0;
    tm1637.clearDisplay();
    tm1637.display(0,10); //выводим на дисплей A        
    do{ 
      buff=KBDread();  
      if (buff){tm1637.display(1,buff);}
      delay(200);
      switch(buff){
        case 1://чтение ключей по командам, кнопка 12 выход
          KeySave=1;
          buff1=1;
          do
          {
            if(ds.reset()) // если обнаружено устройттво
            {
              ds.write(0x33); // отправляем команду "считать ROM" 
              delay(10); // на всякий случай ждем
              for(int i=0;i<8;i++)
              {
                buffTM[i] = ds.read(); // считываем ключ
              }
            }
            buffZ=ScanTM();
            if(buffZ>5){tm1637.display(2,12);tm1637.display(3,buffZ-5);}//пользовательский ключ, выводим С*
            if(buffZ>0&&buffZ<6){tm1637.display(2,10);tm1637.display(3,buffZ);}//админский ключ, выводим А*
            if(!buffZ){tm1637.display(2,0);tm1637.display(3,0);}//админский ключ, выводим А*
            delay(1000);
            if(KBDread()==12){buff1=0;}
          }while(buff1);
          KeySave=0;
        break;
        case 2://стоп таймера
          SetTimerMode=0;
        break;
        case 3://старт таймера
          SetTimerMode=1;
        break;
        case 4://запись/стирание ключей команд, 5- запись, 10-стирание, 12 - выход
          KeySave=1;
          numTM=6;
          Rkbd=0;
          buffTM[0]=255;
          do{
            buffZ=0;
            tm1637.display(2,0);
            tm1637.display(3,numTM-5);
            if(ds.reset())// если обнаружено устройттво
            { 
              ds.write(0x33); // отправляем команду "считать ROM" 
              delay(10); // на всякий случай ждем
              for(int i=0;i<8;i++)
              {
                buffTM[i] = ds.read(); // считываем ключ
              }
            }else
            {
              for(int i=0;i<8;i++)
              {
                buffTM[i] = 255; // стираем прошлый ключ в памяти
              }
              tm1637.display(2,0);tm1637.display(3,0);
             }
            buffZ=ScanTM();
            if(buffZ>5){tm1637.display(2,12);tm1637.display(3,buffZ-5);}//пользовательский ключ, выводим С*
            if(buffZ>0&&buffZ<6){tm1637.display(2,10);tm1637.display(3,buffZ);}//админский ключ, выводим А*
            Rkbd=KBDread();
            if(!buffZ)//если ключ не найден в базе
            {
              tm1637.clearDisplay();
              tm1637.display(0,10);
              tm1637.display(1,4);
              tm1637.display(3,numTM-5);
              if(Rkbd==5)//если кнопка 5 записываем ключ
              {
                if(buffTM[0]!=255)
                {
                  for(int i = 0; i < 8; i++)
                  {
                    EEPROM.write((numTM-1)*8+i,buffTM[i]);
                    TMlistKEY[numTM-1][i]=buffTM[i];
                  }
                  buffTM[0]=255;
                  numTM++;
                }else
                {
                  numTM++;
                }
                tm1637.display(2,5);
                tm1637.display(3,numTM-5);//пользовательский ключ, выводим S*
              }
            }
            if(Rkbd==10)//если нажата кнопка 10
            {
              EEPROM.write((numTM-1)*8,255);//стираем ключ
              TMlistKEY[numTM-1][0]=255;
              tm1637.display(2,12);
              tm1637.display(3,numTM-5);//выводим подтверждение стирания ключа С*
            }
            delay(1000);
          if(Rkbd==12){numTM=99;}//если нажата кнопка 12 выход
          }while(numTM<21);
          KeySave=0;
        break;
        // 5 - подтверждение записи и сл номер, 10 - стиранпие записи 12 выход
        case 6://запись/стирание ключей админа, 5 - запись и сл номер, 10 - стирание 12 выход
          KeySave=1;
          numTM=1;
          Rkbd=0;

          do{
            buffZ=0;
            tm1637.display(2,0);
            tm1637.display(3,numTM-1);
            if(ds.reset())// если обнаружено устройттво
            { 
              ds.write(0x33); // отправляем команду "считать ROM" 
              delay(10); // на всякий случай ждем
              for(int i=0;i<8;i++)
              {
                buffTM[i] = ds.read(); // считываем ключ
              }
            }else
            {
              for(int i=0;i<8;i++)
              {
                buffTM[i] = 255; //стираем прошлый  ключ в памяти
              }
              tm1637.display(2,0);tm1637.display(3,0);
             }
            buffZ=ScanTM();
            if(buffZ>5){tm1637.display(2,12);tm1637.display(3,buffZ-5);}//пользовательский ключ, выводим С*
            if(buffZ>0&&buffZ<6){tm1637.display(2,10);tm1637.display(3,buffZ);}//админский ключ, выводим А*
            Rkbd=KBDread();
            if(!buffZ)//если ключ не найден в базе
            {
              tm1637.clearDisplay();
              tm1637.display(0,10);
              tm1637.display(1,6);
              tm1637.display(3,numTM);
              if(Rkbd==5)//если кнопка 5 записываем ключ
              {
                if (buffTM[0]!=255)
                {
                  for(int i = 0; i < 8; i++)
                  {
                    EEPROM.write((numTM-1)*8+i,buffTM[i]);
                    TMlistKEY[numTM-1][i]=buffTM[i];
                  }
                  buffTM[0]=255;
                  numTM++;
                }else
                {
                  numTM++;
                }
                tm1637.display(2,5);
                tm1637.display(3,numTM);//flvbycrbq ключ, выводим S*
              }
            }
            if(Rkbd==10&&numTM>1)//если нажата кнопка 10 и ключ более 1
            {
              EEPROM.write((numTM-1)*8,255);//стираем ключ
              TMlistKEY[numTM-1][0]=255;
              tm1637.display(2,10);
              tm1637.display(3,numTM);//выводим подтверждение стирания ключа С*
            }
            delay(1000);
          if(Rkbd==12)
          {
            numTM=99;
          }//если нажата кнопка 12 выход
          }while(numTM<21);
          KeySave=0;
        break;
        case 7://чтение времени по командам 5 переключение команд 12 выход
          KeySave=1;
          numTM=1;
          Rkbd=0;
          buffMillis=CMDmillis[numTM]/TimeXX;
          TimeDisplay(numTM,buffMillis);          
          while(numTM<16)
          {
            Rkbd=KBDread();
            if(Rkbd==5)//если нажата кнопка 10 и ключ более 1
            {
              numTM++;
              buffMillis=CMDmillis[numTM]/TimeXX;
              TimeDisplay(numTM,buffMillis);          
            }
            delay(1000);
            if(Rkbd==12)
            {
              numTM=99;
            }//если нажата кнопка 12 выход
          }
          KeySave=0;        
        break;        
        case 8://свет ВКЛ/ВЫКЛ

        break;
        case 9://свет ВКЛ моргание

        break;
        case 10://режим КНОПКИ
          SetMode=1;
          ChCMD=1;
          tm1637.display(2,5);
          tm1637.display(3,1);//S1 режим кнопок
        break;
        case 11://режим КЛЮЧИ
          SetMode=2;
          tm1637.display(2,5);
          tm1637.display(3,2);//S2 режим ключей
        break;
        case 12://Режим ЧЕМОДАН
          SetMode=3;
          tm1637.display(2,11);
          tm1637.display(3,3);//S3 режим ЧЕМОДАН
        break;
      }
      delay(200);
    }while(ds.reset()||KeySave);
    delay(200);
    tm1637.clearDisplay();
    tm1637.display(0,0);
    if(!NextCMD)
    {
      PrevMillis=millis();//запоминаем первый миллс
    }
}

void StartMODE3(void)// режим ЧЕМОДАН
{
//при старте выбираем время блокировки
//на экране bd (block delay) в пятиминутках
//выбор на кнопках от 1 до 12 по 5 минут == от 5 до 60 минут
//затем инициализация датчика случайных чисел SE
//генерируется 4 цифры кода, выводятся на экран на 2 сек
//если нажата неправильная цифра - блокировка на время bd минут и сирена
//если все цифры угаданы - звук и переход на новую игру
//если найден ключ ТМ - сбрасываем все включая звук, найденные ключи
//если с ключем ТМ наата любая кнопка - рестарт игры
  while(1)
  {
    byte EndGAME=0;
    byte i=1;
    byte j=0;
    byte buff=0;
    byte ChmNM=0;// цифра угадана
    byte numKey=0;// количество угаданных цифр
    byte ChemodanRead[4]={0,0,0,0};//буфер

    //инициализация параметров игры
    tm1637.clearDisplay();//на экран выводим bd
    tm1637.display(0,11);
    tm1637.display(1,13);
    buff=KBDread();
    do//ждем нажатие на кнопку
    {
      buff=KBDread();//читаем кнопки
      TimeCH=buff*5;//устанавливаем тайм-аут для ошибки набора *5 мин
      tm1637.display(3,buff);// выводим число 5-минуток тайм-аута
    }while(!buff);//ждем нажатие на кнопку
    delay(4000);
    tm1637.clearDisplay();//на экран выводим 5Е
    tm1637.display(0,5);
    tm1637.display(1,14);
    while(!KBDread())//ждем нажатие на кнопку
    {
      randomSeed(millis());//инициализируем счетчик рандома
      delay(200);
    }
    ChemodanKey[0]=random(1,13);//из списка 1-12 первая цифра
    while(i<4)//набираем 4 цифры
    {
      buff=random(1,13);//из списка 1-12 следующая цифра
      ChmNM=1;
      for(j=0;j<i;j++)
      {
        if(ChemodanKey[j]==buff)//Если цифра повторяется
        {
          ChmNM=0;//сбрасываем счетчик - идем на повтор
        }
      }
      if (ChmNM)//если цифра новая - запоминаем, ищем следующую
      {
        ChemodanKey[i]=buff;
        i++;
      }
    }
    ChmNM=0;
    for (i=0;i<4;i++)
    {
      tm1637.display(i,ChemodanKey[i]);//выводим установленные цифры
                        Serial.print(ChemodanKey[i],HEX); //для отладки
    }
                        Serial.println(); //для отладки
    SirenaOUT;//мявкаем в динамик
    delay(2000);

    tm1637.clearDisplay();//стираем все
    tm1637.display(0,0);//на экран 0
    numKey=0;
    while(!EndGAME)//пока EndGAME==0 крутим цикл
    {
      if(ds.reset()) // если обнаружен ключ сбрасываем все в 0
      {
            for(i=0;i<=numKey;i++)
            {
              ChemodanRead[i]=0;//сбросили хранилище угаданных ключей
            }
            ChmNM=0;//изменили статус на 0
            numKey=0;//число угаданных 0
            tm1637.clearDisplay();//стираем все
            tm1637.display(0,0);//на экран 0
            if (KBDread())//если нажата кнопка стартуем новую игру
            {
              EndGAME=1;
            }
      }
      buff=KBDread();//читаем клавиатуру
      if(buff)//если кнопка нажата
      {
        ChmNM=0;
        for(i=0;i<4;i++)// проверяем цифру
        {
          if(buff==ChemodanKey[i])//если цифра есть в коде
          {
            ChmNM=1;//изменили статус на 1
            ChemodanRead[numKey]=ChemodanKey[i];//запомнили угаданную цифру
            SirenaOUT();//мявкнули в динамик
            tm1637.display(numKey,ChemodanRead[numKey]);//вывели на экран угаданную цифру
          }
        }
        if(!ChmNM)//если не угадали
        {
            for(i=0;i<=numKey;i++)
            {
              ChemodanRead[i]=0;//сбросили хранилище угаданных ключей
            }
            ChmNM=0;//изменили статус на 0
            numKey=0;//число угаданных 0
            tm1637.clearDisplay();//стираем все
            for(i=0;i<4;i++)
            {
              tm1637.display(i,0);//на экран 0
            }
                        Serial.println(" ERROR "); //для отладки
            PrevMillis=millis();//запоминаем первый миллс
            while(millis()-PrevMillis<TimeCH*TimeXX)//в течении ХХ минут ревем сиреной
            {
              SirenaOUT();//сирена
              delay(1000);
                        Serial.println(" ERROR 1"); //для отладки

            if(ds.reset()) // если обнаружен ключ сбрасываем все в 0
            {
              for(i=0;i<=numKey;i++)
              {
                ChemodanRead[i]=0;//сбросили хранилище угаданных ключей
              }
              PrevMillis=TimeCH*TimeXX+millis();
              ChmNM=0;//изменили статус на 0
              numKey=0;//число угаданных 0
              tm1637.clearDisplay();//стираем все
              tm1637.display(0,0);//на экран 0
              if (KBDread())//если нажата кнопка стартуем новую игру
              {
                EndGAME=1;
              }
            }
          }
          tm1637.clearDisplay();//стираем все
          tm1637.display(0,0);//на экран 0
        }else
        {
          numKey++;//если угадали - следующий номер
          delay(1000);
        }
      }
      if(numKey>3)//если угадали все 4 - гимн
      {
        SirenaOUT();
        SirenaOUT();
        SirenaOUT();
        EndGAME=1;
      }
    }
  }
}
void TimeDisplay (byte Ncmd, unsigned long buffTime)//Вывод на дисплей - 1 цифра номер команды, 2-4 - число минут текущей команды
{
  tm1637.display(0,Ncmd); //выводим на дисплей 1 цифру - команда
  tm1637.display(1,buffTime/100);//выводим на дисплей 1 цифру - сотни минут
  tm1637.display(2,buffTime%100/10);//выводим на дисплей 1 цифру - десятки минут
  tm1637.display(3,buffTime%10);//выводим на дисплей 1 цифру - минуты
  if(buffTime>999)
  {
    Seg_ON=1;
  }else
  {
    Seg_ON=0;
  }
  tm1637.point(Seg_ON);//вкл двоеточие между сегментами если минут больше 999
}

byte ScanTM(void)//проверка ключей ТМ на наличие в хранилище
{
  byte buff2=0;
  byte buff1=1;
  for(int y=0;y<20;y++)
  {
    if(TMlistKEY[y][0]!=255)//Если 1й байт ключа FF - ячейка пустая, пропускаем
    {
      buff1=1;
      for(int i=0;i<8;i++)
      {
        if(buffTM[i]!=TMlistKEY[y][i]){buff1=0;}  // сравниваем ключ с базой
      }
      if (buff1){buff2=y+1;}
    }
  }
  return buff2; //Возвращаем номер ключа или 0 если не найден
}

void SoundSET(void)
{
/*********************************************************
    //вывод звука
    for (int thisNote = 0; thisNote < 8; thisNote++) 
    {
      // to calculate the note duration, take one second divided by the note type.
      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
      int noteDuration = 1000 / noteDurations[thisNote];
      tone(SoundPin, melody[thisNote], noteDuration);
      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      // stop the tone playing:
      noTone(SoundPin);
    }
*********************************************************/
}

void SirenaOUT(void)
{
/*********************************************************
  //Сирена
  byte Dlit = 17;
  int Niz = 500;
  int Verh = 3000;
  byte Shag = 70;
    for (int j = Niz;j<= Verh;j+=Shag)
    {
      tone(SoundPin,j, Dlit);    
      delay(Dlit);                   
    }
    for (int j = Verh;j>= Niz;j-=Shag)
    {
      tone(SoundPin,j, Dlit);    
      delay(Dlit);                   
    }
***********************************************************/
}

Меню реализовано в функции AdminMode

skalinas
Offline
Зарегистрирован: 13.01.2016

Подправил ваш код, добавил РУССКИЙ. Нашел код на просторах инета, суть такая, используются заглавные английские буквы и генерируются недостающие заглавные РУССКИЕ. Перед выводом на экран русского текста указываются недостающие символы, но не более 8 символов. Коряво конечно, но работает. Искал библиотеки русификаторы, ни одна на китайских LCD не работает. Не получилось все перевести, так как используется у вас в коде char menuTxt[][20], как в него впихнуть русские буквы, пока не разобрался.

И еще, почему то у вас 3 основных меню, у каждого 2 подменю, не совсем понял функции основных меню.

По поводу дребезга, дребезг у меня проскакивает и очень сильно на шилде с «плохими» кнопками вообще беда.

Давал ранее ссылку на свой код по антидребезгу, там таких проблем нет и там реализована прокрутка по удержанию кнопки. Если долго нажимать Селект (более 5 секунд) тоже идет срабатывание кнопки. Реализовывал для перехода в режим калибровки датчиков. Все возможности кнопок можно посмотреть на LCD.

#include <EEPROM.h>
#include <LiquidCrystal.h> //lcd lib

LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );

#define FANPWM_PIN 11                //Пин порта, где будет ШИМ Охлаждения

int Ledlcd = 10;                     //Номер Pin к которому подключена подсветка LCD
int brightnessLCD =0;                //Переменная в которой хранится уровень яркости LCD (От 0 до 254) 
int ekran=0;

unsigned long time;

 float tempe = 0; 
 byte settempOn;
 byte settempOff;
 byte FANPWM_MAX;
 byte FANPWM_MIN;    
 
 byte key(){                          
 int val = analogRead(0);
 byte bt;
   if (val < 50) bt = 5;         // кнопка назад
   else if (val < 150) bt = 3;   // кнопка вверх
   else if (val < 350) bt = 4;   // Кнопка вниз
   else if (val < 550) bt = 2;   // кнопка вперед
   else if (val < 800) bt = 1;   // кнопка входа в меню
   else return 0;
   while (analogRead(0) < 800);  // ждать пока кнопка не отпустится
   return bt;  
  }
////////////////////////////////////////////////////////////////////
// инициализировать дисплей
// третья строка, содержит необходимые русские буквы от "БГДЖЗИЙЛПУФЦЧШЩЬЪЫЭЮЯ" до 21 букв,
// но одновременно рекомендуется использовать не более 8 букв на дисплее, получилось использовать весь набор из 21 буквы
////////////////////////////////////////////////////////////////////
 static byte addon_letters[16];
 void init_rus(const char* letters_use )
{
  // пользовательские символы
  static byte letters[][8]   = {
	{ B11111, B10000, B10000, B11111, B10001, B10001, B11111, B00000 },//Б
	{ B11111, B10000, B10000, B10000, B10000, B10000, B10000, B00000 },//Г
	{ B01111, B01001, B01001, B01001, B01001, B11111, B10001, B00000 },//Д
	{ B10101, B10101, B10101, B01110, B10101, B10101, B10101, B00000 },//Ж
	{ B01110, B10001, B00001, B00110, B00001, B10001, B01110, B00000 },//З
	{ B10001, B10001, B10011, B10101, B11001, B10001, B10001, B00000 },//И
	{ B10101, B10101, B10011, B10101, B11001, B10001, B10001, B00000 },//Й
	{ B00111, B01001, B10001, B10001, B10001, B10001, B10001, B00000 },//Л
	{ B11111, B10001, B10001, B10001, B10001, B10001, B10001, B00000 },//П
	{ B10001, B10001, B10001, B01111, B00001, B10001, B01110, B00000 },//У
	{ B01110, B10101, B10101, B10101, B01110, B00100, B00100, B00000 },//Ф
	{ B10001, B10001, B10001, B10001, B10001, B10001, B11111, B00001 },//Ц
	{ B10001, B10001, B10001, B01111, B00001, B00001, B00001, B00000 },//Ч
	{ B10101, B10101, B10101, B10101, B10101, B10101, B11111, B00000 },//Ш
	{ B10101, B10101, B10101, B10101, B10101, B10101, B11111, B00001 },//Щ
	{ B10000, B10000, B10000, B11110, B10001, B10001, B11110, B00000 },//Ь
	{ B11000, B01000, B01110, B01001, B01001, B01001, B01110, B00000 },//Ъ
	{ B10001, B10001, B10001, B11101, B10101, B10101, B11101, B00000 },//Ы
	{ B11110, B00001, B00001, B01111, B00001, B00001, B11110, B00000 },//Э
	{ B10111, B10101, B10101, B11101, B10101, B10101, B10111, B00000 },//Ю
	{ B01111, B10001, B10001, B01111, B10001, B10001, B10001, B00000 },//Я
  };
  static char chars[] = {'Б','Г','Д','Ж','З','И','Й','Л','П','У','Ф','Ц','Ч','Ш','Щ','Ь','Ъ','Ы','Э','Ю','Я'};
  static byte empty[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  int index = 0, cl = sizeof(chars)/sizeof(char),i,j,symb;
  memset(addon_letters,0,sizeof(addon_letters));
  for( j = 0; j < strlen(letters_use) && j < 21; j++ )
    lcd.createChar(j, empty);
  for( j = 0; j < strlen(letters_use) && j < 21; j++ )
  {
    symb = -1;
    for( i=0; i < cl; i++ ) if( chars[i] == letters_use[j] ) { symb = i; addon_letters[index] = letters_use[j]; break; }  
    if( symb != -1 ) { lcd.createChar(index, letters[symb]); index++; }
  }
}
////////////////////////////////////////////////////////////////////
// печать русских букв
////////////////////////////////////////////////////////////////////
void print_rus(char *str) {
  static char rus_letters[] = {'А','В','Е','Ё','К','М','Н','О','Р','С','Т','Х'};
  static char trans_letters[] = {'A','B','E','E','K','M','H','O','P','C','T','X'};
  int lcount = sizeof(rus_letters)/sizeof(char), i, j;
  for( i=0; i<strlen(str); i++ )
  { 
	if( byte(str[i]) == 208 ) continue; // 208 игнорировать
	int found = 0;
	for(j=0; j < 16; j++) if( addon_letters[j] != 0 && byte(str[i]) == byte(addon_letters[j]) ) { lcd.write(j); found = 1; break; }
	if(!found) for(j=0; j < lcount; j++) if( byte(str[i]) == byte(rus_letters[j]) ) { lcd.write(trans_letters[j]); found = 1; break; }
	if(!found) lcd.write(byte(str[i]));
  }  
}
void print_rus(int x, int y, char *str) {
  lcd.setCursor(x, y);
  print_rus(str);
}
////////////////////////////////////////////////////////////////////
 
 ////////// - цикл 1 - /////////////
 
  void Submenu1(){            
  lcd.clear();
  init_rus("ПМЖЛ");
  char menuTxt[][20] = {"SET SUNRISE >>", "SET SUNSET  >>", "SET POWER   >>"};
  byte pos = 0;
  
  byte KEY;
  while((KEY=key()) != 1){  
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 2) pos++;
    
         if (KEY == 5 && pos == 0) ;
    else if (KEY == 5 && pos == 1) ;
    else if (KEY == 5 && pos == 2) ;
  }
  lcd.clear();
  init_rus("ВЫХД");
  print_rus(0,0,"     -ВЫХОД-   ");
  delay(500);
 }  
 
//**********************************************************************************//
//********************цикл установки границ температурного коридора*****************//
//**********************************************************************************//
 
  void SetFanOnOff(){      
  byte pos = 4;   
    lcd.clear();
    lcd.blink();
      byte KEY;                     // читаем состояние кнопок
      while(1)                      // крутим   цикл  
    {                          
    //lcd.setCursor(0, 1);
    init_rus("ЗДЬХИ");
    print_rus(0,1,"ЗАДАТЬ,СОХРАНИТЬ");
    
    lcd.setCursor(1, 0);     // выводим инфу
    lcd.print("L=");
      if (settempOn < 10) lcd.print("0");
    lcd.print(settempOn);
    lcd.print("*C");
   
    lcd.setCursor(9, 0);
    lcd.print("H=");
     if (settempOff < 10) lcd.print("0");
    lcd.print(settempOff);
    lcd.print("*C");
    
    lcd.setCursor(pos, 0);                       // устанавливаем курсор согласно позиции

    while ((KEY=key()) == 0);                   //жду нажатия кнопки
    if (KEY == 1) break;
    
    if (KEY == 5 && pos < 12) pos += 8;           // крутим позицию
    else if (KEY == 2 && pos > 4) pos -= 8; 
    
    else if (pos == 4 && KEY == 3) settempOn++;   // крутим значения
    else if (pos == 4 && KEY == 4) settempOn--;
    else if (pos == 12 && KEY == 3) settempOff++;
    else if (pos == 12 && KEY == 4) settempOff--;    
          
    if (settempOn > 40) settempOn = 0;            // устанавливаем макс. значения переменной температуры
    else if (settempOff > 40) settempOff = 0;
        
    }  // конец цикла
    
    lcd.noBlink(); 
    lcd.clear();

    EEPROM.write(44, settempOn);    // Зашиваем значение On в память
    EEPROM.write(45, settempOff);   // Зашиваем значение Off в память
    
    init_rus("ХЯ");
    print_rus(0,0,"  -СОХРАНЯЕМ-  ");
    delay(1000);
    } 

//*********************************************************************************//
//***************** Цикл установки мощности MIN & MAX вентилятора *****************//
//*********************************************************************************//

  void setPower_Fan(){      
  byte pos = 5;   
  lcd.clear();
  lcd.blink();
  byte KEY; 
  while(1)                         // крутим   цикл   
  {
    //lcd.setCursor(0, 1);
    init_rus("ЗДЬХИ");
    print_rus(0,1,"ЗАДАТЬ,СОХРАНИТЬ");
    
    //lcd.setCursor(0, 0);     // выводим инфу
    init_rus("Х");
    print_rus(0,0,"МАХ=");
    if (FANPWM_MAX < 10) lcd.print("0");
    if (FANPWM_MAX < 100) lcd.print("0");
    lcd.print(FANPWM_MAX);
   
    //lcd.setCursor(9, 0);
    init_rus("И");
    print_rus(0,1,"МИН=");
    if (FANPWM_MIN < 10) lcd.print("0");
    if (FANPWM_MIN < 100) lcd.print("0");
    lcd.print(FANPWM_MIN);
    
    lcd.setCursor(pos, 0);                       // устанавливаем курсор согласно позиции

    while ((KEY=key()) == 0);//жду нажатия кнопки
    if (KEY == 1) break;

    if (KEY == 5 && pos < 14) pos += 9;           // крутим позицию
    else if (KEY == 2 && pos > 5) pos -= 9; 
    
    else if (pos == 5 && KEY == 3) FANPWM_MAX++;   // крутим значения
    else if (pos == 5 && KEY == 4) FANPWM_MAX--;
    else if (pos == 14 && KEY == 3) FANPWM_MIN++;
    else if (pos == 14 && KEY == 4) FANPWM_MIN--;    
          
    if (FANPWM_MAX > 255) FANPWM_MAX = 0;            // устанавливаем макс. значения переменной температуры
    else if (FANPWM_MIN > 255) FANPWM_MIN = 0;
        
  }  // конец цикла
    
  lcd.noBlink(); 
  lcd.clear();

  EEPROM.write(46, FANPWM_MAX);    // Зашиваем значение MAX в память
  EEPROM.write(47, FANPWM_MIN);    // Зашиваем значение MIN в память
  
   init_rus("ХЯ");
   print_rus(0,0,"  -СОХРАНЯЕМ-  ");
  delay(1000);
} 
 
  ///////////- Главное меню -/////////////
void menu(){
  lcd.clear();
  init_rus("ПМЖЛ");
  char menuTxt[][20] = {"Menu-1      >>", "Menu-2      >>"};
  byte pos = 0;
  
    byte KEY;
    while((KEY=key()) != 1){
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 1) pos++;
       
    if (KEY == 5 && pos == 0) Submenu1();
    else if (KEY == 5 && pos == 1) SubmenuFan();   
  }
  lcd.clear();
  init_rus("ВЫХД");
  print_rus(0,0,"     -ВЫХОД-   ");
  delay(500);
 } 

  void SubmenuFan(){    // Охлаждение //
  lcd.clear();
  init_rus("ПМЖЛ");
  char menuTxt[][20] = {"SET TEMPER. >>", "SET POWER   >>"};
  byte pos = 0;
  
    byte KEY;                 // читаем состояние кнопок
    while((KEY=key()) != 1){  // крутим   цикл                                       
    
    lcd.setCursor(0, 0);
    lcd.print(pos+1);
    lcd.print(".");
    lcd.print(menuTxt[pos]);
    
    if (KEY == 3 && pos != 0) pos--;
    else if (KEY == 4 && pos < 1) pos++;
    
         if (KEY == 5 && pos == 0) SetFanOnOff();
    else if (KEY == 5 && pos == 1) setPower_Fan();  
  }
  lcd.clear();
  init_rus("ВЫХД");
  print_rus(0,0,"     -ВЫХОД-   ");
  delay(1000);
 }  
 
void setup(){
 lcd.begin(16, 2);  
 //lcd.setCursor(2, 0);
 init_rus("ПКМЮ");
 print_rus(0,0,"ПРОВЕРКА МЕНЮ 1");
 
 pinMode(Ledlcd, OUTPUT);
 brightnessLCD = EEPROM.read(2);             // Подсветка LCD //
 analogWrite(Ledlcd, brightnessLCD);
 analogWrite(FANPWM_PIN, FANPWM_MIN);        //Пишем в порт минимальное значение 

  settempOn = EEPROM.read(44);               // Охлаждение //
  settempOff = EEPROM.read(45); 
  FANPWM_MAX = EEPROM.read(46);
  FANPWM_MIN = EEPROM.read(47);
}

void loop()
{
  byte KEY=key();
  switch (KEY)
  {
  case 1: menu(); break;
  case 2: if (--ekran<0) ekran=2; break;
  case 3: brightnessLCD += 5; break;
  case 4: brightnessLCD -= 5; break;
  case 5: if (++ekran>2) ekran=0; break;
  default: break;
  }
  if (KEY==2 || KEY==5 || KEY==1)
  {
    lcd.setCursor(2, 0);
    switch (ekran)
    {
    case 0: init_rus("ПКМЮ");print_rus(0,0,"ПРОВЕРКА МЕНЮ 1"); break;
    case 1: init_rus("ПКМЮ");print_rus(0,0,"ПРОВЕРКА МЕНЮ 2"); break;
    case 2: init_rus("ПКМЮ");print_rus(0,0,"ПРОВЕРКА МЕНЮ 3"); break;
    }
  }
  if (KEY==3 || KEY==4)
  {
    brightnessLCD = constrain(brightnessLCD, 0, 254);
    analogWrite(Ledlcd, brightnessLCD);    // Устанавливаем состояние яркости для светодиода 
    EEPROM.write(2, brightnessLCD); 
  }      
  }
releyshic
Offline
Зарегистрирован: 20.11.2015

Господа что вы никак switch не изучите! каша блин а не код

Sasha80
Offline
Зарегистрирован: 18.01.2016

releyshic пишет:

Господа что вы никак switch не изучите! каша блин а не код

 

Москва не сразу строилась! Доберемся и до switch. Спасибо за совет!

skalinas
Offline
Зарегистрирован: 13.01.2016

http://forum.amperka.ru/threads/Библиотека-для-создания-Меню-на-дисплеях.1815/

Тут как делать Меню, там нужно скачать библиотеку. Выкладываю правленный код под наш шилд. Осталось прикрутить антидребезг и русские буквы.

#include <MyMenu.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //инициализация дисплея

#define NUM_ITEMS 32 //количество пунктов в меню включая все заголовки всех подменю

MItm items[NUM_ITEMS] = {
  MItm("SHOPPING LIST",0,0), //этот пункт является заголовком подменю с индексом 0 (то есть главного меню)
  MItm("Fruits",1), //пункт главного меню, который при выборе переходит на подменю с индексом 1
  MItm("Veggies",2), //с индексом 2
  MItm("Other",3), //и с индексом 3 соответственно
  MItm("FRUITS LIST",1,0), //это подменю с индексом 1, а ноль - верхнее для него меню
  MItm("Apple",50), //подменю с индексом 50 нет, поэтому будет вызвана функция (ниже)
  MItm("Orange",60),
  MItm("Banana",70),
  MItm("Pear",80),
  MItm(" <<BACK",0), //вот так можно создавать кнопку "Назад"
  MItm("VEGGIES LIST",2,0), //подменю с индексом 2
  MItm("Tomato",90),
  MItm("Potato",100),
  MItm("Smth else",110),
  MItm(" <<BACK",0),
  MItm("Other",3,0),
  MItm("Meat",4),
  MItm("Fish",5),
  MItm(" <<BACK",0),
  MItm("MEAT",4,3), //здесь уже верхним меню является подменю с индексом 3
  MItm("Chicken",6),
  MItm("Bacon",7),
  MItm("Beef",8),
  MItm("SHOWFISH",5),
  MItm(" <<BACK",3),
  MItm(" <<MAIN",0),
  MItm("FISH",5,3),
  MItm("Clownfish",9),
  MItm("Shark",10),
  MItm("SHOW MEAT",4),
  MItm(" <<BACK",3),
  MItm(" <<MAIN",0)
};

Menu menu(items,NUM_ITEMS,&lcd,menuCallback); //так создается меню (подробнее ниже)

void setup() {            //настраиваем кнопки
  pinMode(0,INPUT);
    
  lcd.begin(16,2);         //запускаем экран
  
  menu.goMain();           //отображаем на экране главное меню
}

void loop() {
  if(analogRead(0) < 80){ //нажата кнопка "вперед" или "выбрать пункт"
    menu.goNext(); //функция переходит на новый уровень подменю или вызывает callback
    delay(100); 
  }
  if(analogRead(0) < 200){ //нажата кнопка "вверх"
    menu.goUp(); //функция перемещает курсор на один пункт вверх
    delay(100);  
  }
  if(analogRead(0) < 400){ //нажата кнопка "вниз"
    menu.goDown(); //функция перемещает курсор на один пункт вниз
    delay(100);  
  }
   if(analogRead(0) < 600){ //нажата кнопка "назад"
    menu.goBack(); //функция возвращает на предыдущий уровень меню
    delay(100);
  }
delay(100);
}
    
void menuCallback(int idx){
//эта функция будет вызвана, если подменю с индексом idx нет
//и нужно совершить действие, а не уходить на еще один уровень в меню

  if(idx < 10){ //если idx < 10 делаем одно
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("NO MEAT n FISH!");
    delay(1000);
  }else if(idx == 10){ //если выбран пункт "акула" делаем другое :)
    int i=16;
    while(i >= 0){
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("-^-^-^-^-^-^-^-^-^-^");
      lcd.setCursor(i,1);
      lcd.print("/l");
      delay(300);
      i--;
    }
  }else{ //иначе просто пишем что было выбрано
    lcd.clear();
    lcd.setCursor(3,0);
    lcd.print(String(idx)+" pressed");
    delay(1000);
  }
  menu.goLast(); //после некоторой паузы вот этой функцией возвращаемся на последнее показанное меню
}

 

Goodawel
Offline
Зарегистрирован: 05.11.2017

Здравствуйте! Люди добрые подскажите как в моём случае прописать выход из меню по кнопке select.


#include <DallasTemperature.h>

#include <DHT.h>

#include <EEPROM.h>
#include <OneWire.h>
#include <LiquidCrystal.h>

#define OUT1 2 // выходы для реле 
#define OUT2 3

#define DHTPIN 12     // what digital pin we're connected to

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)


DHT dht(DHTPIN, DHTTYPE);

byte tempOUT1, tempOUT2;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
OneWire  ds(11); // 11 вход датчика 18b20

byte gradus[8] = {
  0b00110,
  0b01001,
  0b01001,
  0b00110,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};


void erorr(){ // останавливает работу программы и сигнализирует ошибку
  digitalWrite(OUT1, LOW); // выключаем реле
  digitalWrite(OUT2, LOW);
    while(1){ // крутим бесконечный цикл
      digitalWrite(13, !digitalRead(13));
      delay(500);
    }  
}
////

byte key(){ //// для кнопок ЛСДшилда
  int val = analogRead(0);
    if (val < 50) return 5;
    else if (val < 150) return 3;
    else if (val < 350) return 4;
    else if (val < 500) return 2;
    else if (val < 800) return 1;
    else return 0;  
}
////

void setMenu(){ // установка температуры 
  byte pos;    
  //digitalWrite(OUT1, LOW); // выключаем реле
  //digitalWrite(OUT2, LOW);

  lcd.clear(); 
  lcd.setCursor(0, 0); // что нужно отрисовать один раз
  lcd.print("Garag: ");
  lcd.setCursor(0, 1);
  lcd.print("Kotel: ");
  lcd.setCursor(11, 1);
  lcd.print("|");
  lcd.blink();
  
  while(1){ // крутим бесконечный цикл      
    byte KEY = key(); // читаем состояние кнопок
    
    lcd.setCursor(6, 0); // выводим на экран
    lcd.print(tempOUT1);
    lcd.write(1);
    lcd.print("C  ");
    lcd.setCursor(6, 1);
    lcd.print(tempOUT2);    
    lcd.write(1);
    lcd.print("C  ");
    
     ////// обработка кнопок 
    if (pos == 0){  // если в первой позиции
      lcd.setCursor(5, 0); // устанавливаем курсор
      if (KEY == 2) { // если нажата кнопка
        tempOUT1--;   // изменяем значение
        EEPROM.write(1, tempOUT1); // сохраняем в еепром
      }
      else if (KEY == 5){
        tempOUT1++;
        EEPROM.write(1, tempOUT1);     
      }    
    }
    if (pos == 1){ 
      lcd.setCursor(5, 1);
      if (KEY == 2) {
        tempOUT2--;
        EEPROM.write(2, tempOUT2);
      }
      else if (KEY == 5){
        tempOUT2++;
        EEPROM.write(2, tempOUT2);     
      }    
    }
    
    if (KEY == 3) pos--; // крутим позицию
    else if (KEY == 4) pos++;    
    if (pos > 1) pos = 0; 
 
   delay(200);
  }
}

float getTemp(){   // возвращает температуру с датчика
  byte data[12];   // и останавливает программу на секунду
  byte addr[8];
    
  
  if (!ds.search(addr)) {
    lcd.clear();
    lcd.print("No sensor."); 
    erorr(); 
  }
  
  ds.reset_search(); 
 
  if (OneWire::crc8(addr, 7) != addr[7]) {
    lcd.clear();
    lcd.print("Sensor CRC erorr");
    erorr();   
  }
  
  ds.reset();            
  ds.select(addr);        
  ds.write(0x44);      
  delay(1000);   
  
  ds.reset();
  ds.select(addr);    
  ds.write(0xBE);          

  for (int i = 0; i < 9; i++) data[i] = ds.read(); 
  int raw = (data[1] << 8) | data[0]; // Переводим в температуру   
  if (data[7] == 0x10) raw = (raw & 0xFFF0) + 12 - data[6];  
  
  return raw / 16.0;
}

unsigned long timing;

void setup() {
  Serial.begin(9600); 
  lcd.createChar(1, gradus);
  lcd.begin(16, 2);
  lcd.clear();
  dht.begin();
  
  pinMode(13, OUTPUT); 
  pinMode(OUT1, OUTPUT);
  pinMode(OUT2, OUTPUT);
  
  tempOUT1 = EEPROM.read(1); // читаем настройки 
  tempOUT2 = EEPROM.read(2); // из еепром
}

void loop() {  
  if (key() == 1) setMenu(); // если нажата селект, уходим в меню
  else if (key() == 4) analogWrite(10, 30); // если вниз, глушим подсветку
  else if (key() == 3) digitalWrite(10, HIGH);
  float temperature = getTemp(); // читаем температуру

  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  getTemp();
  //if(t <= tempOUT1){
    //if (!digitalRead(OUT1)){
    //  digitalWrite(OUT1, HIGH);
    //  timing = millis();
   // } 
   // if (!digitalRead(OUT2) && millis() - timing > 10000){
     // digitalWrite(OUT2, HIGH);
    //}
  //}
  if(t >= tempOUT1 ){
    if (digitalRead(OUT1)){
      digitalWrite(OUT1, LOW);
      timing = millis();
    } 
    if (digitalRead(OUT2) && millis() - timing > 10000){
      digitalWrite(OUT2, LOW);
    }
    goto  metka1;
  }
  
  
 
  if(temperature -1<= tempOUT2){
    if (!digitalRead(OUT1)){
      digitalWrite(OUT1, HIGH);
      timing = millis();
    } 
    if (!digitalRead(OUT2) && millis() - timing > 10000){
      digitalWrite(OUT2, HIGH);
    }
  }
  if(temperature +1>= tempOUT2 ){
    if (digitalRead(OUT1)){
      digitalWrite(OUT1, LOW);
      timing = millis();
    } 
    if (digitalRead(OUT2) && millis() - timing > 10000){
      digitalWrite(OUT2, LOW);
    }
  }

  

  

  metka1:   
  lcd.setCursor(0, 0); /// вывод инфы на экран
  lcd.print("G");
  lcd.print("-");
  lcd.print(t);
  lcd.write(1);
  lcd.print("C");
  lcd.setCursor(10, 0);
  lcd.print(h);
  lcd.print("%");
    //if (digitalRead(OUT1)) lcd.print(" ON "); // показываем состояние выхода
    //else lcd.print(" OFF");
  lcd.setCursor(0, 1);
  lcd.print("K");
  lcd.print("-");
  //lcd.setCursor(7, 1);
  lcd.print(temperature);
  lcd.write(1);
  lcd.print("C");
  //lcd.write(1);
    //if (digitalRead(OUT2)) lcd.print(" ON ");
    //else lcd.print(" OFF");    
    
  //lcd.setCursor(9, 0); // показываем температуру с датчика
  //lcd.print("|"); 
  //lcd.print(h, 1);
  //lcd.write(1);
  //lcd.print("C");
  //lcd.setCursor(9, 1);     
  //lcd.print("|");  
}