Цифровые автоматы в классах по qwone

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone пишет:

Теперь сделаем вывод на экран LCD1602 I2C

QSketch:271: error: 'class LiquidCrystal_I2C' has no member named 'init'
 
exit status 1
'class LiquidCrystal_I2C' has no member named 'init'
 
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ворота пишет:
QSketch:271: error: 'class LiquidCrystal_I2C' has no member named 'init'

 
exit status 1
'class LiquidCrystal_I2C' has no member named 'init'
 

 https://github.com/johnrickman/LiquidCrystal_I2C

Pyotr
Offline
Зарегистрирован: 12.03.2014

Если не против.
Редактируемые переменные (уставки) и их мин. и макс. значения можно не хранить в ОЗУ, а только в еепром и загружать в локальные по необходимости. Это на случай если уставок десятки-сотни.

При работе с еепром удобно пользоваться атрибутом ЕЕМЕМ. Ненадо помнить где какая переменная лежит.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

http://robocraft.ru/blog/3043.html

Ну где-то так 

/**/
//--переменые---------------------
#include <avr/eeprom.h>
typedef struct {
  uint8_t value;
  uint8_t minimum;
  uint8_t maximum;
} byte_t ;
const byte numVar = 4;
byte_t EEMEM adr[numVar];
void saveZeroSettings() {
  byte_t data[numVar] = { // начальные настройки
    {10, 10, 50}, // 1-я переменная
    {20, 10, 50}, // 2-я переменная
    {30, 10, 50}, // 3-я переменная
    {40, 10, 50}  // 4-я переменная
  };
  for (int i = 0; i < numVar; ++i) {
    eeprom_write_byte(&adr[i].value  , data[i].value);
    eeprom_write_byte(&adr[i].minimum, data[i].minimum);
    eeprom_write_byte(&adr[i].maximum, data[i].maximum);
  }
}
byte var[4];
void initVar() {
  for (int i = 0; i < numVar; ++i) {
    var[i] = eeprom_read_byte(&adr[i].value);
  }
}
//----------------------------------------------
template <typename T> inline Print & operator << (Print & s, T n) {
  s.print(n);
  return s;
}
//-----------------------------------------------
void setup() {
  Serial.begin(9600);
  saveZeroSettings(); 
  initVar();
for (int i = 0; i < numVar; ++i) {
    var[i] = eeprom_read_byte(&adr[i].value);
    Serial << i << "=" << var[i] << "\n";
    }
}
void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Поправил скетч #50 Понятно что скеч стал сложнее для понимания.Но проверил - работает

//--переменые---------------------
#include <avr/eeprom.h>
typedef struct {
  uint8_t value;
  uint8_t minimum;
  uint8_t maximum;
} byte_t ;
const byte numVar = 4;
byte_t EEMEM adr[numVar];
void saveZeroSettings() {
  byte_t data[numVar] = { // начальные настройки
    {10, 10, 50}, // 1-я переменная
    {20, 10, 50}, // 2-я переменная
    {30, 10, 50}, // 3-я переменная
    {40, 10, 50}  // 4-я переменная
  };
  for (int i = 0; i < numVar; ++i) {
    eeprom_write_byte(&adr[i].value  , data[i].value  );
    eeprom_write_byte(&adr[i].minimum, data[i].minimum);
    eeprom_write_byte(&adr[i].maximum, data[i].maximum);
  }
}
byte var[4];
void initVar() {
  for (int i = 0; i < numVar; ++i) {
    var[i] = eeprom_read_byte(&adr[i].value);
  }
}
//---------сенсор----------------------------
class Cl_sens {
  protected:
    const byte pin;
    byte val;
    unsigned long past;
  public:
    Cl_sens(byte p): pin(p) {}
    void init() {
      pinMode(pin, INPUT);
      val = analogRead(pin) / 16;
      past = millis();
    }
    void run() {
      if (millis() - past >= 500) {
        val = analogRead(pin) / 16;
        past = millis();
      }
    }
    byte read() {
      return val;
    }
};
const int numSens = 2;
Cl_sens Sens[numSens] = {
  Cl_sens(/*пин*/A0),  //сенсор 1
  Cl_sens(/*пин*/A1),  //сенсор 2
};
//---кнопки-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
const int numBtn = 3;
Cl_btn Btn[numBtn] = {
  Cl_btn(/*пин*/2),  //кнопка верх
  Cl_btn(/*пин*/3),  //кнопка вниз
  Cl_btn(/*пин*/4)   //кнопка Select
};
//--LCD1602-----------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool backlightState = 0;
void invertBL() {
  if (!backlightState) {
    backlightState = 1;
    lcd.backlight();// Включаем подсветку дисплея
  }
  else {
    backlightState = 0;
    lcd.noBacklight();// Выключаем подсветку дисплея
  }
}

//--меню--------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte strMain = 0; // главный экран
const byte str1    = 1; // 1-й экран
const byte Estr1   = 2; // 1-й экран(редактирование)
const byte str2    = 3; // 2-й экран
const byte Estr2   = 4; // 2-й экран(редактирование)
const byte str3    = 5; // 3-й экран
const byte Estr3   = 6; // 3-й экран(редактирование)
const byte str4    = 7; // 4-й экран
const byte Estr4   = 8; // 4-й экран(редактирование)
byte pos;
byte editVar;
unsigned long pastMenu;
void setPos(byte p) {
  pastMenu = millis();
  pos = p;
  switch (p) {
    case strMain:
      lcd.clear();
      lcd << F("T1:") << Sens[0].read() << F("   ");
      lcd.setCursor(0, 1);
      lcd << F("T2:") << Sens[1].read() << F("   ");
      Btn[0].Do = [] {};  //кнопка верх
      Btn[1].Do = [] {setPos(str1);};  //кнопка вниз
      Btn[2].Do = [] {invertBL();};  //кнопка Select
      break;
    case str1:
      lcd.clear();
      lcd << F("var1=") << var[0] << F("  ");
      Btn[0].Do = [] {setPos(strMain);}; //кнопка верх
      Btn[1].Do = [] {setPos(str2);};    //кнопка вниз
      Btn[2].Do = [] {                   //кнопка Select
        editVar = var[0];
        setPos(Estr1);
      };
      break;
    case Estr1:
      lcd.clear();
      lcd << F("var1-") << editVar << F("  ");
      Btn[0].Do = [] {     //кнопка верх
        byte maximum = eeprom_read_byte(&adr[0].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr1);
      };
      Btn[1].Do = [] {       //кнопка вниз
        byte minimum = eeprom_read_byte(&adr[0].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr1);
      };
      Btn[2].Do = [] {  //кнопка Select
        eeprom_write_byte(&adr[0].value, editVar);
        var[0] = editVar;
        setPos(str1);
      };
      break;
    case str2:
      lcd.clear();
      lcd << F("var2=") << var[1] << F("  ");
      Btn[0].Do = [] {setPos(str1);};  //кнопка верх
      Btn[1].Do = [] {setPos(str3);};  //кнопка вниз
      Btn[2].Do = [] {                 //кнопка Select
        editVar = var[1];
        setPos(Estr2);
      };
      break;
    case Estr2:
      lcd.clear();
      lcd << F("var2-") << editVar << F("  ");
      Btn[0].Do = [] {
        byte maximum = eeprom_read_byte(&adr[1].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr2);
      };  //кнопка верх
      Btn[1].Do = [] {
        byte minimum = eeprom_read_byte(&adr[1].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr2);
      };  //кнопка вниз
      Btn[2].Do = [] {    //кнопка Select
        eeprom_write_byte(&adr[1].value, editVar);
        var[1] = editVar;
        setPos(str2);
      };
      break;
    case str3:
      lcd.clear();
      lcd << F("var3=") << var[2] << F("  ");
      Btn[0].Do = [] {setPos(str2);};  //кнопка верх
      Btn[1].Do = [] {setPos(str4);};  //кнопка вниз
      Btn[2].Do = [] {                 //кнопка Select
        editVar = var[2];
        setPos(Estr3);
      };
      break;
    case Estr3:
      lcd.clear();
      lcd << F("var3-") << editVar << F("  ");
      Btn[0].Do = [] {   //кнопка верх
        byte maximum = eeprom_read_byte(&adr[2].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr3);
      };
      Btn[1].Do = [] {   //кнопка вниз
        byte minimum = eeprom_read_byte(&adr[2].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr3);
      };
      Btn[2].Do = [] {  //кнопка Select
        eeprom_write_byte(&adr[2].value, editVar);
        var[2] = editVar;
        setPos(str3);
      };
      break;
    case str4:
      lcd.clear();
      lcd << F("var4=") << var[3] << F("  ");
      Btn[0].Do = [] {setPos(str3);}; //кнопка верх
      Btn[1].Do = [] {};              //кнопка вниз
      Btn[2].Do = [] {                //кнопка Select
        editVar = var[3];
        setPos(Estr4);
      };
      break;
    case Estr4:
      lcd.clear();
      lcd << F("var4-") << editVar << F("  ");
      Btn[0].Do = [] {   //кнопка верх
        byte maximum = eeprom_read_byte(&adr[3].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr3);
      };
      Btn[1].Do = [] {   //кнопка вниз
        byte minimum = eeprom_read_byte(&adr[3].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr4);
      };
      Btn[2].Do = [] {  //кнопка Select
        eeprom_write_byte(&adr[3].value, editVar);
        var[3] = editVar;
        setPos(str4);
      };
      break;
  }
}
void runMenu() {
  switch (pos) {
    case strMain:
      // если находимся на главном экране то обновлять каждую секунду
      if (millis() - pastMenu >= 1000) setPos(strMain);
      break;
    default:
      // если пользователь не нажимает на кнопки, то вернуться на главный экран
      if (millis() - pastMenu >= 10000) setPos(strMain);
  }
}
//--main------------------------------
void setup() {
  //saveZeroSettings(); раскоментировать только для загрузки EEPROM
  initVar();
  for (int i = 0; i < numSens; i++)Sens[i].init();
  for (int i = 0; i < numBtn; i++)Btn[i].init();
  lcd.init();
  invertBL();
  setPos(strMain);
}
void loop() {
  for (int i = 0; i < numSens; i++)Sens[i].run();
  for (int i = 0; i < numBtn; i++)Btn[i].run();
  runMenu();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну а теперь подключим ... реле

//--переменые---------------------
#include <avr/eeprom.h>
typedef struct {
  uint8_t value;
  uint8_t minimum;
  uint8_t maximum;
} byte_t ;
const byte numVar = 4;
byte_t EEMEM adr[numVar];
void saveZeroSettings() {
  byte_t data[numVar] = { // начальные настройки
    {20, 10, 50}, // 1-я переменная
    {30, 10, 50}, // 2-я переменная
    {20, 10, 50}, // 3-я переменная
    {30, 10, 50}  // 4-я переменная
  };
  for (int i = 0; i < numVar; ++i) {
    eeprom_write_byte(&adr[i].value  , data[i].value  );
    eeprom_write_byte(&adr[i].minimum, data[i].minimum);
    eeprom_write_byte(&adr[i].maximum, data[i].maximum);
  }
}
byte var[4];
void initVar() {
  for (int i = 0; i < numVar; ++i) {
    var[i] = eeprom_read_byte(&adr[i].value);
  }
}
//---------сенсор----------------------------
class Cl_sens {
  protected:
    const byte pin;
    byte val;
    unsigned long past;
  public:
    Cl_sens(byte p): pin(p) {}
    void init() {
      pinMode(pin, INPUT);
      val = analogRead(pin) / 16;
      past = millis();
    }
    void run() {
      if (millis() - past >= 500) {
        val = analogRead(pin) / 16;
        past = millis();
      }
    }
    byte read() {
      return val;
    }
};
const int numSens = 2;
Cl_sens Sens[numSens] = {
  Cl_sens(/*пин*/A0),  //сенсор 1
  Cl_sens(/*пин*/A1),  //сенсор 2
};
//---кнопки-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
const int numBtn = 3;
Cl_btn Btn[numBtn] = {
  Cl_btn(/*пин*/2),  //кнопка верх
  Cl_btn(/*пин*/3),  //кнопка вниз
  Cl_btn(/*пин*/4)   //кнопка Select
};
//--LCD1602-----------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool backlightState = 0;
void invertBL() {
  if (!backlightState) {
    backlightState = 1;
    lcd.backlight();// Включаем подсветку дисплея
  }
  else {
    backlightState = 0;
    lcd.noBacklight();// Выключаем подсветку дисплея
  }
}
//---реле-------------------------------
typedef byte (*pRetByte)();
class Cl_relay {
  protected:
    byte pin;
    pRetByte RetByte1 = [] {return (byte)0;};
    pRetByte RetByte2 = [] {return (byte)0;};
    bool state;
    unsigned long past;
    void set(bool s) {
      past = millis();
      state = s;
      switch (s) {
        case false:
          digitalWrite(pin, HIGH);
          break;
        case true:
          digitalWrite(pin, LOW);
          break;
      }
    }
  public:
    Cl_relay(byte p, pRetByte pRB1, pRetByte pRB2)
      : pin(p), RetByte1(pRB1), RetByte2(pRB2) {}
    void init() {
      pinMode(pin, OUTPUT);
      set(false);
    }
    void run() {
      if (millis() - past > 200) {
        switch (state) {
          case false:
            if (RetByte1() >= RetByte2() + 1)set(true);
            break;
          case true:
            if (RetByte2() >= RetByte1() + 1)set(false);
            break;
        }
      }
    }
    void viev() {
      switch (state) {
        case false:
          lcd << F("OFF");
          break;
        case true:
          lcd << F(" ON");
          break;
      }
    }
};
const int numRly = 4;
Cl_relay Rly[numRly] = {
  // пин                  1 выражением сравнивается с 2 выражением
  Cl_relay(/*пин*/5, [] {return var[0];}, [] {return Sens[0].read();}), //реле 1
  Cl_relay(/*пин*/6, [] {return var[1];}, [] {return Sens[0].read();}), //реле 2
  Cl_relay(/*пин*/7, [] {return var[2];}, [] {return Sens[1].read();}), //реле 4
  Cl_relay(/*пин*/8, [] {return var[3];}, [] {return Sens[1].read();})  //реле 3
};
//--меню--------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte strMain = 0; // главный экран
const byte str1    = 1; // 1-й экран
const byte Estr1   = 2; // 1-й экран(редактирование)
const byte str2    = 3; // 2-й экран
const byte Estr2   = 4; // 2-й экран(редактирование)
const byte str3    = 5; // 3-й экран
const byte Estr3   = 6; // 3-й экран(редактирование)
const byte str4    = 7; // 4-й экран
const byte Estr4   = 8; // 4-й экран(редактирование)
byte pos;
byte editVar;
unsigned long pastMenu;
void setPos(byte p) {
  pastMenu = millis();
  pos = p;
  switch (p) {
    case strMain:
      lcd.clear();
      lcd << F("T1:") << Sens[0].read() << F("   ");
      lcd.setCursor(6,  0); Rly[0].viev();
      lcd.setCursor(10, 0); Rly[1].viev();
      lcd.setCursor(0, 1);
      lcd << F("T2:") << Sens[1].read() << F("   ");
      lcd.setCursor(6,  1); Rly[2].viev();
      lcd.setCursor(10, 1); Rly[3].viev();
      Btn[0].Do = [] {};  //кнопка верх
      Btn[1].Do = [] {setPos(str1);};  //кнопка вниз
      Btn[2].Do = [] {invertBL();};  //кнопка Select
      break;
    case str1:
      lcd.clear();
      lcd << F("var1=") << var[0] << F("  ");
      Btn[0].Do = [] {setPos(strMain);}; //кнопка верх
      Btn[1].Do = [] {setPos(str2);};    //кнопка вниз
      Btn[2].Do = [] {                   //кнопка Select
        editVar = var[0];
        setPos(Estr1);
      };
      break;
    case Estr1:
      lcd.clear();
      lcd << F("var1-") << editVar << F("  ");
      Btn[0].Do = [] {     //кнопка верх
        byte maximum = eeprom_read_byte(&adr[0].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr1);
      };
      Btn[1].Do = [] {       //кнопка вниз
        byte minimum = eeprom_read_byte(&adr[0].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr1);
      };
      Btn[2].Do = [] {  //кнопка Select
        eeprom_write_byte(&adr[0].value, editVar);
        var[0] = editVar;
        setPos(str1);
      };
      break;
    case str2:
      lcd.clear();
      lcd << F("var2=") << var[1] << F("  ");
      Btn[0].Do = [] {setPos(str1);};  //кнопка верх
      Btn[1].Do = [] {setPos(str3);};  //кнопка вниз
      Btn[2].Do = [] {                 //кнопка Select
        editVar = var[1];
        setPos(Estr2);
      };
      break;
    case Estr2:
      lcd.clear();
      lcd << F("var2-") << editVar << F("  ");
      Btn[0].Do = [] {
        byte maximum = eeprom_read_byte(&adr[1].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr2);
      };  //кнопка верх
      Btn[1].Do = [] {
        byte minimum = eeprom_read_byte(&adr[1].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr2);
      };  //кнопка вниз
      Btn[2].Do = [] {    //кнопка Select
        eeprom_write_byte(&adr[1].value, editVar);
        var[1] = editVar;
        setPos(str2);
      };
      break;
    case str3:
      lcd.clear();
      lcd << F("var3=") << var[2] << F("  ");
      Btn[0].Do = [] {setPos(str2);};  //кнопка верх
      Btn[1].Do = [] {setPos(str4);};  //кнопка вниз
      Btn[2].Do = [] {                 //кнопка Select
        editVar = var[2];
        setPos(Estr3);
      };
      break;
    case Estr3:
      lcd.clear();
      lcd << F("var3-") << editVar << F("  ");
      Btn[0].Do = [] {   //кнопка верх
        byte maximum = eeprom_read_byte(&adr[2].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr3);
      };
      Btn[1].Do = [] {   //кнопка вниз
        byte minimum = eeprom_read_byte(&adr[2].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr3);
      };
      Btn[2].Do = [] {  //кнопка Select
        eeprom_write_byte(&adr[2].value, editVar);
        var[2] = editVar;
        setPos(str3);
      };
      break;
    case str4:
      lcd.clear();
      lcd << F("var4=") << var[3] << F("  ");
      Btn[0].Do = [] {setPos(str3);}; //кнопка верх
      Btn[1].Do = [] {};              //кнопка вниз
      Btn[2].Do = [] {                //кнопка Select
        editVar = var[3];
        setPos(Estr4);
      };
      break;
    case Estr4:
      lcd.clear();
      lcd << F("var4-") << editVar << F("  ");
      Btn[0].Do = [] {   //кнопка верх
        byte maximum = eeprom_read_byte(&adr[3].maximum);
        if (editVar < maximum) editVar++;
        setPos(Estr3);
      };
      Btn[1].Do = [] {   //кнопка вниз
        byte minimum = eeprom_read_byte(&adr[3].minimum);
        if (editVar > minimum) editVar--;
        setPos(Estr4);
      };
      Btn[2].Do = [] {  //кнопка Select
        eeprom_write_byte(&adr[3].value, editVar);
        var[3] = editVar;
        setPos(str4);
      };
      break;
  }
}
void runMenu() {
  switch (pos) {
    case strMain:
      // если находимся на главном экране то обновлять каждую секунду
      if (millis() - pastMenu >= 1000) setPos(strMain);
      break;
    default:
      // если пользователь не нажимает на кнопки, то вернуться на главный экран
      if (millis() - pastMenu >= 10000) setPos(strMain);
  }
}
//--main------------------------------
void setup() {
  saveZeroSettings();// раскоментировать только для загрузки EEPROM
  initVar();
  for (int i = 0; i < numSens; i++)Sens[i].init();
  for (int i = 0; i < numRly ; i++)Rly [i].init();
  for (int i = 0; i < numBtn; i++)Btn[i].init();
  lcd.init();
  invertBL();
  setPos(strMain);
}
void loop() {
  for (int i = 0; i < numSens; i++)Sens[i].run();
  for (int i = 0; i < numRly ; i++) Rly[i].run();
  for (int i = 0; i < numBtn; i++)Btn[i].run();
  runMenu();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Так на будущее на подумать.

/**/
//--так оценочный класс byte ----
typedef struct {
  byte data;
} byte_t;
class Cl_byte {
  protected :
    byte_t adr;
    byte data;
  public:
    Cl_byte(byte_t a): adr(a) {
      data = read();
    }
    byte read() {
      return eeprom_read_byte(&adr.data);
    }
    void write(byte d) {
      data = d;
      if (read() != d)
        eeprom_write_byte(&adr.data, d);
    }
    void zeroSetting() {
      byte_t tmp = {0xFF};
      eeprom_write_byte(&adr.data, tmp.data);
    }
};
const byte num = 5;
byte_t EEMEM adr[num];
Cl_byte Byte[num] = {
  Cl_byte(adr[0]),
  Cl_byte(adr[1]),
  Cl_byte(adr[2]),
  Cl_byte(adr[3]),
  Cl_byte(adr[4])
};
void setup() {
  //for (int i = 0; i < num; i++)Byte[i].zeroSetting(); // для первичной настройки в EEPROM
  for (int i = 0; i < num; i++)Byte[i].read();
  for (int i = 0; i < num; i++)Byte[i].write(10);
}

void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Переписал программу #11  под теперешний стиль

/*LCD Key Shield*/
unsigned long mill;
//--------------------Cl_aKeyboard--------------------------------
typedef void (*pDo)();
/*состояние-нет нажатий/правая/левая/вверх/вниз/влево/выбор*/
const byte skNone   = 0;
const byte skRight  = 1;
const byte skUp     = 2;
const byte skDown   = 3;
const byte skLeft   = 4;
const byte skSelect = 5;
class Cl_aKeyboard {
  public:
    // обработчики кнопок
    pDo DoRight = [] {};
    pDo DoUp = [] {};
    pDo DoDown = [] {};
    pDo DoLeft = [] {};
    pDo DoSelect = [] {};
  protected:
    const byte pin;
    byte state;
    unsigned long past;
    byte read() {
      int tmp = analogRead(pin);
      if (tmp < 80)       return skRight;
      else if (tmp < 200) return  skUp;
      else if (tmp < 400) return  skDown;
      else if (tmp < 600) return  skLeft;
      else if (tmp < 800) return  skSelect;
      else  return  skNone;
    }
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case skNone:
          break;
        case skRight:
          DoRight();
          break;
        case skUp:
          DoUp();
          break;
        case skDown:
          DoDown();
          break;
        case skLeft:
          DoLeft();
          break;
        case skSelect:
          DoSelect();
          break;
      }
    }
  public:
    Cl_aKeyboard(byte p) : pin(p) {}
    void init() {
      set(read());
    }
    void run() {
      if (millis() - past >= 100) {
        switch (state) {
          case skNone: {
              byte tmp = read();
              if (tmp != skNone)set(tmp);
              break;
            }
          default:
            if (millis() - past >= 300)set(skNone);
        }
      }
    }
};
Cl_aKeyboard Keyboard(/*пин*/A0);
//---------------lcd и меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
#include <LiquidCrystal.h>
LiquidCrystal lcd(/*RS*/8,/*Enable*/9,/*DB4*/4,/*DB5*/5,/*DB6*/6,/*DB7*/7);
const byte sNone    = 0;// 1-экран
const byte sRight   = 1;// 2-экран
const byte sUp      = 2;// 3-экран
const byte sDown    = 3;// 4-экран
const byte sLeft    = 4;// 5-экран
const byte sSelect  = 5;// 6-экран
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  switch (p) {
    case sNone:
      lcd.clear();
      lcd << F("LCD Key Shield");
      lcd.setCursor(0, 1);
      lcd << F("Press Key:None");
      break;
    case sRight:
      lcd.clear();
      lcd << F("LCD Key Shield");
      lcd.setCursor(0, 1);
      lcd << F("Press Key:Right");
      break;
    case sUp:
      lcd.clear();
      lcd << F("LCD Key Shield");
      lcd.setCursor(0, 1);
      lcd << F("Press Key:Up");
      break;
    case sDown:
      lcd.clear();
      lcd << F("LCD Key Shield");
      lcd.setCursor(0, 1);
      lcd << F("Press Key:Down");
      break;
    case sLeft:
      lcd.clear();
      lcd << F("LCD Key Shield");
      lcd.setCursor(0, 1);
      lcd << F("Press Key:Left");
      break;
    case sSelect:
      lcd.clear();
      lcd << F("LCD Key Shield");
      lcd.setCursor(0, 1);
      lcd << F("Press Key:Select");
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sNone);
  Keyboard.DoRight  = [] {setPos(sRight); };
  Keyboard.DoUp     = [] {setPos(sUp);    };
  Keyboard.DoDown   = [] {setPos(sDown);  };
  Keyboard.DoLeft   = [] {setPos(sLeft);  };
  Keyboard.DoSelect = [] {setPos(sSelect);};
}
void menuRun() {
  if (pos != sNone && millis() - past >= 10000)setPos(sNone);
}
//----------------------------------------
void setup() {
  Keyboard.init();
  menuInit();
}
void loop() {
  Keyboard.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/*LCD Key Shield*/
unsigned long mill;
//--------------------Cl_aKeyboard--------------------------------
typedef void (*pDo)();
/*состояние-нет нажатий/правая/левая/вверх/вниз/влево/выбор*/
const byte skNone   = 0;
const byte skRight  = 1;
const byte skUp     = 2;
const byte skDown   = 3;
const byte skLeft   = 4;
const byte skSelect = 5;
class Cl_aKeyboard {
  public:
    // обработчики кнопок
    pDo DoRight = [] {};
    pDo DoUp = [] {};
    pDo DoDown = [] {};
    pDo DoLeft = [] {};
    pDo DoSelect = [] {};
  protected:
    const byte pin;
    byte state;
    unsigned long past;
    byte read() {
      int tmp = analogRead(pin);
      if (tmp < 100)       return skRight;
      else if (tmp < 200) return  skUp;
      else if (tmp < 400) return  skDown;
      else if (tmp < 600) return  skLeft;
      else if (tmp < 800) return  skSelect;
      else  return  skNone;
    }
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case skNone:
          break;
        case skRight:
          DoRight();
          break;
        case skUp:
          DoUp();
          break;
        case skDown:
          DoDown();
          break;
        case skLeft:
          DoLeft();
          break;
        case skSelect:
          DoSelect();
          break;
      }
    }
  public:
    Cl_aKeyboard(byte p) : pin(p) {}
    void init() {
      set(read());
    }
    void run() {
      if (millis() - past >= 100) {
        switch (state) {
          case skNone: {
              byte tmp = read();
              if (tmp != skNone)set(tmp);
              break;
            }
          default:
            if (millis() - past >= 300)set(skNone);
        }
      }
    }
};
Cl_aKeyboard Keyboard(/*пин*/A0);
//---------------lcd и меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
#include <LiquidCrystal.h>
LiquidCrystal lcd(/*RS*/8,/*Enable*/9,/*DB4*/4,/*DB5*/5,/*DB6*/6,/*DB7*/7);
const byte sMain = 0;// главный экран
const byte ss1   = 1;// 1-экран
const byte ss2   = 2;// 2-экран
const byte ss3   = 3;// 3-экран
const byte ss4   = 4;// 4-экран
const byte ss5   = 5;// 5-экран
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  switch (p) {
    case sMain:
      lcd.clear();
      lcd << F("Main screen");
      Keyboard.DoUp   = [] { };
      Keyboard.DoDown = [] {setPos(ss1); };
      break;
    case ss1:
      lcd.clear();
      lcd << F("1 screen");
      Keyboard.DoUp   = [] {setPos(sMain); };
      Keyboard.DoDown = [] {setPos(ss2); };
      break;
    case ss2:
      lcd.clear();
      lcd << F("2 screen");
      Keyboard.DoUp   = [] {setPos(ss1); };
      Keyboard.DoDown = [] {setPos(ss3); };
      break;
    case ss3:
      lcd.clear();
      lcd << F("3 screen");
      Keyboard.DoUp   = [] {setPos(ss2); };
      Keyboard.DoDown = [] {setPos(ss4); };
      break;
    case ss4:
      lcd.clear();
      lcd << F("4 screen");
      Keyboard.DoUp   = [] {setPos(ss3); };
      Keyboard.DoDown = [] {setPos(ss5); };
      break;
    case ss5:
      lcd.clear();
      lcd << F("5 screen");
      Keyboard.DoUp   = [] {setPos(ss4); };
      Keyboard.DoDown = [] { };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------------
void setup() {
  Keyboard.init();
  menuInit();
}
void loop() {
  Keyboard.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--меню--------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//----------------------------------
void setup() {
  Serial.begin(9600);
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  Btn.Do = [] {Serial << F("Btn\n");};
  JoyLR.Do1 = [] {Serial << F("Right\n");};
  JoyLR.Do2 = [] {Serial << F("Left\n");};
  JoyUD.Do1 = [] {Serial << F("Up\n");};
  JoyUD.Do2 = [] {Serial << F("Down\n");};
}
void loop() {
  Btn.run();
  JoyLR.run();
  JoyUD.run();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А теперь подключим lcd I2C с меню . джойстик вверх вкл подсветку, вниз выключить . вправо-влево бегаем по экранам меню . если ничего не делаем 10сек возврат на главный экран. Подобный скетч выше но на трех кнопках.

//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------------lcd---------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//--------------- меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte sMain = 0;// главный экран
const byte ss1   = 1;// 1-экран
const byte ss2   = 2;// 2-экран
const byte ss3   = 3;// 3-экран
const byte ss4   = 4;// 4-экран
const byte ss5   = 5;// 5-экран
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:
      lcd << F("Main screen");
      JoyUD.Do1   = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1:
      lcd << F("1 screen");
      JoyUD.Do1   = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss2:
      lcd << F("2 screen");
      JoyUD.Do1   = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss3:
      lcd << F("3 screen");
      JoyUD.Do1   = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss4:
      lcd << F("4 screen");
      JoyUD.Do1   = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss5:
      lcd << F("5 screen");
      JoyUD.Do1 = [] {setPos(ss4); };
      JoyUD.Do2 = [] {};
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  Btn.Do = [] {};
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Добавил таймер на millis

//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------------lcd---------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//--------------- меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte sMain = 0;// главный экран
const byte ss1   = 1;// 1-экран
const byte ss2   = 2;// 2-экран
const byte ss3   = 3;// 3-экран
const byte ss4   = 4;// 4-экран
const byte ss5   = 5;// 5-экран
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:
      { unsigned long now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd << F("Time:") << hour << F(":") << minute << F(":") << second;
      }
      JoyUD.Do1   = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1:
      lcd << F("1 screen");
      JoyUD.Do1   = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss2:
      lcd << F("2 screen");
      JoyUD.Do1   = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss3:
      lcd << F("3 screen");
      JoyUD.Do1   = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss4:
      lcd << F("4 screen");
      JoyUD.Do1   = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss5:
      lcd << F("5 screen");
      JoyUD.Do1 = [] {setPos(ss4); };
      JoyUD.Do2 = [] {};
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  Btn.Do = [] {};
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const timer_t Timer[] = {
  {0, 0, 0},// 1-й таймер
  {0, 0, 0},// 2-й таймер
  {0, 0, 0},// 3-й таймер
  {0, 0, 0},// 4-й таймер
  {0, 0, 0} // 5-й таймер
};
//---------------lcd---------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//--------------- меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte sMain = 0;// главный экран
const byte ss1   = 1;// 1-экран
const byte ss2   = 2;// 2-экран
const byte ss3   = 3;// 3-экран
const byte ss4   = 4;// 4-экран
const byte ss5   = 5;// 5-экран
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:
      { unsigned long now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd << F("Time:") << hour << F(":") << minute << F(":") << second;
      }
      JoyUD.Do1   = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1:
      {
        lcd << F("Timer1:") << Timer[0].hour << F(":") << Timer[0].minute << F(":") << Timer[0].second;
      }
      JoyUD.Do1   = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss2:
      {
        lcd << F("Timer2:") << Timer[1].hour << F(":") << Timer[1].minute << F(":") << Timer[1].second;
      }
      JoyUD.Do1   = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss3:
      {
        lcd << F("Timer3:") << Timer[2].hour << F(":") << Timer[2].minute << F(":") << Timer[2].second;
      }
      JoyUD.Do1   = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss4:
      {
        lcd << F("Timer4:") << Timer[3].hour << F(":") << Timer[3].minute << F(":") << Timer[3].second;
      }
      JoyUD.Do1   = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss5:
      {
        lcd << F("Timer5:") << Timer[4].hour << F(":") << Timer[4].minute << F(":") << Timer[4].second;
      }
      JoyUD.Do1 = [] {setPos(ss4); };
      JoyUD.Do2 = [] {};
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  Btn.Do = [] {};
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
timer_t Timer[] = {
  {1, 10, 11},// 1-й таймер
  {2, 20, 22},// 2-й таймер
  {3, 30, 33},// 3-й таймер
  {4, 40, 44},// 4-й таймер
  {5, 50, 55} // 5-й таймер
};
//---------------lcd---------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//--------------- меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte sMain   = 0;// главный экран
const byte ss1     = 1;// 1-экран
const byte ss1e1   = 2;// редактирование 1
const byte ss1e2   = 3;// редактирование 2
const byte ss1e3   = 4;// редактирование 3
const byte ss2     = 5;// 2-экран
const byte ss2e1   = 6;// редактирование 1
const byte ss2e2   = 7;// редактирование 2
const byte ss2e3   = 8;// редактирование 3
const byte ss3     = 9;// 3-экран
const byte ss3e1   = 10;// редактирование 1
const byte ss3e2   = 11;// редактирование 2
const byte ss3e3   = 12;// редактирование 3
const byte ss4     = 13;// 4-экран
const byte ss4e1   = 14;// редактирование 1
const byte ss4e2   = 15;// редактирование 2
const byte ss4e3   = 16;// редактирование 3
const byte ss5     = 17;// 5-экран
const byte ss5e1   = 18;// редактирование 1
const byte ss5e2   = 19;// редактирование 2
const byte ss5e3   = 20;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { unsigned long now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd << F("Time:") << hour << F(":") << minute << F(":") << second;
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << Timer[0].hour << F(":") << Timer[0].minute << F(":") << Timer[0].second;
      }
      Btn.Do    = [] {setPos(ss1e1); };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1e1:// редактирование 1
      {
        lcd << F("Timer1:") << Timer[0].hour << F(":") << Timer[0].minute << F(">") << Timer[0].second;
      }
      Btn.Do      = [] {setPos(ss1e2);};
      JoyUD.Do1   = [] {
        if (Timer[0].second < 59)Timer[0].second++;
        setPos(ss1e1);
      };
      JoyUD.Do2   = [] {
        if (Timer[0].second > 0)Timer[0].second--;
        setPos(ss1e1);
      };
      break;
    case ss1e2:// редактирование 2
      {
        lcd << F("Timer1:") << Timer[0].hour << F(">") << Timer[0].minute << F(":") << Timer[0].second;
      }
      Btn.Do      = [] {setPos(ss1e3);};
      JoyUD.Do1   = [] {
        if (Timer[0].minute < 59)Timer[0].minute++;
        setPos(ss1e2);
      };
      JoyUD.Do2   = [] {
        if (Timer[0].minute > 0)Timer[0].minute--;
        setPos(ss1e2);
      };
      break;
    case ss1e3:// редактирование 3
      {
        lcd << F("Timer1>") << Timer[0].hour << F(":") << Timer[0].minute << F(":") << Timer[0].second;
      }
      Btn.Do      = [] {setPos(ss1);};
      JoyUD.Do1   = [] {
        if (Timer[0].hour < 23)Timer[0].hour++;
        setPos(ss1e3);
      };
      JoyUD.Do2   = [] {
        if (Timer[0].hour > 0)Timer[0].hour--;
        setPos(ss1e3);
      };
      break;
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << Timer[1].hour << F(":") << Timer[1].minute << F(":") << Timer[1].second;
      }
      Btn.Do    = [] {setPos(ss2e1); };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2e1:
      {
        lcd << F("Timer2:") << Timer[1].hour << F(":") << Timer[1].minute << F(">") << Timer[1].second;
      }
      Btn.Do      = [] {setPos(ss2e2);};
      JoyUD.Do1   = [] {
        if (Timer[1].second < 59)Timer[1].second++;
        setPos(ss2e1);
      };
      JoyUD.Do2   = [] {
        if (Timer[1].second > 0)Timer[1].second--;
        setPos(ss2e1);
      };
      break;
    case ss2e2:
      {
        lcd << F("Timer2:") << Timer[1].hour << F(">") << Timer[1].minute << F(":") << Timer[1].second;
      }
      Btn.Do      = [] {setPos(ss2e3);};
      JoyUD.Do1   = [] {
        if (Timer[1].minute < 59)Timer[1].minute++;
        setPos(ss2e2);
      };
      JoyUD.Do2   = [] {
        if (Timer[1].minute > 0)Timer[1].minute--;
        setPos(ss2e2);
      };
      break;
    case ss2e3:
      {
        lcd << F("Timer2>") << Timer[1].hour << F(":") << Timer[1].minute << F(":") << Timer[1].second;
      }
      Btn.Do      = [] {setPos(ss2);};
      JoyUD.Do1   = [] {
        if (Timer[1].hour < 23)Timer[1].hour++;
        setPos(ss2e3);
      };
      JoyUD.Do2   = [] {
        if (Timer[1].hour > 0)Timer[1].hour--;
        setPos(ss2e3);
      };
      break;
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << Timer[2].hour << F(":") << Timer[2].minute << F(":") << Timer[2].second;
      }
      Btn.Do    = [] {setPos(ss3e1); };
      JoyUD.Do1   = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3e1:
      {
        lcd << F("Timer3:") << Timer[2].hour << F(":") << Timer[2].minute << F(">") << Timer[2].second;
      }
      Btn.Do      = [] {setPos(ss3e2);};
      JoyUD.Do1   = [] {
        if (Timer[2].second < 59)Timer[2].second++;
        setPos(ss3e1);
      };
      JoyUD.Do2   = [] {
        if (Timer[2].second > 0)Timer[2].second--;
        setPos(ss3e1);
      };
      break;
    case ss3e2:
      {
        lcd << F("Timer3:") << Timer[2].hour << F(">") << Timer[2].minute << F(":") << Timer[2].second;
      }
      Btn.Do      = [] {setPos(ss3e3);};
      JoyUD.Do1   = [] {
        if (Timer[2].minute < 59)Timer[2].minute++;
        setPos(ss3e2);
      };
      JoyUD.Do2   = [] {
        if (Timer[2].minute > 0)Timer[2].minute--;
        setPos(ss3e2);
      };
      break;
      break;
    case ss3e3:
      {
        lcd << F("Timer3>") << Timer[2].hour << F(":") << Timer[2].minute << F(":") << Timer[2].second;
      }
      Btn.Do      = [] {setPos(ss3);};
      JoyUD.Do1   = [] {
        if (Timer[2].hour < 23)Timer[2].hour++;
        setPos(ss3e3);
      };
      JoyUD.Do2   = [] {
        if (Timer[2].hour > 0)Timer[2].hour--;
        setPos(ss3e3);
      };
      break;
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << Timer[3].hour << F(":") << Timer[3].minute << F(":") << Timer[3].second;
      }
      Btn.Do    = [] {setPos(ss4e1); };
      JoyUD.Do1   = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4e1:
      {
        lcd << F("Timer4:") << Timer[3].hour << F(":") << Timer[3].minute << F(">") << Timer[3].second;
      }
      Btn.Do      = [] {setPos(ss4e2);};
      JoyUD.Do1   = [] {
        if (Timer[3].second < 59)Timer[3].second++;
        setPos(ss4e1);
      };
      JoyUD.Do2   = [] {
        if (Timer[3].second > 0)Timer[3].second--;
        setPos(ss4e1);
      };
      break;
    case ss4e2:
      {
        lcd << F("Timer4:") << Timer[3].hour << F(">") << Timer[3].minute << F(":") << Timer[3].second;
      }
      Btn.Do      = [] {setPos(ss4e3);};
      JoyUD.Do1   = [] {
        if (Timer[3].minute < 59)Timer[3].minute++;
        setPos(ss4e2);
      };
      JoyUD.Do2   = [] {
        if (Timer[3].minute > 0)Timer[3].minute--;
        setPos(ss4e2);
      };
      break;
    case ss4e3:
      {
        lcd << F("Timer4>") << Timer[3].hour << F(":") << Timer[3].minute << F(":") << Timer[3].second;
      }
      Btn.Do      = [] {setPos(ss4);};
      JoyUD.Do1   = [] {
        if (Timer[3].hour < 23)Timer[3].hour++;
        setPos(ss4e3);
      };
      JoyUD.Do2   = [] {
        if (Timer[3].hour > 0)Timer[3].hour--;
        setPos(ss4e3);
      };
      break;
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << Timer[4].hour << F(":") << Timer[4].minute << F(":") << Timer[4].second;
      }
      Btn.Do    = [] {setPos(ss5e1); };
      JoyUD.Do1 = [] {setPos(ss4);};
      JoyUD.Do2 = [] {};
      break;
    case ss5e1:
      {
        lcd << F("Timer5:") << Timer[4].hour << F(":") << Timer[4].minute << F(">") << Timer[4].second;
      }
      Btn.Do      = [] {setPos(ss5e2);};
      JoyUD.Do1   = [] {
        if (Timer[4].second < 59)Timer[4].second++;
        setPos(ss5e1);
      };
      JoyUD.Do2   = [] {
        if (Timer[4].second > 0)Timer[4].second--;
        setPos(ss5e1);
      };
      break;
    case ss5e2:
      {
        lcd << F("Timer5:") << Timer[4].hour << F(">") << Timer[4].minute << F(":") << Timer[4].second;
      }
      Btn.Do      = [] {setPos(ss5e3);};
      JoyUD.Do1   = [] {
        if (Timer[4].minute < 59)Timer[4].minute++;
        setPos(ss5e2);
      };
      JoyUD.Do2   = [] {
        if (Timer[4].minute > 0)Timer[4].minute--;
        setPos(ss5e2);
      };
      break;
    case ss5e3:
      {
        lcd << F("Timer5>") << Timer[4].hour << F(":") << Timer[4].minute << F(":") << Timer[4].second;
      }
      Btn.Do      = [] {setPos(ss5);};
      JoyUD.Do1   = [] {
        if (Timer[4].hour < 23)Timer[4].hour++;
        setPos(ss5e3);
      };
      JoyUD.Do2   = [] {
        if (Timer[4].hour > 0)Timer[4].hour--;
        setPos(ss5e3);
      };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Немного громоздко.Но похоже надо еще думать как упростить.

//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer] = { // начальные настройки
    {1, 10, 11},// 1-й таймер
    {2, 20, 22},// 2-й таймер
    {3, 30, 33},// 3-й таймер
    {4, 40, 44},// 4-й таймер
    {5, 50, 55} // 5-й таймер
  };
  for (int i = 0; i < numTimer; ++i) {
    eeprom_write_byte(&adr[i].hour  , data[i].hour);
    eeprom_write_byte(&adr[i].minute, data[i].minute);
    eeprom_write_byte(&adr[i].second, data[i].second);
  }
}
//---------------lcd---------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte sMain   = 0;// главный экран
const byte ss1     = 1;// 1-экран
const byte ss1e1   = 2;// редактирование 1
const byte ss1e2   = 3;// редактирование 2
const byte ss1e3   = 4;// редактирование 3
const byte ss2     = 5;// 2-экран
const byte ss2e1   = 6;// редактирование 1
const byte ss2e2   = 7;// редактирование 2
const byte ss2e3   = 8;// редактирование 3
const byte ss3     = 9;// 3-экран
const byte ss3e1   = 10;// редактирование 1
const byte ss3e2   = 11;// редактирование 2
const byte ss3e3   = 12;// редактирование 3
const byte ss4     = 13;// 4-экран
const byte ss4e1   = 14;// редактирование 1
const byte ss4e2   = 15;// редактирование 2
const byte ss4e3   = 16;// редактирование 3
const byte ss5     = 17;// 5-экран
const byte ss5e1   = 18;// редактирование 1
const byte ss5e2   = 19;// редактирование 2
const byte ss5e3   = 20;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { unsigned long now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd << F("Time:") << hour << F(":") << minute << F(":") << second;
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << eeprom_read_byte(&adr[0].hour) << F(":") << eeprom_read_byte(&adr[0].minute) << F(":") << eeprom_read_byte(&adr[0].second);
      }
      Btn.Do    = [] {
        var = eeprom_read_byte(&adr[0].second);
        setPos(ss1e1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1e1:// редактирование секунд
      {
        lcd << F("Timer1:") << eeprom_read_byte(&adr[0].hour) << F(":") << eeprom_read_byte(&adr[0].minute) << F(">") << var;
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[0].second, var);
        var = eeprom_read_byte(&adr[0].minute);
        setPos(ss1e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e1);
      };
      break;
    case ss1e2:// редактирование минут
      {
        lcd << F("Timer1:") << eeprom_read_byte(&adr[0].hour) << F(">") << var << F(":") << eeprom_read_byte(&adr[0].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[0].minute, var);
        var = eeprom_read_byte(&adr[0].hour);
        setPos(ss1e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e2);
      };
      break;
    case ss1e3:// редактирование часов
      {
        lcd << F("Timer1>") << var << F(":") << eeprom_read_byte(&adr[0].minute) << F(":") << eeprom_read_byte(&adr[0].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[0].hour, var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e3);
      };
      break;
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << eeprom_read_byte(&adr[1].hour) << F(":") << eeprom_read_byte(&adr[1].minute) << F(":") << eeprom_read_byte(&adr[1].second);
      }
      Btn.Do    = [] {
        var = eeprom_read_byte(&adr[1].second);
        setPos(ss2e1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2e1:
      {
        lcd << F("Timer2:") << eeprom_read_byte(&adr[1].hour) << F(":") << eeprom_read_byte(&adr[1].minute) << F(">") << var;
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[1].second, var);
        var = eeprom_read_byte(&adr[1].minute);
        setPos(ss2e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e1);
      };
      break;
    case ss2e2:
      {
        lcd << F("Timer2:") << eeprom_read_byte(&adr[1].hour) << F(">") << var << F(":") << eeprom_read_byte(&adr[1].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[1].minute, var);
        var = eeprom_read_byte(&adr[1].hour);
        setPos(ss2e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e2);
      };
      break;
    case ss2e3:
      {
        lcd << F("Timer2>") << var << F(":") << eeprom_read_byte(&adr[1].minute) << F(":") << eeprom_read_byte(&adr[1].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[1].hour, var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e3);
      };
      break;
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << eeprom_read_byte(&adr[2].hour) << F(":") << eeprom_read_byte(&adr[2].minute) << F(":") << eeprom_read_byte(&adr[2].second);
      }
      Btn.Do    = [] {
        var = eeprom_read_byte(&adr[2].second);
        setPos(ss3e1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3e1:// редакт секунд
      {
        lcd << F("Timer3:") << eeprom_read_byte(&adr[2].hour) << F(":") << eeprom_read_byte(&adr[2].minute) << F(">") << var;
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[2].second, var);
        var = eeprom_read_byte(&adr[2].minute);
        setPos(ss3e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e1);
      };
      break;
    case ss3e2:// редакт минут
      {
        lcd << F("Timer3:") << eeprom_read_byte(&adr[2].hour) << F(">") << var << F(":") << eeprom_read_byte(&adr[2].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[2].minute, var);
        var = eeprom_read_byte(&adr[2].hour);
        setPos(ss3e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e2);
      };
      break;
    case ss3e3:// редакт часов
      {
        lcd << F("Timer3>") << var << F(":") << eeprom_read_byte(&adr[2].minute) << F(":") << eeprom_read_byte(&adr[2].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[2].hour, var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e3);
      };
      break;
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << eeprom_read_byte(&adr[3].hour) << F(":") << eeprom_read_byte(&adr[3].minute) << F(":") << eeprom_read_byte(&adr[3].second);
      }
      Btn.Do    = [] {
        var = eeprom_read_byte(&adr[3].second);
        setPos(ss4e1);
      };
      JoyUD.Do1   = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4e1:
      {
        lcd << F("Timer4:") << eeprom_read_byte(&adr[3].hour) << F(":") << eeprom_read_byte(&adr[3].minute) << F(">") << var;
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[3].second, var);
        var = eeprom_read_byte(&adr[3].minute);
        setPos(ss4e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e1);
      };
      break;
    case ss4e2:
      {
        lcd << F("Timer4:") << eeprom_read_byte(&adr[3].hour) << F(">") << var << F(":") << eeprom_read_byte(&adr[3].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[3].minute, var);
        var = eeprom_read_byte(&adr[3].hour);
        setPos(ss4e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e2);
      };
      break;
    case ss4e3:
      {
        lcd << F("Timer4>") << var << F(":") << eeprom_read_byte(&adr[3].minute) << F(":") << eeprom_read_byte(&adr[3].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[3].hour, var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e3);
      };
      break;
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << eeprom_read_byte(&adr[4].hour) << F(":") << eeprom_read_byte(&adr[4].minute) << F(":") << eeprom_read_byte(&adr[4].second);
      }
      Btn.Do    = [] {
        var = eeprom_read_byte(&adr[4].second);
        setPos(ss5e1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5e1:
      {
        lcd << F("Timer5:") << eeprom_read_byte(&adr[4].hour) << F(":") << eeprom_read_byte(&adr[4].minute) << F(">") << var;
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[4].second, var);
        var = eeprom_read_byte(&adr[4].minute);
        setPos(ss5e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e1);
      };
      break;
    case ss5e2:
      {
        lcd << F("Timer5:") << eeprom_read_byte(&adr[4].hour) << F(">") << var << F(":") << eeprom_read_byte(&adr[4].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[4].minute, var);
        var = eeprom_read_byte(&adr[4].hour);
        setPos(ss5e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e2);
      };
      break;
    case ss5e3:
      {
        lcd << F("Timer5>") << var << F(":") << eeprom_read_byte(&adr[4].minute) << F(":") << eeprom_read_byte(&adr[4].second);
      }
      Btn.Do      = [] {
        eeprom_write_byte(&adr[4].hour, var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e3);
      };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  saveZeroSettings();
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Тоже самое но чуть попроще в чтении скетча

/**/
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer] = { // начальные настройки
    {1, 10, 11},// 1-й таймер
    {2, 20, 22},// 2-й таймер
    {3, 30, 33},// 3-й таймер
    {4, 40, 44},// 4-й таймер
    {5, 50, 55} // 5-й таймер
  };
  for (int i = 0; i < numTimer; ++i) {
    eeprom_write_byte(&adr[i].hour  , data[i].hour);
    eeprom_write_byte(&adr[i].minute, data[i].minute);
    eeprom_write_byte(&adr[i].second, data[i].second);
  }
}
class Cl_Timer {
  private:
    timer_t * adr;
  public:
    Cl_Timer(timer_t * a): adr(a) {}
    void init() {}
    void run() {}
    byte hour() {
      return eeprom_read_byte(&(adr->hour));
    }
    byte minute() {
      return eeprom_read_byte(&(adr->minute));
    }
    byte second() {
      return eeprom_read_byte(&(adr->second));
    }
    void writeHour(byte data) {
      eeprom_write_byte(&(adr->hour), data);
    }
    void writeMinute(byte data) {
      eeprom_write_byte(&(adr->minute), data);
    }
    void writeSecond(byte data) {
      eeprom_write_byte(&(adr->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(&adr[0]), // 1-й таймер
  Cl_Timer(&adr[1]), // 2-й таймер
  Cl_Timer(&adr[2]), // 3-й таймер
  Cl_Timer(&adr[3]), // 4-й таймер
  Cl_Timer(&adr[4])  // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------------lcd---------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte sMain   = 0;// главный экран
const byte ss1     = 1;// 1-экран
const byte ss1e1   = 2;// редактирование 1
const byte ss1e2   = 3;// редактирование 2
const byte ss1e3   = 4;// редактирование 3
const byte ss2     = 5;// 2-экран
const byte ss2e1   = 6;// редактирование 1
const byte ss2e2   = 7;// редактирование 2
const byte ss2e3   = 8;// редактирование 3
const byte ss3     = 9;// 3-экран
const byte ss3e1   = 10;// редактирование 1
const byte ss3e2   = 11;// редактирование 2
const byte ss3e3   = 12;// редактирование 3
const byte ss4     = 13;// 4-экран
const byte ss4e1   = 14;// редактирование 1
const byte ss4e2   = 15;// редактирование 2
const byte ss4e3   = 16;// редактирование 3
const byte ss5     = 17;// 5-экран
const byte ss5e1   = 18;// редактирование 1
const byte ss5e2   = 19;// редактирование 2
const byte ss5e3   = 20;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { unsigned long now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd << F("Time:") << hour << F(":") << minute << F(":") << second;
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << Timer[0].hour() << F(":") << Timer[0].minute() << F(":") << Timer[0].second();
      }
      Btn.Do    = [] {
        var = Timer[0].second();
        setPos(ss1e1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1e1:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour() << F(":") << Timer[0].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[0].writeSecond(var);
        var = Timer[0].minute();
        setPos(ss1e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e1);
      };
      break;
    case ss1e2:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour() <<  F(">") << var  << F(":") << Timer[0].second();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute(var);
        var = Timer[0].hour();
        setPos(ss1e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e2);
      };
      break;
    case ss1e3:// редактирование часов
      {
        lcd << F("Timer1>") << var << F(":") << Timer[0].minute() << F(":") << Timer[0].second();
      }
      Btn.Do      = [] {
        Timer[0].writeHour(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e3);
      };
      break;
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << Timer[1].hour() << F(":") << Timer[1].minute() << F(":") << Timer[1].second();
      }
      Btn.Do    = [] {
        var = Timer[1].second();
        setPos(ss2e1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2e1:
      {
        lcd << F("Timer2:") << Timer[1].hour() << F(":") << Timer[1].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[1].writeSecond(var);
        var = Timer[1].minute();
        setPos(ss2e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e1);
      };
      break;
    case ss2e2:
      {
        lcd << F("Timer2:") << Timer[1].hour() << F(">") << var  << F(":") << Timer[1].second();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute(var);
        var = Timer[1].hour();
        setPos(ss2e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e2);
      };
      break;
    case ss2e3:
      {
        lcd << F("Timer2>") << var << F(":") << Timer[1].minute() << F(":") << Timer[1].second();
      }
      Btn.Do      = [] {
        Timer[1].writeHour(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e3);
      };
      break;
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << Timer[2].hour() << F(":") << Timer[2].minute() << F(":") << Timer[2].second();
      }
      Btn.Do    = [] {
        var = Timer[2].second();
        setPos(ss3e1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3e1:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour() << F(":") << Timer[2].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[2].writeSecond(var);
        var = Timer[2].minute();
        setPos(ss3e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e1);
      };
      break;
    case ss3e2:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour() <<  F(">") << var << F(":") << Timer[2].second();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute(var);
        var = Timer[2].hour();
        setPos(ss3e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e2);
      };
      break;
    case ss3e3:// редакт часов
      {
        lcd << F("Timer3>") << var << F(":") << Timer[2].minute() << F(":") << Timer[2].second();
      }
      Btn.Do      = [] {
        Timer[2].writeHour(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e3);
      };
      break;
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << Timer[3].hour() << F(":") << Timer[3].minute() << F(":") << Timer[3].second();
      }
      Btn.Do    = [] {
        var = Timer[3].second();
        setPos(ss4e1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4e1:
      {
        lcd << F("Timer4:") << Timer[3].hour() << F(":") << Timer[3].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[3].writeSecond(var);
        var = Timer[3].minute();
        setPos(ss4e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e1);
      };
      break;
    case ss4e2:
      {
        lcd << F("Timer4:") << Timer[3].hour() << F(">") << var << F(":") << Timer[3].second();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute(var);
        var = Timer[3].hour();
        setPos(ss4e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e2);
      };
      break;
    case ss4e3:
      {
        lcd << F("Timer4>") << var << F(":") << Timer[3].minute() << F(":") << Timer[3].second();
      }
      Btn.Do      = [] {
        Timer[3].writeHour(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e3);
      };
      break;
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << Timer[4].hour() << F(":") << Timer[4].minute() << F(":") << Timer[4].second();
      }
      Btn.Do    = [] {
        var = Timer[4].second();
        setPos(ss5e1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5e1:
      {
        lcd << F("Timer5:") << Timer[4].hour() << F(":") << Timer[4].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[4].writeSecond(var);
        var = Timer[4].minute();
        setPos(ss5e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e1);
      };
      break;
    case ss5e2:
      {
        lcd << F("Timer5:") << Timer[4].hour() <<  F(">") << var  << F(":") << Timer[4].second();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute(var);
        var = Timer[4].hour();
        setPos(ss5e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e2);
      };
      break;
    case ss5e3:
      {
        lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute() << F(":") << Timer[4].second();
      }
      Btn.Do      = [] {
        Timer[4].writeHour(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e3);
      };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++) Timer[i].init();
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  for (int i = 0; i < numTimer; i++) Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
unsigned long now ;// количество секунд прошедшее после вкл
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer] = { // начальные настройки
    {0, 0, 30},// 1-й таймер
    {0, 1, 00},// 2-й таймер
    {0, 1, 30},// 3-й таймер
    {0, 2, 00},// 4-й таймер
    {0, 2, 30} // 5-й таймер
  };
  for (int i = 0; i < numTimer; ++i) {
    eeprom_write_byte(&adr[i].hour  , data[i].hour);
    eeprom_write_byte(&adr[i].minute, data[i].minute);
    eeprom_write_byte(&adr[i].second, data[i].second);
  }
}
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Timer {
  private:
    timer_t * adr;
    byte stat;// состояние
    unsigned long past;
    void setStat(byte s) {
      stat = s;
      past = millis();
      switch (s) {
        case sOFF: break;
        case  sON: break;
        case  sEND: break;
      }
    }
  public:
    Cl_Timer(timer_t * a): adr(a) {}
    void init() {
      setStat(sOFF);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (stat) {
          case sOFF:
            if (now >= ((unsigned long)hour() * 24 + minute()) * 60 + second())setStat(sON);
            break;
          case  sON:
            setStat(sON);
            break;
          case  sEND:
            setStat(sEND);
            break;
        }
      }
    }
    void state() {
      switch (stat) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
    byte hour() {
      return eeprom_read_byte(&(adr->hour));
    }
    byte minute() {
      return eeprom_read_byte(&(adr->minute));
    }
    byte second() {
      return eeprom_read_byte(&(adr->second));
    }
    void writeHour(byte data) {
      eeprom_write_byte(&(adr->hour), data);
    }
    void writeMinute(byte data) {
      eeprom_write_byte(&(adr->minute), data);
    }
    void writeSecond(byte data) {
      eeprom_write_byte(&(adr->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(&adr[0]), // 1-й таймер
  Cl_Timer(&adr[1]), // 2-й таймер
  Cl_Timer(&adr[2]), // 3-й таймер
  Cl_Timer(&adr[3]), // 4-й таймер
  Cl_Timer(&adr[4])  // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
const byte sMain   = 0;// главный экран
const byte ss1     = 1;// 1-экран
const byte ss1e1   = 2;// редактирование 1
const byte ss1e2   = 3;// редактирование 2
const byte ss1e3   = 4;// редактирование 3
const byte ss2     = 5;// 2-экран
const byte ss2e1   = 6;// редактирование 1
const byte ss2e2   = 7;// редактирование 2
const byte ss2e3   = 8;// редактирование 3
const byte ss3     = 9;// 3-экран
const byte ss3e1   = 10;// редактирование 1
const byte ss3e2   = 11;// редактирование 2
const byte ss3e3   = 12;// редактирование 3
const byte ss4     = 13;// 4-экран
const byte ss4e1   = 14;// редактирование 1
const byte ss4e2   = 15;// редактирование 2
const byte ss4e3   = 16;// редактирование 3
const byte ss5     = 17;// 5-экран
const byte ss5e1   = 18;// редактирование 1
const byte ss5e2   = 19;// редактирование 2
const byte ss5e3   = 20;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd  << hour << F(":") << minute << F(":") << second;
        lcd.setCursor(9, 0);
        Timer[0].state(); lcd << F(" ");
        Timer[1].state(); lcd << F(" ");
        lcd.setCursor(5, 1);
        Timer[2].state(); lcd << F(" ");
        Timer[3].state(); lcd << F(" ");
        Timer[4].state(); lcd << F(" ");
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << Timer[0].hour() << F(":") << Timer[0].minute() << F(":") << Timer[0].second();
      }
      Btn.Do    = [] {
        var = Timer[0].second();
        setPos(ss1e1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1e1:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour() << F(":") << Timer[0].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[0].writeSecond(var);
        var = Timer[0].minute();
        setPos(ss1e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e1);
      };
      break;
    case ss1e2:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour() <<  F(">") << var  << F(":") << Timer[0].second();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute(var);
        var = Timer[0].hour();
        setPos(ss1e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e2);
      };
      break;
    case ss1e3:// редактирование часов
      {
        lcd << F("Timer1>") << var << F(":") << Timer[0].minute() << F(":") << Timer[0].second();
      }
      Btn.Do      = [] {
        Timer[0].writeHour(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1e3);
      };
      break;
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << Timer[1].hour() << F(":") << Timer[1].minute() << F(":") << Timer[1].second();
      }
      Btn.Do    = [] {
        var = Timer[1].second();
        setPos(ss2e1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2e1:
      {
        lcd << F("Timer2:") << Timer[1].hour() << F(":") << Timer[1].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[1].writeSecond(var);
        var = Timer[1].minute();
        setPos(ss2e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e1);
      };
      break;
    case ss2e2:
      {
        lcd << F("Timer2:") << Timer[1].hour() << F(">") << var  << F(":") << Timer[1].second();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute(var);
        var = Timer[1].hour();
        setPos(ss2e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e2);
      };
      break;
    case ss2e3:
      {
        lcd << F("Timer2>") << var << F(":") << Timer[1].minute() << F(":") << Timer[1].second();
      }
      Btn.Do      = [] {
        Timer[1].writeHour(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2e3);
      };
      break;
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << Timer[2].hour() << F(":") << Timer[2].minute() << F(":") << Timer[2].second();
      }
      Btn.Do    = [] {
        var = Timer[2].second();
        setPos(ss3e1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3e1:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour() << F(":") << Timer[2].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[2].writeSecond(var);
        var = Timer[2].minute();
        setPos(ss3e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e1);
      };
      break;
    case ss3e2:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour() <<  F(">") << var << F(":") << Timer[2].second();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute(var);
        var = Timer[2].hour();
        setPos(ss3e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e2);
      };
      break;
    case ss3e3:// редакт часов
      {
        lcd << F("Timer3>") << var << F(":") << Timer[2].minute() << F(":") << Timer[2].second();
      }
      Btn.Do      = [] {
        Timer[2].writeHour(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3e3);
      };
      break;
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << Timer[3].hour() << F(":") << Timer[3].minute() << F(":") << Timer[3].second();
      }
      Btn.Do    = [] {
        var = Timer[3].second();
        setPos(ss4e1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4e1:
      {
        lcd << F("Timer4:") << Timer[3].hour() << F(":") << Timer[3].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[3].writeSecond(var);
        var = Timer[3].minute();
        setPos(ss4e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e1);
      };
      break;
    case ss4e2:
      {
        lcd << F("Timer4:") << Timer[3].hour() << F(">") << var << F(":") << Timer[3].second();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute(var);
        var = Timer[3].hour();
        setPos(ss4e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e2);
      };
      break;
    case ss4e3:
      {
        lcd << F("Timer4>") << var << F(":") << Timer[3].minute() << F(":") << Timer[3].second();
      }
      Btn.Do      = [] {
        Timer[3].writeHour(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4e3);
      };
      break;
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << Timer[4].hour() << F(":") << Timer[4].minute() << F(":") << Timer[4].second();
      }
      Btn.Do    = [] {
        var = Timer[4].second();
        setPos(ss5e1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5e1:
      {
        lcd << F("Timer5:") << Timer[4].hour() << F(":") << Timer[4].minute() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[4].writeSecond(var);
        var = Timer[4].minute();
        setPos(ss5e2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5e1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e1);
      };
      break;
    case ss5e2:
      {
        lcd << F("Timer5:") << Timer[4].hour() <<  F(">") << var  << F(":") << Timer[4].second();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute(var);
        var = Timer[4].hour();
        setPos(ss5e3);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5e2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e2);
      };
      break;
    case ss5e3:
      {
        lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute() << F(":") << Timer[4].second();
      }
      Btn.Do      = [] {
        Timer[4].writeHour(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5e3);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5e3);
      };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++) Timer[i].init();
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  for (int i = 0; i < numTimer; i++) Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
unsigned long now ;// количество секунд прошедшее после вкл
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr1[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer * 2] = { // начальные настройки
    {0, 0, 30}, {0, 3, 00}, // 1-й таймер
    {0, 1, 00}, {0, 3, 30}, // 2-й таймер
    {0, 1, 30}, {0, 4, 00}, // 3-й таймер
    {0, 2, 00}, {0, 4, 30}, // 4-й таймер
    {0, 2, 30}, {0, 5, 00}  // 5-й таймер
  };
  for (int i = 0; i < numTimer * 2; ++i) {
    eeprom_write_byte(&adr1[i].hour  , data[i].hour);
    eeprom_write_byte(&adr1[i].minute, data[i].minute);
    eeprom_write_byte(&adr1[i].second, data[i].second);
  }
}
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Timer {
  private:
    timer_t *adr1, *adr2;
    byte stat;// состояние
    unsigned long past;
    void setStat(byte s) {
      stat = s;
      past = millis();
      switch (s) {
        case sOFF: break;
        case  sON: break;
        case  sEND: break;
      }
    }
  public:
    Cl_Timer(timer_t * a1, timer_t * a2): adr1(a1), adr2(a2) {}
    void init() {
      setStat(sOFF);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (stat) {
          case sOFF:
            if (now >= ((unsigned long)hour1() * 24 + minute1()) * 60 + second1())setStat(sON);
            break;
          case  sON:
            setStat(sON);
            break;
          case  sEND:
            setStat(sEND);
            break;
        }
      }
    }
    void state() {
      switch (stat) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
    byte hour1() {
      return eeprom_read_byte(&(adr1->hour));
    }
    byte minute1() {
      return eeprom_read_byte(&(adr1->minute));
    }
    byte second1() {
      return eeprom_read_byte(&(adr1->second));
    }
    void writeHour1(byte data) {
      eeprom_write_byte(&(adr1->hour), data);
    }
    void writeMinute1(byte data) {
      eeprom_write_byte(&(adr1->minute), data);
    }
    void writeSecond1(byte data) {
      eeprom_write_byte(&(adr1->second), data);
    }
    byte hour2() {
      return eeprom_read_byte(&(adr2->hour));
    }
    byte minute2() {
      return eeprom_read_byte(&(adr2->minute));
    }
    byte second2() {
      return eeprom_read_byte(&(adr2->second));
    }
    void writeHour2(byte data) {
      eeprom_write_byte(&(adr2->hour), data);
    }
    void writeMinute2(byte data) {
      eeprom_write_byte(&(adr2->minute), data);
    }
    void writeSecond2(byte data) {
      eeprom_write_byte(&(adr2->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(&adr1[0], &adr1[1]), // 1-й таймер
  Cl_Timer(&adr1[2], &adr1[3]), // 2-й таймер
  Cl_Timer(&adr1[4], &adr1[5]), // 3-й таймер
  Cl_Timer(&adr1[6], &adr1[7]), // 4-й таймер
  Cl_Timer(&adr1[8], &adr1[9])  // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
const byte sMain      = 0;// главный экран

const byte ss1        = 1;// 1-экран
const byte ss1sec1    = 2;// редактирование 1
const byte ss1min1    = 3;// редактирование 2
const byte ss1hour1   = 4;// редактирование 3
const byte ss1sec2    = 5;// редактирование 1
const byte ss1min2    = 6;// редактирование 2
const byte ss1hour2   = 7;// редактирование 3

const byte ss2        = 11;// 2-экран
const byte ss2sec1    = 12;// редактирование 1
const byte ss2min1    = 13;// редактирование 2
const byte ss2hour1   = 14;// редактирование 3
const byte ss2sec2    = 15;// редактирование 1
const byte ss2min2    = 16;// редактирование 2
const byte ss2hour2   = 17;// редактирование 3


const byte ss3        = 21;// 3-экран
const byte ss3sec1    = 22;// редактирование 1
const byte ss3min1    = 23;// редактирование 2
const byte ss3hour1   = 24;// редактирование 3
const byte ss3sec2    = 25;// редактирование 1
const byte ss3min2    = 26;// редактирование 2
const byte ss3hour2   = 27;// редактирование 3

const byte ss4        = 31;// 4-экран
const byte ss4sec1    = 32;// редактирование 1
const byte ss4min1    = 33;// редактирование 2
const byte ss4hour1   = 34;// редактирование 3
const byte ss4sec2    = 35;// редактирование 1
const byte ss4min2    = 36;// редактирование 2
const byte ss4hour2   = 37;// редактирование 3

const byte ss5        = 41;// 5-экран
const byte ss5sec1    = 42;// редактирование 1
const byte ss5min1    = 43;// редактирование 2
const byte ss5hour1   = 44;// редактирование 3
const byte ss5sec2    = 45;// редактирование 1
const byte ss5min2    = 46;// редактирование 2
const byte ss5hour2   = 47;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd  << hour << F(":") << minute << F(":") << second;
        lcd.setCursor(9, 0);
        Timer[0].state(); lcd << F(" ");
        Timer[1].state(); lcd << F(" ");
        lcd.setCursor(5, 1);
        Timer[2].state(); lcd << F(" ");
        Timer[3].state(); lcd << F(" ");
        Timer[4].state(); lcd << F(" ");
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do    = [] {
        var = Timer[0].second1();
        setPos(ss1sec1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1sec1:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond1(var);
        var = Timer[0].minute1();
        setPos(ss1min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec1);
      };
      break;
    case ss1min1:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour1() <<  F(">") << var  << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute1(var);
        var = Timer[0].hour1();
        setPos(ss1hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min1);
      };
      break;
    case ss1hour1:// редактирование часов
      {
        lcd << F("Timer1>") << var << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeHour1(var);
        setPos(ss1sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour1);
      };
      break;
    case ss1sec2:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[0].writeSecond2(var);
        var = Timer[0].minute2();
        setPos(ss1min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec2);
      };
      break;
    case ss1min2:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") <<  Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(">") << var                 << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute2(var);
        var = Timer[0].hour2();
        setPos(ss1hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min2);
      };
      break;
    case ss1hour2:// редактирование часов
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeHour2(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do    = [] {
        var = Timer[1].second1();
        setPos(ss2sec1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2sec1:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond1(var);
        var = Timer[1].minute1();
        setPos(ss2min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec1);
      };
      break;
    case ss2min1:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(">") << var  << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute1(var);
        var = Timer[1].hour1();
        setPos(ss2hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min1);
      };
      break;
    case ss2hour1:
      {
        lcd << F("Timer2>") << var << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeHour1(var);
        var = Timer[1].second2();
        setPos(ss2sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour1);
      };
      break;
    case ss2sec2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[1].writeSecond2(var);
        var = Timer[1].minute2();
        setPos(ss2min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec2);
      };
      break;
    case ss2min2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(">") << var                << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute2(var);
        var = Timer[1].hour2();
        setPos(ss2hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min2);
      };
      break;
    case ss2hour2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeHour2(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do    = [] {
        var = Timer[2].second1();
        setPos(ss3sec1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3sec1:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond1(var);
        var = Timer[2].minute1();
        setPos(ss3min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec1);
      };
      break;
    case ss3min1:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour1() <<  F(">") << var               << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute1(var);
        var = Timer[2].hour1();
        setPos(ss3hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min1);
      };
      break;
    case ss3hour1:// редакт часов
      {
        lcd << F("Timer3>") << var              << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeHour1(var);
        var = Timer[2].second2();
        setPos(ss3sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour1);
      };
      break;
    case ss3sec2:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[2].writeSecond2(var);
        var = Timer[2].minute2();
        setPos(ss3min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec2);
      };
      break;
    case ss3min2:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(">") << var                << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute2(var);
        var = Timer[2].hour2();
        setPos(ss3hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min2);
      };
      break;
    case ss3hour2:// редакт часов
      {
        lcd << F("Timer3:") << Timer[2].hour1()  << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var               << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeHour2(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do    = [] {
        var = Timer[3].second1();
        setPos(ss4sec1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4sec1:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond1(var);
        var = Timer[3].minute1();
        setPos(ss4min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec1);
      };
      break;
    case ss4min1:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(">") << var                << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute1(var);
        var = Timer[3].hour1();
        setPos(ss4hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min1);
      };
      break;
    case ss4hour1:
      {
        lcd << F("Timer4>") << var << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeHour1(var);
        var = Timer[3].second2();
        setPos(ss4sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour1);
      };
      break;
    case ss4sec2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[3].writeSecond2(var);
        var = Timer[3].minute2();
        setPos(ss4min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec2);
      };
      break;
    case ss4min2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(">") << var                << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute2(var);
        var = Timer[3].hour2();
        setPos(ss4hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min2);
      };
      break;
    case ss4hour2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeHour2(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do    = [] {
        var = Timer[4].second1();
        setPos(ss5sec1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5sec1:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond1(var);
        var = Timer[4].minute1();
        setPos(ss5min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec1);
      };
      break;
    case ss5min1:
      {
        lcd << F("Timer5:") << Timer[4].hour1() <<  F(">") << var  << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute1(var);
        var = Timer[4].hour1();
        setPos(ss5hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min1);
      };
      break;
    case ss5hour1:
      {
        lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeHour1(var);
        var = Timer[4].second2();
        setPos(ss5sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour1);
      };
      break;
    case ss5sec2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() <<  F(">") << var;
      }
      Btn.Do      = [] {
        Timer[4].writeSecond2(var);
        var = Timer[4].minute2();
        setPos(ss5min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec2);
      };
      break;
    case ss5min2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(">") << var                << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute2(var);
        var = Timer[4].hour2();
        setPos(ss5hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min2);
      };
      break;
    case ss5hour2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeHour2(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour2);
      };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++) Timer[i].init();
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  for (int i = 0; i < numTimer; i++) Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Подключим 5 реле на таймеры и получим.

/**/
unsigned long now ;// количество секунд прошедшее после вкл
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr1[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer * 2] = { // начальные настройки
    {0, 0, 30}, {0, 3, 00}, // 1-й таймер
    {0, 1, 00}, {0, 3, 30}, // 2-й таймер
    {0, 1, 30}, {0, 4, 00}, // 3-й таймер
    {0, 2, 00}, {0, 4, 30}, // 4-й таймер
    {0, 2, 30}, {0, 5, 00}  // 5-й таймер
  };
  for (int i = 0; i < numTimer * 2; ++i) {
    eeprom_write_byte(&adr1[i].hour  , data[i].hour);
    eeprom_write_byte(&adr1[i].minute, data[i].minute);
    eeprom_write_byte(&adr1[i].second, data[i].second);
  }
}
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Timer {
  private:
    timer_t *adr1, *adr2;
    byte pin;
    byte stat;// состояние
    unsigned long past;
    void setStat(byte s) {
      stat = s;
      past = millis();
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case  sON:
          digitalWrite(pin, LOW);
          break;
        case  sEND:
          digitalWrite(pin, HIGH);

          break;
      }
    }
  public:
    Cl_Timer(byte p, timer_t * a1, timer_t * a2)
      :  adr1(a1), adr2(a2), pin(p) {}
    void init() {
      pinMode(pin, OUTPUT);
      setStat(sOFF);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (stat) {
          case sOFF:
            if (now >= ((unsigned long)hour1() * 24 + minute1()) * 60 + second1())setStat(sON);
            else setStat(sOFF);
            break;
          case  sON:
            if (now >= ((unsigned long)hour2() * 24 + minute2()) * 60 + second2())setStat(sEND);
            else setStat(sON);
            break;
          case  sEND:
            setStat(sEND);
            break;
        }
      }
    }
    void state() {
      switch (stat) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
    byte hour1() {
      return eeprom_read_byte(&(adr1->hour));
    }
    byte minute1() {
      return eeprom_read_byte(&(adr1->minute));
    }
    byte second1() {
      return eeprom_read_byte(&(adr1->second));
    }
    void writeHour1(byte data) {
      eeprom_write_byte(&(adr1->hour), data);
    }
    void writeMinute1(byte data) {
      eeprom_write_byte(&(adr1->minute), data);
    }
    void writeSecond1(byte data) {
      eeprom_write_byte(&(adr1->second), data);
    }
    byte hour2() {
      return eeprom_read_byte(&(adr2->hour));
    }
    byte minute2() {
      return eeprom_read_byte(&(adr2->minute));
    }
    byte second2() {
      return eeprom_read_byte(&(adr2->second));
    }
    void writeHour2(byte data) {
      eeprom_write_byte(&(adr2->hour), data);
    }
    void writeMinute2(byte data) {
      eeprom_write_byte(&(adr2->minute), data);
    }
    void writeSecond2(byte data) {
      eeprom_write_byte(&(adr2->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(/*пин*/2, &adr1[0], &adr1[1]), // 1-й таймер
  Cl_Timer(/*пин*/3, &adr1[2], &adr1[3]), // 2-й таймер
  Cl_Timer(/*пин*/4, &adr1[4], &adr1[5]), // 3-й таймер
  Cl_Timer(/*пин*/5, &adr1[6], &adr1[7]), // 4-й таймер
  Cl_Timer(/*пин*/6, &adr1[8], &adr1[9]) // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
const byte sMain      = 0;// главный экран

const byte ss1        = 1;// 1-экран
const byte ss1sec1    = 2;// редактирование 1
const byte ss1min1    = 3;// редактирование 2
const byte ss1hour1   = 4;// редактирование 3
const byte ss1sec2    = 5;// редактирование 1
const byte ss1min2    = 6;// редактирование 2
const byte ss1hour2   = 7;// редактирование 3

const byte ss2        = 11;// 2-экран
const byte ss2sec1    = 12;// редактирование 1
const byte ss2min1    = 13;// редактирование 2
const byte ss2hour1   = 14;// редактирование 3
const byte ss2sec2    = 15;// редактирование 1
const byte ss2min2    = 16;// редактирование 2
const byte ss2hour2   = 17;// редактирование 3


const byte ss3        = 21;// 3-экран
const byte ss3sec1    = 22;// редактирование 1
const byte ss3min1    = 23;// редактирование 2
const byte ss3hour1   = 24;// редактирование 3
const byte ss3sec2    = 25;// редактирование 1
const byte ss3min2    = 26;// редактирование 2
const byte ss3hour2   = 27;// редактирование 3

const byte ss4        = 31;// 4-экран
const byte ss4sec1    = 32;// редактирование 1
const byte ss4min1    = 33;// редактирование 2
const byte ss4hour1   = 34;// редактирование 3
const byte ss4sec2    = 35;// редактирование 1
const byte ss4min2    = 36;// редактирование 2
const byte ss4hour2   = 37;// редактирование 3

const byte ss5        = 41;// 5-экран
const byte ss5sec1    = 42;// редактирование 1
const byte ss5min1    = 43;// редактирование 2
const byte ss5hour1   = 44;// редактирование 3
const byte ss5sec2    = 45;// редактирование 1
const byte ss5min2    = 46;// редактирование 2
const byte ss5hour2   = 47;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd  << hour << F(":") << minute << F(":") << second;
        lcd.setCursor(9, 0);
        Timer[0].state(); lcd << F(" ");
        Timer[1].state(); lcd << F(" ");
        lcd.setCursor(5, 1);
        Timer[2].state(); lcd << F(" ");
        Timer[3].state(); lcd << F(" ");
        Timer[4].state(); lcd << F(" ");
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do    = [] {
        var = Timer[0].second1();
        setPos(ss1sec1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1sec1:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond1(var);
        var = Timer[0].minute1();
        setPos(ss1min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec1);
      };
      break;
    case ss1min1:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour1() <<  F(">") << var  << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute1(var);
        var = Timer[0].hour1();
        setPos(ss1hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min1);
      };
      break;
    case ss1hour1:// редактирование часов
      {
        lcd << F("Timer1>") << var << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeHour1(var);
        setPos(ss1sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour1);
      };
      break;
    case ss1sec2:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[0].writeSecond2(var);
        var = Timer[0].minute2();
        setPos(ss1min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec2);
      };
      break;
    case ss1min2:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") <<  Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(">") << var                 << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute2(var);
        var = Timer[0].hour2();
        setPos(ss1hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min2);
      };
      break;
    case ss1hour2:// редактирование часов
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
      }
      Btn.Do      = [] {
        Timer[0].writeHour2(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do    = [] {
        var = Timer[1].second1();
        setPos(ss2sec1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2sec1:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond1(var);
        var = Timer[1].minute1();
        setPos(ss2min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec1);
      };
      break;
    case ss2min1:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(">") << var  << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute1(var);
        var = Timer[1].hour1();
        setPos(ss2hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min1);
      };
      break;
    case ss2hour1:
      {
        lcd << F("Timer2>") << var << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeHour1(var);
        var = Timer[1].second2();
        setPos(ss2sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour1);
      };
      break;
    case ss2sec2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[1].writeSecond2(var);
        var = Timer[1].minute2();
        setPos(ss2min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec2);
      };
      break;
    case ss2min2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(">") << var                << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute2(var);
        var = Timer[1].hour2();
        setPos(ss2hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min2);
      };
      break;
    case ss2hour2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
      }
      Btn.Do      = [] {
        Timer[1].writeHour2(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do    = [] {
        var = Timer[2].second1();
        setPos(ss3sec1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3sec1:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond1(var);
        var = Timer[2].minute1();
        setPos(ss3min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec1);
      };
      break;
    case ss3min1:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour1() <<  F(">") << var               << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute1(var);
        var = Timer[2].hour1();
        setPos(ss3hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min1);
      };
      break;
    case ss3hour1:// редакт часов
      {
        lcd << F("Timer3>") << var              << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeHour1(var);
        var = Timer[2].second2();
        setPos(ss3sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour1);
      };
      break;
    case ss3sec2:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[2].writeSecond2(var);
        var = Timer[2].minute2();
        setPos(ss3min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec2);
      };
      break;
    case ss3min2:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(">") << var                << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute2(var);
        var = Timer[2].hour2();
        setPos(ss3hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min2);
      };
      break;
    case ss3hour2:// редакт часов
      {
        lcd << F("Timer3:") << Timer[2].hour1()  << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var               << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
      }
      Btn.Do      = [] {
        Timer[2].writeHour2(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do    = [] {
        var = Timer[3].second1();
        setPos(ss4sec1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4sec1:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond1(var);
        var = Timer[3].minute1();
        setPos(ss4min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec1);
      };
      break;
    case ss4min1:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(">") << var                << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute1(var);
        var = Timer[3].hour1();
        setPos(ss4hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min1);
      };
      break;
    case ss4hour1:
      {
        lcd << F("Timer4>") << var << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeHour1(var);
        var = Timer[3].second2();
        setPos(ss4sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour1);
      };
      break;
    case ss4sec2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(">") << var;
      }
      Btn.Do      = [] {
        Timer[3].writeSecond2(var);
        var = Timer[3].minute2();
        setPos(ss4min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec2);
      };
      break;
    case ss4min2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(">") << var                << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute2(var);
        var = Timer[3].hour2();
        setPos(ss4hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min2);
      };
      break;
    case ss4hour2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
      }
      Btn.Do      = [] {
        Timer[3].writeHour2(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do    = [] {
        var = Timer[4].second1();
        setPos(ss5sec1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5sec1:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond1(var);
        var = Timer[4].minute1();
        setPos(ss5min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec1);
      };
      break;
    case ss5min1:
      {
        lcd << F("Timer5:") << Timer[4].hour1() <<  F(">") << var  << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute1(var);
        var = Timer[4].hour1();
        setPos(ss5hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min1);
      };
      break;
    case ss5hour1:
      {
        lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeHour1(var);
        var = Timer[4].second2();
        setPos(ss5sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour1);
      };
      break;
    case ss5sec2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() <<  F(">") << var;
      }
      Btn.Do      = [] {
        Timer[4].writeSecond2(var);
        var = Timer[4].minute2();
        setPos(ss5min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec2);
      };
      break;
    case ss5min2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(">") << var                << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute2(var);
        var = Timer[4].hour2();
        setPos(ss5hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min2);
      };
      break;
    case ss5hour2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
      }
      Btn.Do      = [] {
        Timer[4].writeHour2(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour2);
      };
      break;
  }
}
void menuInit() {
  lcd.begin(16, 2);
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++) Timer[i].init();
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  for (int i = 0; i < numTimer; i++) Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Моя упрощенная библиотека для работы с lcd1602 i2c

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);
//--------------------------------------------------
void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(5, 0);
  lcd << F("ABCD");
  lcd.setCursor(8, 1);
  lcd << F("EFGH");
  lcd.show();
}
void loop() {
}
/**/

Я планирую позже использовать ее,так как она уменьшает мигание дисплея.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

И вот с этой библиотекой код. И да если вы будете ее использовать,то не забывайте использовать команды clear() -очистка буфера и show()- отправка этого буфера в память дисплея

/**/
unsigned long now ;// количество секунд прошедшее после вкл
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr1[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer * 2] = { // начальные настройки
    {0, 0, 30}, {0, 3, 00}, // 1-й таймер
    {0, 1, 00}, {0, 3, 30}, // 2-й таймер
    {0, 1, 30}, {0, 4, 00}, // 3-й таймер
    {0, 2, 00}, {0, 4, 30}, // 4-й таймер
    {0, 2, 30}, {0, 5, 00}  // 5-й таймер
  };
  for (int i = 0; i < numTimer * 2; ++i) {
    eeprom_write_byte(&adr1[i].hour  , data[i].hour);
    eeprom_write_byte(&adr1[i].minute, data[i].minute);
    eeprom_write_byte(&adr1[i].second, data[i].second);
  }
}
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Timer {
  private:
    timer_t *adr1, *adr2;
    byte pin;
    byte stat;// состояние
    unsigned long past;
    void setStat(byte s) {
      stat = s;
      past = millis();
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case  sON:
          digitalWrite(pin, LOW);
          break;
        case  sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    Cl_Timer(byte p, timer_t * a1, timer_t * a2)
      :  adr1(a1), adr2(a2), pin(p) {}
    void init() {
      pinMode(pin, OUTPUT);
      setStat(sOFF);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (stat) {
          case sOFF:
            if (now >= ((unsigned long)hour1() * 24 + minute1()) * 60 + second1())setStat(sON);
            else setStat(sOFF);
            break;
          case  sON:
            if (now >= ((unsigned long)hour2() * 24 + minute2()) * 60 + second2())setStat(sEND);
            else setStat(sON);
            break;
          case  sEND:
            setStat(sEND);
            break;
        }
      }
    }
    void state() {
      switch (stat) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
    byte hour1() {
      return eeprom_read_byte(&(adr1->hour));
    }
    byte minute1() {
      return eeprom_read_byte(&(adr1->minute));
    }
    byte second1() {
      return eeprom_read_byte(&(adr1->second));
    }
    void writeHour1(byte data) {
      eeprom_write_byte(&(adr1->hour), data);
    }
    void writeMinute1(byte data) {
      eeprom_write_byte(&(adr1->minute), data);
    }
    void writeSecond1(byte data) {
      eeprom_write_byte(&(adr1->second), data);
    }
    byte hour2() {
      return eeprom_read_byte(&(adr2->hour));
    }
    byte minute2() {
      return eeprom_read_byte(&(adr2->minute));
    }
    byte second2() {
      return eeprom_read_byte(&(adr2->second));
    }
    void writeHour2(byte data) {
      eeprom_write_byte(&(adr2->hour), data);
    }
    void writeMinute2(byte data) {
      eeprom_write_byte(&(adr2->minute), data);
    }
    void writeSecond2(byte data) {
      eeprom_write_byte(&(adr2->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(/*пин*/2, &adr1[0], &adr1[1]), // 1-й таймер
  Cl_Timer(/*пин*/3, &adr1[2], &adr1[3]), // 2-й таймер
  Cl_Timer(/*пин*/4, &adr1[4], &adr1[5]), // 3-й таймер
  Cl_Timer(/*пин*/5, &adr1[6], &adr1[7]), // 4-й таймер
  Cl_Timer(/*пин*/6, &adr1[8], &adr1[9]) // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
const byte sMain      = 0;// главный экран

const byte ss1        = 1;// 1-экран
const byte ss1sec1    = 2;// редактирование 1
const byte ss1min1    = 3;// редактирование 2
const byte ss1hour1   = 4;// редактирование 3
const byte ss1sec2    = 5;// редактирование 1
const byte ss1min2    = 6;// редактирование 2
const byte ss1hour2   = 7;// редактирование 3

const byte ss2        = 11;// 2-экран
const byte ss2sec1    = 12;// редактирование 1
const byte ss2min1    = 13;// редактирование 2
const byte ss2hour1   = 14;// редактирование 3
const byte ss2sec2    = 15;// редактирование 1
const byte ss2min2    = 16;// редактирование 2
const byte ss2hour2   = 17;// редактирование 3


const byte ss3        = 21;// 3-экран
const byte ss3sec1    = 22;// редактирование 1
const byte ss3min1    = 23;// редактирование 2
const byte ss3hour1   = 24;// редактирование 3
const byte ss3sec2    = 25;// редактирование 1
const byte ss3min2    = 26;// редактирование 2
const byte ss3hour2   = 27;// редактирование 3

const byte ss4        = 31;// 4-экран
const byte ss4sec1    = 32;// редактирование 1
const byte ss4min1    = 33;// редактирование 2
const byte ss4hour1   = 34;// редактирование 3
const byte ss4sec2    = 35;// редактирование 1
const byte ss4min2    = 36;// редактирование 2
const byte ss4hour2   = 37;// редактирование 3

const byte ss5        = 41;// 5-экран
const byte ss5sec1    = 42;// редактирование 1
const byte ss5min1    = 43;// редактирование 2
const byte ss5hour1   = 44;// редактирование 3
const byte ss5sec2    = 45;// редактирование 1
const byte ss5min2    = 46;// редактирование 2
const byte ss5hour2   = 47;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { now = millis() / 1000;
        int hour = now / 60 / 60 % 24 ;
        int minute = now / 60 % 60;
        int second = now % 60;
        lcd  << hour << F(":") << minute << F(":") << second;
        lcd.setCursor(9, 0);
        Timer[0].state(); lcd << F(" ");
        Timer[1].state(); lcd << F(" ");
        lcd.setCursor(5, 1);
        Timer[2].state(); lcd << F(" ");
        Timer[3].state(); lcd << F(" ");
        Timer[4].state(); lcd << F(" ");
        lcd.show();
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[0].second1();
        setPos(ss1sec1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1sec1:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond1(var);
        var = Timer[0].minute1();
        setPos(ss1min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec1);
      };
      break;
    case ss1min1:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour1() <<  F(">") << var  << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute1(var);
        var = Timer[0].hour1();
        setPos(ss1hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min1);
      };
      break;
    case ss1hour1:// редактирование часов
      {
        lcd << F("Timer1>") << var << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeHour1(var);
        setPos(ss1sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour1);
      };
      break;
    case ss1sec2:// редактирование секунд
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond2(var);
        var = Timer[0].minute2();
        setPos(ss1min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec2);
      };
      break;
    case ss1min2:// редактирование минут
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") <<  Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(">") << var                 << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute2(var);
        var = Timer[0].hour2();
        setPos(ss1hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min2);
      };
      break;
    case ss1hour2:// редактирование часов
      {
        lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeHour2(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss2: // 2-экран
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[1].second1();
        setPos(ss2sec1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2sec1:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond1(var);
        var = Timer[1].minute1();
        setPos(ss2min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec1);
      };
      break;
    case ss2min1:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(">") << var  << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute1(var);
        var = Timer[1].hour1();
        setPos(ss2hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min1);
      };
      break;
    case ss2hour1:
      {
        lcd << F("Timer2>") << var << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeHour1(var);
        var = Timer[1].second2();
        setPos(ss2sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour1);
      };
      break;
    case ss2sec2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond2(var);
        var = Timer[1].minute2();
        setPos(ss2min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec2);
      };
      break;
    case ss2min2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(">") << var                << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute2(var);
        var = Timer[1].hour2();
        setPos(ss2hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min2);
      };
      break;
    case ss2hour2:
      {
        lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeHour2(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss3: // 3-экран
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[2].second1();
        setPos(ss3sec1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3sec1:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond1(var);
        var = Timer[2].minute1();
        setPos(ss3min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec1);
      };
      break;
    case ss3min1:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour1() <<  F(">") << var               << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute1(var);
        var = Timer[2].hour1();
        setPos(ss3hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min1);
      };
      break;
    case ss3hour1:// редакт часов
      {
        lcd << F("Timer3>") << var              << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeHour1(var);
        var = Timer[2].second2();
        setPos(ss3sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour1);
      };
      break;
    case ss3sec2:// редакт секунд
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond2(var);
        var = Timer[2].minute2();
        setPos(ss3min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec2);
      };
      break;
    case ss3min2:// редакт минут
      {
        lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(">") << var                << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute2(var);
        var = Timer[2].hour2();
        setPos(ss3hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min2);
      };
      break;
    case ss3hour2:// редакт часов
      {
        lcd << F("Timer3:") << Timer[2].hour1()  << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var               << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeHour2(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss4: // 4-экран
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[3].second1();
        setPos(ss4sec1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4sec1:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond1(var);
        var = Timer[3].minute1();
        setPos(ss4min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec1);
      };
      break;
    case ss4min1:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(">") << var                << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute1(var);
        var = Timer[3].hour1();
        setPos(ss4hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min1);
      };
      break;
    case ss4hour1:
      {
        lcd << F("Timer4>") << var << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeHour1(var);
        var = Timer[3].second2();
        setPos(ss4sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour1);
      };
      break;
    case ss4sec2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond2(var);
        var = Timer[3].minute2();
        setPos(ss4min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec2);
      };
      break;
    case ss4min2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(">") << var                << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute2(var);
        var = Timer[3].hour2();
        setPos(ss4hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min2);
      };
      break;
    case ss4hour2:
      {
        lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeHour2(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss5: // 5-экран
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[4].second1();
        setPos(ss5sec1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5sec1:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond1(var);
        var = Timer[4].minute1();
        setPos(ss5min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec1);
      };
      break;
    case ss5min1:
      {
        lcd << F("Timer5:") << Timer[4].hour1() <<  F(">") << var  << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute1(var);
        var = Timer[4].hour1();
        setPos(ss5hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min1);
      };
      break;
    case ss5hour1:
      {
        lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeHour1(var);
        var = Timer[4].second2();
        setPos(ss5sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour1);
      };
      break;
    case ss5sec2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() <<  F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond2(var);
        var = Timer[4].minute2();
        setPos(ss5min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec2);
      };
      break;
    case ss5min2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(">") << var                << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute2(var);
        var = Timer[4].hour2();
        setPos(ss5hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min2);
      };
      break;
    case ss5hour2:
      {
        lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeHour2(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour2);
      };
      break;
  }
}
void menuInit() {
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++) Timer[i].init();
  lcd.init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  for (int i = 0; i < numTimer; i++) Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

добавил класс- millis-часы(не полный)

/**/
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);
//---------- millis часы ----------------------------------------------
class Cl_clock {
  protected:
    unsigned long time;
    unsigned long past;
    void set() {
      past = millis();
      time = past / 1000;
    }
  public:
    void init() {
      set();
    }
    void run()  {
      if (millis() - past >= 100) set();
    }
    unsigned long now()  {
      return time;
    }
    byte hour() {
      return (time / 60 / 60 % 24);
    }
    byte minute() {
      return (time / 60 % 60);
    }
    byte second() {
      return (time % 60);
    }
};
Cl_clock clock;
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr1[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer * 2] = { // начальные настройки
    {0, 0, 30}, {0, 3, 00}, // 1-й таймер
    {0, 1, 00}, {0, 3, 30}, // 2-й таймер
    {0, 1, 30}, {0, 4, 00}, // 3-й таймер
    {0, 2, 00}, {0, 4, 30}, // 4-й таймер
    {0, 2, 30}, {0, 5, 00}  // 5-й таймер
  };
  for (int i = 0; i < numTimer * 2; ++i) {
    eeprom_write_byte(&adr1[i].hour  , data[i].hour);
    eeprom_write_byte(&adr1[i].minute, data[i].minute);
    eeprom_write_byte(&adr1[i].second, data[i].second);
  }
}
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Timer {
  private:
    timer_t *adr1, *adr2;
    byte pin;
    byte stat;// состояние
    unsigned long past;
    void setStat(byte s) {
      stat = s;
      past = millis();
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case  sON:
          digitalWrite(pin, LOW);
          break;
        case  sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    Cl_Timer(byte p, timer_t * a1, timer_t * a2)
      :  adr1(a1), adr2(a2), pin(p) {}
    void init() {
      pinMode(pin, OUTPUT);
      setStat(sOFF);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (stat) {
          case sOFF:
            if (clock.now() >= ((unsigned long)hour1() * 24 + minute1()) * 60 + second1())setStat(sON);
            else setStat(sOFF);
            break;
          case  sON:
            if (clock.now() >= ((unsigned long)hour2() * 24 + minute2()) * 60 + second2())setStat(sEND);
            else setStat(sON);
            break;
          case  sEND:
            setStat(sEND);
            break;
        }
      }
    }
    void state() {
      switch (stat) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
    byte hour1() {
      return eeprom_read_byte(&(adr1->hour));
    }
    byte minute1() {
      return eeprom_read_byte(&(adr1->minute));
    }
    byte second1() {
      return eeprom_read_byte(&(adr1->second));
    }
    void writeHour1(byte data) {
      eeprom_write_byte(&(adr1->hour), data);
    }
    void writeMinute1(byte data) {
      eeprom_write_byte(&(adr1->minute), data);
    }
    void writeSecond1(byte data) {
      eeprom_write_byte(&(adr1->second), data);
    }
    byte hour2() {
      return eeprom_read_byte(&(adr2->hour));
    }
    byte minute2() {
      return eeprom_read_byte(&(adr2->minute));
    }
    byte second2() {
      return eeprom_read_byte(&(adr2->second));
    }
    void writeHour2(byte data) {
      eeprom_write_byte(&(adr2->hour), data);
    }
    void writeMinute2(byte data) {
      eeprom_write_byte(&(adr2->minute), data);
    }
    void writeSecond2(byte data) {
      eeprom_write_byte(&(adr2->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(/*пин*/2, &adr1[0], &adr1[1]), // 1-й таймер
  Cl_Timer(/*пин*/3, &adr1[2], &adr1[3]), // 2-й таймер
  Cl_Timer(/*пин*/4, &adr1[4], &adr1[5]), // 3-й таймер
  Cl_Timer(/*пин*/5, &adr1[6], &adr1[7]), // 4-й таймер
  Cl_Timer(/*пин*/6, &adr1[8], &adr1[9]) // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
const byte sMain      = 0;// главный экран

const byte ss1        = 1;// 1-экран
const byte ss1sec1    = 2;// редактирование 1
const byte ss1min1    = 3;// редактирование 2
const byte ss1hour1   = 4;// редактирование 3
const byte ss1sec2    = 5;// редактирование 1
const byte ss1min2    = 6;// редактирование 2
const byte ss1hour2   = 7;// редактирование 3

const byte ss2        = 11;// 2-экран
const byte ss2sec1    = 12;// редактирование 1
const byte ss2min1    = 13;// редактирование 2
const byte ss2hour1   = 14;// редактирование 3
const byte ss2sec2    = 15;// редактирование 1
const byte ss2min2    = 16;// редактирование 2
const byte ss2hour2   = 17;// редактирование 3

const byte ss3        = 21;// 3-экран
const byte ss3sec1    = 22;// редактирование 1
const byte ss3min1    = 23;// редактирование 2
const byte ss3hour1   = 24;// редактирование 3
const byte ss3sec2    = 25;// редактирование 1
const byte ss3min2    = 26;// редактирование 2
const byte ss3hour2   = 27;// редактирование 3

const byte ss4        = 31;// 4-экран
const byte ss4sec1    = 32;// редактирование 1
const byte ss4min1    = 33;// редактирование 2
const byte ss4hour1   = 34;// редактирование 3
const byte ss4sec2    = 35;// редактирование 1
const byte ss4min2    = 36;// редактирование 2
const byte ss4hour2   = 37;// редактирование 3

const byte ss5        = 41;// 5-экран
const byte ss5sec1    = 42;// редактирование 1
const byte ss5min1    = 43;// редактирование 2
const byte ss5hour1   = 44;// редактирование 3
const byte ss5sec2    = 45;// редактирование 1
const byte ss5min2    = 46;// редактирование 2
const byte ss5hour2   = 47;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { lcd  << clock.hour() << F(":") << clock.minute() << F(":") << clock.second();
        lcd.setCursor(9, 0);
        Timer[0].state(); lcd << F(" ");
        Timer[1].state(); lcd << F(" ");
        lcd.setCursor(5, 1);
        Timer[2].state(); lcd << F(" ");
        Timer[3].state(); lcd << F(" ");
        Timer[4].state(); lcd << F(" ");
        lcd.show();
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[0].second1();
        setPos(ss1sec1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1sec1:// редактирование секунд
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond1(var);
        var = Timer[0].minute1();
        setPos(ss1min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec1);
      };
      break;
    case ss1min1:// редактирование минут
      { lcd << F("Timer1:") << Timer[0].hour1() <<  F(">") << var  << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute1(var);
        var = Timer[0].hour1();
        setPos(ss1hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min1);
      };
      break;
    case ss1hour1:// редактирование часов
      { lcd << F("Timer1>") << var << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeHour1(var);
        setPos(ss1sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour1);
      };
      break;
    case ss1sec2:// редактирование секунд
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond2(var);
        var = Timer[0].minute2();
        setPos(ss1min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec2);
      };
      break;
    case ss1min2:// редактирование минут
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") <<  Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(">") << var                 << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute2(var);
        var = Timer[0].hour2();
        setPos(ss1hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min2);
      };
      break;
    case ss1hour2:// редактирование часов
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeHour2(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss2: // 2-экран
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[1].second1();
        setPos(ss2sec1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2sec1:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond1(var);
        var = Timer[1].minute1();
        setPos(ss2min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec1);
      };
      break;
    case ss2min1:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(">") << var  << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute1(var);
        var = Timer[1].hour1();
        setPos(ss2hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min1);
      };
      break;
    case ss2hour1:
      { lcd << F("Timer2>") << var << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeHour1(var);
        var = Timer[1].second2();
        setPos(ss2sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour1);
      };
      break;
    case ss2sec2:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond2(var);
        var = Timer[1].minute2();
        setPos(ss2min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec2);
      };
      break;
    case ss2min2:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(">") << var                << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute2(var);
        var = Timer[1].hour2();
        setPos(ss2hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min2);
      };
      break;
    case ss2hour2:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeHour2(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss3: // 3-экран
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[2].second1();
        setPos(ss3sec1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3sec1:// редакт секунд
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond1(var);
        var = Timer[2].minute1();
        setPos(ss3min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec1);
      };
      break;
    case ss3min1:// редакт минут
      { lcd << F("Timer3:") << Timer[2].hour1() <<  F(">") << var               << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute1(var);
        var = Timer[2].hour1();
        setPos(ss3hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min1);
      };
      break;
    case ss3hour1:// редакт часов
      { lcd << F("Timer3>") << var              << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeHour1(var);
        var = Timer[2].second2();
        setPos(ss3sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour1);
      };
      break;
    case ss3sec2:// редакт секунд
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond2(var);
        var = Timer[2].minute2();
        setPos(ss3min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec2);
      };
      break;
    case ss3min2:// редакт минут
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(">") << var                << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute2(var);
        var = Timer[2].hour2();
        setPos(ss3hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min2);
      };
      break;
    case ss3hour2:// редакт часов
      { lcd << F("Timer3:") << Timer[2].hour1()  << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var               << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeHour2(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss4: // 4-экран
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[3].second1();
        setPos(ss4sec1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4sec1:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond1(var);
        var = Timer[3].minute1();
        setPos(ss4min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec1);
      };
      break;
    case ss4min1:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(">") << var                << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute1(var);
        var = Timer[3].hour1();
        setPos(ss4hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min1);
      };
      break;
    case ss4hour1:
      { lcd << F("Timer4>") << var << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeHour1(var);
        var = Timer[3].second2();
        setPos(ss4sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour1);
      };
      break;
    case ss4sec2:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond2(var);
        var = Timer[3].minute2();
        setPos(ss4min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec2);
      };
      break;
    case ss4min2:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(">") << var                << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute2(var);
        var = Timer[3].hour2();
        setPos(ss4hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min2);
      };
      break;
    case ss4hour2:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeHour2(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss5: // 5-экран
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[4].second1();
        setPos(ss5sec1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5sec1:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond1(var);
        var = Timer[4].minute1();
        setPos(ss5min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec1);
      };
      break;
    case ss5min1:
      { lcd << F("Timer5:") << Timer[4].hour1() <<  F(">") << var  << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute1(var);
        var = Timer[4].hour1();
        setPos(ss5hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min1);
      };
      break;
    case ss5hour1:
      { lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeHour1(var);
        var = Timer[4].second2();
        setPos(ss5sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour1);
      };
      break;
    case ss5sec2:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() <<  F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond2(var);
        var = Timer[4].minute2();
        setPos(ss5min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec2);
      };
      break;
    case ss5min2:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(">") << var                << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute2(var);
        var = Timer[4].hour2();
        setPos(ss5hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min2);
      };
      break;
    case ss5hour2:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeHour2(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour2);
      };
      break;
  }
}
void menuInit() {
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  lcd.init();
  clock.init();
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++) Timer[i].init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  clock.run();
  for (int i = 0; i < numTimer; i++) Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Модуль с DS3231 и тестовый скетч 

/**/
#include <Wire.h>
#include "DS3231.h"
RTClib RTC;
//-----------------------
void setup () {
  Serial.begin(9600);
  Wire.begin();
}
void loop () {
  delay(1000);
  DateTime now = RTC.now();
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

С недостатками но работает уже с модулем

/**/
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);
//---------- часы ----------------------------------------------
/**/
#include "DS3231.h"
RTClib RTC;
class Cl_clock {
  protected:
    DateTime _now;
    unsigned long past;
    unsigned long time;
    void set() {
      past = millis();
      _now = RTC.now();
      time = (_now.hour() * 24 + _now.minute()) * 60 + _now.second();
    }
  public:
    void init() {
      set();
    }
    void run()  {
      if (millis() - past >= 1000) set();
    }
    unsigned long now() {
      return time;
    }
    byte hour() {
      return _now.hour();
    }
    byte minute() {
      return _now.minute();
    }
    byte second() {
      return _now.second();
    }
};
Cl_clock clock;
// -------------таймеры------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;
} timer_t;
const byte numTimer = 5;
timer_t EEMEM adr1[numTimer];
// первичные настройки в EEPROM
void saveZeroSettings() {
  timer_t data[numTimer * 2] = { // начальные настройки
    {0, 0, 30}, {0, 3, 00}, // 1-й таймер
    {0, 1, 00}, {0, 3, 30}, // 2-й таймер
    {0, 1, 30}, {0, 4, 00}, // 3-й таймер
    {0, 2, 00}, {0, 4, 30}, // 4-й таймер
    {0, 2, 30}, {0, 5, 00}  // 5-й таймер
  };
  for (int i = 0; i < numTimer * 2; ++i) {
    eeprom_write_byte(&adr1[i].hour  , data[i].hour);
    eeprom_write_byte(&adr1[i].minute, data[i].minute);
    eeprom_write_byte(&adr1[i].second, data[i].second);
  }
}
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Timer {
  private:
    timer_t *adr1, *adr2;
    byte pin;
    byte stat;// состояние
    unsigned long past;
    void setStat(byte s) {
      stat = s;
      past = millis();
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case  sON:
          digitalWrite(pin, LOW);
          break;
        case  sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    Cl_Timer(byte p, timer_t * a1, timer_t * a2)
      :  adr1(a1), adr2(a2), pin(p) {}
    void init() {
      pinMode(pin, OUTPUT);
      setStat(sOFF);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (stat) {
          case sOFF:
            if (clock.now() >= ((unsigned long)hour1() * 24 + minute1()) * 60 + second1())setStat(sON);
            else setStat(sOFF);
            break;
          case  sON:
            if (clock.now() >= ((unsigned long)hour2() * 24 + minute2()) * 60 + second2())setStat(sEND);
            else setStat(sON);
            break;
          case  sEND:
            setStat(sEND);
            break;
        }
      }
    }
    void state() {
      switch (stat) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
    byte hour1() {
      return eeprom_read_byte(&(adr1->hour));
    }
    byte minute1() {
      return eeprom_read_byte(&(adr1->minute));
    }
    byte second1() {
      return eeprom_read_byte(&(adr1->second));
    }
    void writeHour1(byte data) {
      eeprom_write_byte(&(adr1->hour), data);
    }
    void writeMinute1(byte data) {
      eeprom_write_byte(&(adr1->minute), data);
    }
    void writeSecond1(byte data) {
      eeprom_write_byte(&(adr1->second), data);
    }
    byte hour2() {
      return eeprom_read_byte(&(adr2->hour));
    }
    byte minute2() {
      return eeprom_read_byte(&(adr2->minute));
    }
    byte second2() {
      return eeprom_read_byte(&(adr2->second));
    }
    void writeHour2(byte data) {
      eeprom_write_byte(&(adr2->hour), data);
    }
    void writeMinute2(byte data) {
      eeprom_write_byte(&(adr2->minute), data);
    }
    void writeSecond2(byte data) {
      eeprom_write_byte(&(adr2->second), data);
    }
};
Cl_Timer Timer[numTimer] = {
  Cl_Timer(/*пин*/2, &adr1[0], &adr1[1]), // 1-й таймер
  Cl_Timer(/*пин*/3, &adr1[2], &adr1[3]), // 2-й таймер
  Cl_Timer(/*пин*/4, &adr1[4], &adr1[5]), // 3-й таймер
  Cl_Timer(/*пин*/5, &adr1[6], &adr1[7]), // 4-й таймер
  Cl_Timer(/*пин*/6, &adr1[8], &adr1[9]) // 5-й таймер
};
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//--------------- меню---------------------------------------------
byte var; // некая вспомогательная переменная
const byte sMain      = 0;// главный экран

const byte ss1        = 1;// 1-экран
const byte ss1sec1    = 2;// редактирование 1
const byte ss1min1    = 3;// редактирование 2
const byte ss1hour1   = 4;// редактирование 3
const byte ss1sec2    = 5;// редактирование 1
const byte ss1min2    = 6;// редактирование 2
const byte ss1hour2   = 7;// редактирование 3

const byte ss2        = 11;// 2-экран
const byte ss2sec1    = 12;// редактирование 1
const byte ss2min1    = 13;// редактирование 2
const byte ss2hour1   = 14;// редактирование 3
const byte ss2sec2    = 15;// редактирование 1
const byte ss2min2    = 16;// редактирование 2
const byte ss2hour2   = 17;// редактирование 3

const byte ss3        = 21;// 3-экран
const byte ss3sec1    = 22;// редактирование 1
const byte ss3min1    = 23;// редактирование 2
const byte ss3hour1   = 24;// редактирование 3
const byte ss3sec2    = 25;// редактирование 1
const byte ss3min2    = 26;// редактирование 2
const byte ss3hour2   = 27;// редактирование 3

const byte ss4        = 31;// 4-экран
const byte ss4sec1    = 32;// редактирование 1
const byte ss4min1    = 33;// редактирование 2
const byte ss4hour1   = 34;// редактирование 3
const byte ss4sec2    = 35;// редактирование 1
const byte ss4min2    = 36;// редактирование 2
const byte ss4hour2   = 37;// редактирование 3

const byte ss5        = 41;// 5-экран
const byte ss5sec1    = 42;// редактирование 1
const byte ss5min1    = 43;// редактирование 2
const byte ss5hour1   = 44;// редактирование 3
const byte ss5sec2    = 45;// редактирование 1
const byte ss5min2    = 46;// редактирование 2
const byte ss5hour2   = 47;// редактирование 3
byte pos;
unsigned long past;
void setPos(byte p) {
  pos = p;
  past = millis();
  lcd.clear();
  switch (p) {
    case sMain:// главный экран
      { lcd  << clock.hour() << F(":") << clock.minute() << F(":") << clock.second();
        lcd.setCursor(9, 0);
        Timer[0].state(); lcd << F(" ");
        Timer[1].state(); lcd << F(" ");
        lcd.setCursor(5, 1);
        Timer[2].state(); lcd << F(" ");
        Timer[3].state(); lcd << F(" ");
        Timer[4].state(); lcd << F(" ");
        lcd.show();
      }
      Btn.Do    = [] {};
      JoyUD.Do1 = [] { };
      JoyUD.Do2 = [] {setPos(ss1); };
      break;
    case ss1: // 1-экран
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[0].second1();
        setPos(ss1sec1);
      };
      JoyUD.Do1 = [] {setPos(sMain); };
      JoyUD.Do2 = [] {setPos(ss2); };
      break;
    case ss1sec1:// редактирование секунд
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond1(var);
        var = Timer[0].minute1();
        setPos(ss1min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec1);
      };
      break;
    case ss1min1:// редактирование минут
      { lcd << F("Timer1:") << Timer[0].hour1() <<  F(">") << var  << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute1(var);
        var = Timer[0].hour1();
        setPos(ss1hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min1);
      };
      break;
    case ss1hour1:// редактирование часов
      { lcd << F("Timer1>") << var << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeHour1(var);
        setPos(ss1sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour1);
      };
      break;
    case ss1sec2:// редактирование секунд
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(":") << Timer[0].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeSecond2(var);
        var = Timer[0].minute2();
        setPos(ss1min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1sec2);
      };
      break;
    case ss1min2:// редактирование минут
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") <<  Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[0].hour2() << F(">") << var                 << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeMinute2(var);
        var = Timer[0].hour2();
        setPos(ss1hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss1min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1min2);
      };
      break;
    case ss1hour2:// редактирование часов
      { lcd << F("Timer1:") << Timer[0].hour1() << F(":") << Timer[0].minute1() << F(":") << Timer[0].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[0].minute2() << F(":") << Timer[0].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[0].writeHour2(var);
        setPos(ss1);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss1hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss1hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss2: // 2-экран
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[1].second1();
        setPos(ss2sec1);
      };
      JoyUD.Do1 = [] {setPos(ss1); };
      JoyUD.Do2 = [] {setPos(ss3); };
      break;
    case ss2sec1:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond1(var);
        var = Timer[1].minute1();
        setPos(ss2min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec1);
      };
      break;
    case ss2min1:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(">") << var  << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute1(var);
        var = Timer[1].hour1();
        setPos(ss2hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min1);
      };
      break;
    case ss2hour1:
      { lcd << F("Timer2>") << var << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeHour1(var);
        var = Timer[1].second2();
        setPos(ss2sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour1);
      };
      break;
    case ss2sec2:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(":") << Timer[1].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeSecond2(var);
        var = Timer[1].minute2();
        setPos(ss2min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2sec2);
      };
      break;
    case ss2min2:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[1].hour2() << F(">") << var                << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeMinute2(var);
        var = Timer[1].hour2();
        setPos(ss2hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss2min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2min2);
      };
      break;
    case ss2hour2:
      { lcd << F("Timer2:") << Timer[1].hour1() << F(":") << Timer[1].minute1() << F(":") << Timer[1].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[1].minute2() << F(":") << Timer[1].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[1].writeHour2(var);
        setPos(ss2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss2hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss2hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss3: // 3-экран
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[2].second1();
        setPos(ss3sec1);
      };
      JoyUD.Do1 = [] {setPos(ss2); };
      JoyUD.Do2 = [] {setPos(ss4); };
      break;
    case ss3sec1:// редакт секунд
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond1(var);
        var = Timer[2].minute1();
        setPos(ss3min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec1);
      };
      break;
    case ss3min1:// редакт минут
      { lcd << F("Timer3:") << Timer[2].hour1() <<  F(">") << var               << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute1(var);
        var = Timer[2].hour1();
        setPos(ss3hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min1);
      };
      break;
    case ss3hour1:// редакт часов
      { lcd << F("Timer3>") << var              << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeHour1(var);
        var = Timer[2].second2();
        setPos(ss3sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour1);
      };
      break;
    case ss3sec2:// редакт секунд
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(":") << Timer[2].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeSecond2(var);
        var = Timer[2].minute2();
        setPos(ss3min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3sec2);
      };
      break;
    case ss3min2:// редакт минут
      { lcd << F("Timer3:") << Timer[2].hour1() << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[2].hour2() << F(">") << var                << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeMinute2(var);
        var = Timer[2].hour2();
        setPos(ss3hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss3min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3min2);
      };
      break;
    case ss3hour2:// редакт часов
      { lcd << F("Timer3:") << Timer[2].hour1()  << F(":") << Timer[2].minute1() << F(":") << Timer[2].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var               << F(":") << Timer[2].minute2() << F(":") << Timer[2].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[2].writeHour2(var);
        setPos(ss3);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss3hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss3hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss4: // 4-экран
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[3].second1();
        setPos(ss4sec1);
      };
      JoyUD.Do1  = [] {setPos(ss3); };
      JoyUD.Do2  = [] {setPos(ss5); };
      break;
    case ss4sec1:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond1(var);
        var = Timer[3].minute1();
        setPos(ss4min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec1);
      };
      break;
    case ss4min1:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(">") << var                << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute1(var);
        var = Timer[3].hour1();
        setPos(ss4hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min1);
      };
      break;
    case ss4hour1:
      { lcd << F("Timer4>") << var << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeHour1(var);
        var = Timer[3].second2();
        setPos(ss4sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour1);
      };
      break;
    case ss4sec2:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(":") << Timer[3].minute2() << F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeSecond2(var);
        var = Timer[3].minute2();
        setPos(ss4min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4sec2);
      };
      break;
    case ss4min2:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[3].hour2() << F(">") << var                << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeMinute2(var);
        var = Timer[3].hour2();
        setPos(ss4hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss4min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4min2);
      };
      break;
    case ss4hour2:
      { lcd << F("Timer4:") << Timer[3].hour1() << F(":") << Timer[3].minute1() << F(":") << Timer[3].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") << var              << F(":") << Timer[3].minute2() << F(":") << Timer[3].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[3].writeHour2(var);
        setPos(ss4);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss4hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss4hour2);
      };
      break;
    //---------------------------------------------------------------------
    case ss5: // 5-экран
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Timer[4].second1();
        setPos(ss5sec1);
      };
      JoyUD.Do1 = [] {
        setPos(ss4);
      };
      JoyUD.Do2 = [] {};
      break;
    case ss5sec1:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(">") << var;
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond1(var);
        var = Timer[4].minute1();
        setPos(ss5min1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec1);
      };
      break;
    case ss5min1:
      { lcd << F("Timer5:") << Timer[4].hour1() <<  F(">") << var  << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute1(var);
        var = Timer[4].hour1();
        setPos(ss5hour1);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min1);
      };
      break;
    case ss5hour1:
      { lcd << F("Timer5>") <<  var << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeHour1(var);
        var = Timer[4].second2();
        setPos(ss5sec2);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour1);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour1);
      };
      break;
    case ss5sec2:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(":") << Timer[4].minute2() <<  F(">") << var;
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeSecond2(var);
        var = Timer[4].minute2();
        setPos(ss5min2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5sec2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5sec2);
      };
      break;
    case ss5min2:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("       ") << Timer[4].hour2() << F(">") << var                << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeMinute2(var);
        var = Timer[4].hour2();
        setPos(ss5hour2);
      };
      JoyUD.Do1   = [] {
        if (var < 59)var++;
        setPos(ss5min2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5min2);
      };
      break;
    case ss5hour2:
      { lcd << F("Timer5:") << Timer[4].hour1() << F(":") << Timer[4].minute1() << F(":") << Timer[4].second1();
        lcd.setCursor(0, 1);
        lcd << F("      >") <<  var             << F(":") << Timer[4].minute2() << F(":") << Timer[4].second2();
        lcd.show();
      }
      Btn.Do      = [] {
        Timer[4].writeHour2(var);
        setPos(ss5);
      };
      JoyUD.Do1   = [] {
        if (var < 23)var++;
        setPos(ss5hour2);
      };
      JoyUD.Do2   = [] {
        if (var > 0)var--;
        setPos(ss5hour2);
      };
      break;
  }
}
void menuInit() {
  setPos(sMain);
}
void menuRun() {
  if (pos != sMain && millis() - past >= 10000)setPos(sMain);
  if (pos == sMain && millis() - past >= 1000)setPos(sMain);
}
//----------------------------------
void setup() {
  lcd.init();
  clock.init();
  saveZeroSettings();
  for (int i = 0; i < numTimer; i++)Timer[i].init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
  JoyLR.Do1 = [] {lcd.backlight();};
  JoyLR.Do2 = [] {lcd.noBacklight();};
}
void loop() {
  clock.run();
  for (int i = 0; i < numTimer; i++)Timer[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Возможно это баян. Но вставив этот код в скетч вы всегда будете знать время последней зашивки кода

void setup() {
  Serial.begin(9600);
  Serial.print(F("data:"));
  Serial.println(F(__DATE__));
  Serial.print(F("time:"));
  Serial.println(F(__TIME__));
}
void loop() {
}

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

баян, еще какой.

тебе совсем там плохо ?

Green
Offline
Зарегистрирован: 01.10.2015
  Serial.println(F(NAME " " VERSION " " __DATE__ " " __TIME__));
Но и этого временами оказывается мало.(
Logik
Offline
Зарегистрирован: 05.08.2014

Может не NAME а всеже __FILE__? Да и VERSION - сугубо личное наверно.

Green
Offline
Зарегистрирован: 01.10.2015

Как бы расположение мне не особо нужно...
Да, и то и другое сугубо личное, но иногда полезное. С особо одарёнными заказчиками(. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Мой программный компонент для модуля DS3231 

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//-----часы-----------------------
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
class dTime {
  protected:
  public:
    byte hh, mm, ss;
    dTime(unsigned long t = 0)
      : hh(t / 60 / 60 % 24), mm(t / 60 % 60), ss(t % 60) {}
    dTime(byte h, byte m, byte s)
      : hh(h), mm(m), ss(s) {}
    dTime(const dTime& t)//      : hh(copy.hh), mm(copy.mm), ss(copy.ss)
    {
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
    }
    dTime(const char* time) {
      hh = conv2d(time);
      mm = conv2d(time + 3);
      ss = conv2d(time + 6);
    }
    dTime(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      hh = conv2d(buff);
      mm = conv2d(buff + 3);
      ss = conv2d(buff + 6);
    }
    dTime& operator=(const dTime& t) {
      if (this == &t)
        return *this;
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
      return *this;
    }
};

#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F
#include <Wire.h>
uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.endTransmission();

  Wire.requestFrom(addr, (byte)1);
  return Wire.read();
}
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.write((byte)val);
  Wire.endTransmission();
}
uint8_t bcd2bin (uint8_t val) {
  return val - 6 * (val >> 4);
}
uint8_t bin2bcd (uint8_t val) {
  return val + 6 * (val / 10);
}
class RTC_DS3231 {
  public:
    void write(dTime t) {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0); // start at location 0
      Wire.write(bin2bcd(t.ss));
      Wire.write(bin2bcd(t.mm));
      Wire.write(bin2bcd(t.hh));
      Wire.endTransmission();
      uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
      statreg &= ~0x80; // flip OSF bit
      write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
    }
    dTime read() {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0);
      Wire.endTransmission();
      Wire.requestFrom(DS3231_ADDRESS, 7);
      uint8_t s = bcd2bin(Wire.read() & 0x7F);
      uint8_t m = bcd2bin(Wire.read());
      uint8_t h = bcd2bin(Wire.read());
      return dTime(h, m, s);
    }
};
RTC_DS3231  rtc;
//-----------------------------
void setup() {
  Serial.begin(9600);
  Wire.begin();
  rtc.write(F(__TIME__));
}
void loop() {
  delay(1000);
  dTime now(rtc.read());
  Serial << now.hh << F(":") << now.mm << F(":") << now.ss << F("\n");
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Добавил к часам управление 4-мя реле . Удачно получилось.

/* часы с ручной установкой времени на DS3231*/
// Оборудование
// Ардуино Нано
// lcd1602_i2c  -- I2C
// модуль DS3231 -- I2C
// ардуино джойстик кнопка A0 потенциометры A1,A2
// модуль реле 2,3,4,5
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_lightON 0x08
#define LCD_lightOFF 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _lightONval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _lightONval = LCD_lightOFF;
      expanderWrite(_lightONval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void lightON(void) {
      _lightONval = LCD_lightON;
      expanderWrite(0);
    }
    void lightOFF(void) {
      _lightONval = LCD_lightOFF;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _lightONval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);//0x3F
//-----часы-----------------------
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
class dTime {
  protected:
  public:
    byte hh, mm, ss;
    unsigned long time() {
      return ((hh * 24 + mm) * 60 + ss);
    }
    dTime(unsigned long t = 0)
      : hh(t / 60 / 60 % 24), mm(t / 60 % 60), ss(t % 60) {}
    dTime(byte h, byte m, byte s)
      : hh(h), mm(m), ss(s) {}
    dTime(const dTime& t)//      : hh(copy.hh), mm(copy.mm), ss(copy.ss)
    {
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
    }
    dTime(const char* time) {
      hh = conv2d(time);
      mm = conv2d(time + 3);
      ss = conv2d(time + 6);
    }
    dTime(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      hh = conv2d(buff);
      mm = conv2d(buff + 3);
      ss = conv2d(buff + 6);
    }
    dTime& operator=(const dTime& t) {
      if (this == &t)
        return *this;
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
      return *this;
    }
};

#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F
#include <Wire.h>
uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.endTransmission();

  Wire.requestFrom(addr, (byte)1);
  return Wire.read();
}
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.write((byte)val);
  Wire.endTransmission();
}
uint8_t bcd2bin (uint8_t val) {
  return val - 6 * (val >> 4);
}
uint8_t bin2bcd (uint8_t val) {
  return val + 6 * (val / 10);
}
class RTC_DS3231 {
  public:
    void write(dTime t) {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0); // start at location 0
      Wire.write(bin2bcd(t.ss));
      Wire.write(bin2bcd(t.mm));
      Wire.write(bin2bcd(t.hh));
      Wire.endTransmission();
      uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
      statreg &= ~0x80; // flip OSF bit
      write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
    }
    dTime read() {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0);
      Wire.endTransmission();
      Wire.requestFrom(DS3231_ADDRESS, 7);
      uint8_t s = bcd2bin(Wire.read() & 0x7F);
      uint8_t m = bcd2bin(Wire.read());
      uint8_t h = bcd2bin(Wire.read());
      return dTime(h, m, s);
    }
};
RTC_DS3231  rtc;// часы
dTime now;//текущее время
//--------------Реле------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;

} timer_t;
class cl_timer {
  protected:
    timer_t *adr;
  public:
    cl_timer(timer_t *a): adr(a) {}
    void save(unsigned long t = 0) {
      setHour(t / 60 / 60 % 24);
      setMinute(t / 60  % 60);
      setSecond(t % 60);
    }
    void save(const char* time) {
      setHour(conv2d(time));
      setMinute(conv2d(time + 3));
      setSecond(conv2d(time + 6));
    }
    void save(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      setHour(conv2d(buff));
      setMinute(conv2d(buff + 3));
      setSecond(conv2d(buff + 6));
    }
    byte hour() {
      return eeprom_read_byte(&(adr->hour));
    };
    byte minute() {
      return eeprom_read_byte(&(adr->minute));
    };
    byte second() {
      return eeprom_read_byte(&(adr->second));
    };
    byte time() {
      return ((hour() * 24 + minute()) * 60 + second());
    };

    void setHour(byte h) {
      eeprom_write_byte(&adr->hour, h);
    }
    void setMinute(byte m) {
      eeprom_write_byte(&adr->minute, m);
    }
    void setSecond(byte s) {
      eeprom_write_byte(&adr->second, s);
    }
};
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Relay {
  protected:
    byte pin;
    byte state;
    void set(byte s) {
      state = s;
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case sON:
          digitalWrite(pin, LOW);
          break;
        case sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    cl_timer timeON, timeOFF;
    Cl_Relay(byte p, cl_timer t1, cl_timer t2)
      : pin(p), timeON(t1), timeOFF(t2) {}
    void init() {
      pinMode(pin, OUTPUT);
      set(sOFF) ;
    }
    void run() {
      switch (state) {
        case sOFF:
          if (now.time() >= timeON.time())set(sON);
          break;
        case sON:
          if (now.time() >= timeOFF.time())set(sEND);
          break;
        case sEND: break;
      }
    }
    void reset() {
      set(sOFF) ;
    }
};
const byte RelayNum = 4; //кол-во реле
timer_t EEMEM adr[RelayNum * 2];
Cl_Relay Relay[RelayNum] = {
  Cl_Relay(/*пин*/2, &adr[0], &adr[1]),// 1-е реле
  Cl_Relay(/*пин*/3, &adr[2], &adr[3]),// 2-е реле
  Cl_Relay(/*пин*/4, &adr[4], &adr[5]),// 3-е реле
  Cl_Relay(/*пин*/5, &adr[6], &adr[7]) // 4-е реле
};
// первичные настройки в EEPROM
void setZero() {
  Relay[0].timeON.save(F("00:00:30")); Relay[0].timeOFF.save(F("00:02:30"));// 1-е реле
  Relay[1].timeON.save(F("00:01:00")); Relay[1].timeOFF.save(F("00:03:00"));// 2-е реле
  Relay[2].timeON.save(F("00:01:30")); Relay[2].timeOFF.save(F("00:03:30"));// 3-е реле
  Relay[3].timeON.save(F("00:02:00")); Relay[3].timeOFF.save(F("00:04:00"));// 4-е реле
}
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------меню----------------
const byte scr0 = 0; // показ времени

const byte scr1       = 10; // показ времени реле1 вкл/выкл
const byte scr1_hour1 = 11; // установка часов  реле1 вкл
const byte scr1_min1  = 12; // установка минут  реле1 вкл
const byte scr1_sec1  = 13; // установка секунд реле1 вкл
const byte scr1_hour2 = 14; // установка часов  реле1 выкл
const byte scr1_min2  = 15; // установка минут  реле1 выкл
const byte scr1_sec2  = 16; // установка секунд реле1 выкл

const byte scr2       = 20; // показ времени реле2 вкл/выкл
const byte scr2_hour1 = 21; // установка часов  реле2 вкл
const byte scr2_min1  = 22; // установка минут  реле2 вкл
const byte scr2_sec1  = 23; // установка секунд реле2 вкл
const byte scr2_hour2 = 24; // установка часов  реле2 выкл
const byte scr2_min2  = 25; // установка минут  реле2 выкл
const byte scr2_sec2  = 26; // установка секунд реле2 выкл

const byte scr3       = 30; // показ времени реле3 вкл/выкл
const byte scr3_hour1 = 31; // установка часов  реле3 вкл
const byte scr3_min1  = 32; // установка минут  реле3 вкл
const byte scr3_sec1  = 33; // установка секунд реле3 вкл
const byte scr3_hour2 = 34; // установка часов  реле3 выкл
const byte scr3_min2  = 35; // установка минут  реле3 выкл
const byte scr3_sec2  = 36; // установка секунд реле3 выкл

const byte scr4       = 40; // показ времени реле4 вкл/выкл
const byte scr4_hour1 = 41; // установка часов  реле4 вкл
const byte scr4_min1  = 42; // установка минут  реле4 вкл
const byte scr4_sec1  = 43; // установка секунд реле4 вкл
const byte scr4_hour2 = 44; // установка часов  реле4 выкл
const byte scr4_min2  = 45; // установка минут  реле4 выкл
const byte scr4_sec2  = 46; // установка секунд реле4 выкл

const byte scr5      = 50;
const byte scr5_hour = 51; // установка времени часы
const byte scr5_min  = 52; // установка времени минуты
const byte scr5_sec  = 53; // установка времени секунд
const byte scr5_res  = 54; // установка времени секунд
byte scr; // номер экрана
unsigned long past;// фик времени в этом экране
byte var;// переменная для редактирования
dTime Time;// переменая времени
void go(byte s) {
  scr = s;
  past = millis();
  lcd.clear();
  switch (s) {
    case scr0: { // 0- экран
        lcd << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.show();
      }
      Btn.Do = [] {};
      JoyLR.Do1 = [] {};
      JoyLR.Do2 = [] {go(scr1);};
      break;
    case scr1: { // ------------------------------1- экран
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[0].timeON.hour();
        go(scr1_hour1);
      };
      JoyLR.Do1 = [] {go(scr0);};
      JoyLR.Do2 = [] {go(scr2);};
      break;
    case scr1_hour1: { // установка часов  реле1 вкл
        lcd  << F("Re1>") << var << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setHour(var);
        var = Relay[0].timeON.minute();
        go(scr1_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour1);
      };
      break;
    case scr1_min1: { // установка минут  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(">") << var << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr1_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min1);
      };
      break;
    case scr1_sec1: { // установка секунд  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[0].timeOFF.hour();
        go(scr1_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec1);
      };
      break;
    case scr1_hour2: { // установка часов  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setHour(var);
        var = Relay[0].timeOFF.minute();
        go(scr1_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour2);
      };
      break;
    case scr1_min2: { // установка минут  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[0].timeOFF.hour() << F(">") << var                     << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr1_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min2);
      };
      break;
    case scr1_sec2: { // установка секунд  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setSecond(var);
        go(scr1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec2);
      };
      break;
    case scr2: { //------------------------------------------------ 2- экран
        lcd  << F("Re2 ")  << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[1].timeON.hour();
        go(scr2_hour1);
      };
      JoyLR.Do1 = [] {go(scr1);};
      JoyLR.Do2 = [] {go(scr3);};
      break;
    case scr2_hour1: { // установка часов  реле2 вкл
        lcd  << F("Re2>") << var << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setHour(var);
        var = Relay[1].timeON.minute();
        go(scr2_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour1);
      };
      break;
    case scr2_min1: { // установка минут  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(">") << var << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setMinute(var);
        var = Relay[1].timeON.second();
        go(scr2_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min1);
      };
      break;
    case scr2_sec1: { // установка секунд  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setSecond(var);
        var = Relay[1].timeOFF.hour();
        go(scr2_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec1);
      };
      break;
    case scr2_hour2: { // установка часов  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setHour(var);
        var = Relay[1].timeOFF.minute();
        go(scr2_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour2);
      };
      break;
    case scr2_min2: { // установка минут  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[1].timeOFF.hour() << F(">") << var                     << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setMinute(var);
        var = Relay[1].timeOFF.second();
        go(scr2_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min2);
      };
      break;
    case scr2_sec2: { // установка секунд  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setSecond(var);
        go(scr2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec2);
      };
      break;
    case scr3: { //---------------------------------- 3- экран
        lcd  << F("Re3 ")  << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[2].timeON.hour();
        go(scr3_hour1);
      };
      JoyLR.Do1 = [] {go(scr2);};
      JoyLR.Do2 = [] {go(scr4);};
      break;
    case scr3_hour1: { // установка часов  реле3 вкл
        lcd  << F("Re3>") << var << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setHour(var);
        var = Relay[2].timeON.minute();
        go(scr3_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour1);
      };
      break;
    case scr3_min1: { // установка минут  реле1 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(">") << var << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setMinute(var);
        var = Relay[2].timeON.second();
        go(scr3_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min1);
      };
      break;
    case scr3_sec1: { // установка секунд  реле3 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setSecond(var);
        var = Relay[2].timeOFF.hour();
        go(scr3_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec1);
      };
      break;
    case scr3_hour2: { // установка часов  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeOFF.setHour(var);
        var = Relay[2].timeOFF.minute();
        go(scr3_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour2);
      };
      break;
    case scr3_min2: { // установка минут  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[2].timeOFF.hour() << F(">") << var                     << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr3_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min2);
      };
      break;
    case scr3_sec2: { // установка секунд  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr3);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec2);
      };
      break;
    case scr4: { // 4- экран
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[3].timeON.hour();
        go(scr4_hour1);
      };
      JoyLR.Do1 = [] {go(scr3);};
      JoyLR.Do2 = [] {go(scr5);};
      break;
    case scr4_hour1: { // установка часов  реле4 вкл
        lcd  << F("Re4>") << var << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeON.setHour(var);
        var = Relay[3].timeON.minute();
        go(scr4_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour1);
      };
      break;
    case scr4_min1: { // установка минут  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(">") << var << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr4_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min1);
      };
      break;
    case scr4_sec1: { // установка секунд  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[3].timeOFF.hour();
        go(scr4_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec1);
      };
      break;
    case scr4_hour2: { // установка часов  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setHour(var);
        var = Relay[3].timeOFF.minute();
        go(scr4_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour2);
      };
      break;
    case scr4_min2: { // установка минут  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[3].timeOFF.hour() << F(">") << var                     << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setMinute(var);
        var = Relay[3].timeOFF.second();
        go(scr4_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min2);
      };
      break;
    case scr4_sec2: { // установка секунд  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr4);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec2);
      };
      break;
    case scr5: { // 5- экран
        lcd << F("SetTime:") << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.show();
      }
      Btn.Do    = [] {
        Time = now;
        go(scr5_hour);
      };
      JoyLR.Do1 = [] {go(scr4);};
      JoyLR.Do2 = [] {go(scr0);};
      break;
    case scr5_hour: {
        lcd << F("SetTime>") << Time.hh << F(":") << Time.mm << F(":") << Time.ss;
        lcd.show();
      }
      Btn.Do    = [] {go(scr5_min);};
      JoyLR.Do1 = [] {
        if (Time.hh > 0)Time.hh--;
        go(scr5_hour);
      };
      JoyLR.Do2 = [] {
        if (Time.hh < 23)Time.hh++;
        go(scr5_hour);
      };
      break;
    case scr5_min: {
        lcd << F("SetTime:") << Time.hh << F(">") << Time.mm << F(":") << Time.ss ;
        lcd.show();
      }
      Btn.Do    = [] {go(scr5_sec);};
      JoyLR.Do1 = [] {
        if (Time.mm > 0)Time.mm--;
        go(scr5_min);
      };
      JoyLR.Do2 = [] {
        if (Time.mm < 59)Time.mm++;
        go(scr5_min);
      };
      break;
    case scr5_sec: {
        lcd << F("SetTime:") << Time.hh << F(":") << Time.mm << F(">") << Time.ss;
        lcd.show();
      }
      Btn.Do = [] {
        rtc.write(Time);
        now = Time;
        go(scr5);
      };
      JoyLR.Do1 = [] {
        if (Time.ss > 0)Time.ss--;
        go(scr5_sec);
      };
      JoyLR.Do2 = [] {
        if (Time.ss < 59)Time.ss++;
        go(scr5_sec);
      };
      break;
  }
}
void menuInit() {
  lcd.lightON();
  now = rtc.read();
  JoyUD.Do1 = [] {lcd.lightON();};
  JoyUD.Do2 = [] {lcd.lightOFF();};
  go(scr0);
}
void menuRun() {
  if (scr != scr0 && millis() - past >= 3000)go(scr0);
  if (scr == scr0 && millis() - past >= 500)go(scr0);
}
//-----------------------------
void setup() {
  lcd.init();
  rtc.write(F("00:00:00"));
  //rtc.write(F(__TIME__));//(для первичной настройки часов)
  setZero();////(для первичной настройки устройства)
  for (int i = 0; i < RelayNum; i++)Relay[i].init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
}
void loop() {
  now = rtc.read();
  for (int i = 0; i < RelayNum; i++)Relay[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Немного подправил скетч.

/* часы с ручной установкой времени на DS3231*/
// Оборудование
// Ардуино Нано
// lcd1602_i2c  -- I2C
// модуль DS3231 -- I2C
// ардуино джойстик кнопка A0 потенциометры A1,A2
// модуль реле 2,3,4,5
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_lightON 0x08
#define LCD_lightOFF 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _lightONval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _lightONval = LCD_lightOFF;
      expanderWrite(_lightONval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void lightON(void) {
      _lightONval = LCD_lightON;
      expanderWrite(0);
    }
    void lightOFF(void) {
      _lightONval = LCD_lightOFF;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _lightONval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);//0x3F
//-----часы-----------------------
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
class dTime {
  protected:
  public:
    byte hh, mm, ss;
    unsigned long time() {
      return ((hh * 24 + mm) * 60 + ss);
    }
    dTime(unsigned long t = 0)
      : hh(t / 60 / 60 % 24), mm(t / 60 % 60), ss(t % 60) {}
    dTime(byte h, byte m, byte s)
      : hh(h), mm(m), ss(s) {}
    dTime(const dTime& t)//      : hh(copy.hh), mm(copy.mm), ss(copy.ss)
    {
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
    }
    dTime(const char* time) {
      hh = conv2d(time);
      mm = conv2d(time + 3);
      ss = conv2d(time + 6);
    }
    dTime(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      hh = conv2d(buff);
      mm = conv2d(buff + 3);
      ss = conv2d(buff + 6);
    }
    dTime& operator=(const dTime& t) {
      if (this == &t)
        return *this;
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
      return *this;
    }
};

#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F
#include <Wire.h>
uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.endTransmission();

  Wire.requestFrom(addr, (byte)1);
  return Wire.read();
}
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.write((byte)val);
  Wire.endTransmission();
}
uint8_t bcd2bin (uint8_t val) {
  return val - 6 * (val >> 4);
}
uint8_t bin2bcd (uint8_t val) {
  return val + 6 * (val / 10);
}
class RTC_DS3231 {
  public:
    void write(dTime t) {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0); // start at location 0
      Wire.write(bin2bcd(t.ss));
      Wire.write(bin2bcd(t.mm));
      Wire.write(bin2bcd(t.hh));
      Wire.endTransmission();
      uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
      statreg &= ~0x80; // flip OSF bit
      write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
    }
    dTime read() {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0);
      Wire.endTransmission();
      Wire.requestFrom(DS3231_ADDRESS, 7);
      uint8_t s = bcd2bin(Wire.read() & 0x7F);
      uint8_t m = bcd2bin(Wire.read());
      uint8_t h = bcd2bin(Wire.read());
      return dTime(h, m, s);
    }
};
RTC_DS3231  rtc;// часы
dTime now, now_; //текущее время
//--------------Реле------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;

} timer_t;
class cl_timer {
  protected:
    timer_t *adr;
  public:
    cl_timer(timer_t *a): adr(a) {}
    void save(unsigned long t = 0) {
      setHour(t / 60 / 60 % 24);
      setMinute(t / 60  % 60);
      setSecond(t % 60);
    }
    void save(const char* time) {
      setHour(conv2d(time));
      setMinute(conv2d(time + 3));
      setSecond(conv2d(time + 6));
    }
    void save(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      setHour(conv2d(buff));
      setMinute(conv2d(buff + 3));
      setSecond(conv2d(buff + 6));
    }
    byte hour() {
      return eeprom_read_byte(&(adr->hour));
    };
    byte minute() {
      return eeprom_read_byte(&(adr->minute));
    };
    byte second() {
      return eeprom_read_byte(&(adr->second));
    };
    byte time() {
      return ((hour() * 24 + minute()) * 60 + second());
    };

    void setHour(byte h) {
      eeprom_write_byte(&adr->hour, h);
    }
    void setMinute(byte m) {
      eeprom_write_byte(&adr->minute, m);
    }
    void setSecond(byte s) {
      eeprom_write_byte(&adr->second, s);
    }
};
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Relay {
  protected:
    byte pin;
    byte state;
    void set(byte s) {
      state = s;
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case sON:
          digitalWrite(pin, LOW);
          break;
        case sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    cl_timer timeON, timeOFF;
    Cl_Relay(byte p, cl_timer t1, cl_timer t2)
      : pin(p), timeON(t1), timeOFF(t2) {}
    void init() {
      pinMode(pin, OUTPUT);
      set(sOFF) ;
    }
    void run() {
      switch (state) {
        case sOFF:
          if (now.time() >= timeON.time())set(sON);
          break;
        case sON:
          if (now.time() >= timeOFF.time())set(sEND);
          break;
        case sEND: break;
      }
    }
    void reset() {
      set(sOFF) ;
    }
    void viev() {
      switch (state) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
};
const byte RelayNum = 4; //кол-во реле
timer_t EEMEM adr[RelayNum * 2];
Cl_Relay Relay[RelayNum] = {
  Cl_Relay(/*пин*/2, &adr[0], &adr[1]),// 1-е реле
  Cl_Relay(/*пин*/3, &adr[2], &adr[3]),// 2-е реле
  Cl_Relay(/*пин*/4, &adr[4], &adr[5]),// 3-е реле
  Cl_Relay(/*пин*/5, &adr[6], &adr[7]) // 4-е реле
};
// первичные настройки в EEPROM
void setZero() {
  Relay[0].timeON.save(F("00:00:30")); Relay[0].timeOFF.save(F("00:02:30"));// 1-е реле
  Relay[1].timeON.save(F("00:01:00")); Relay[1].timeOFF.save(F("00:03:00"));// 2-е реле
  Relay[2].timeON.save(F("00:01:30")); Relay[2].timeOFF.save(F("00:03:30"));// 3-е реле
  Relay[3].timeON.save(F("00:02:00")); Relay[3].timeOFF.save(F("00:04:00"));// 4-е реле
}
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------меню----------------
const byte scr0 = 0; // показ времени

const byte scr1       = 10; // показ времени реле1 вкл/выкл
const byte scr1_hour1 = 11; // установка часов  реле1 вкл
const byte scr1_min1  = 12; // установка минут  реле1 вкл
const byte scr1_sec1  = 13; // установка секунд реле1 вкл
const byte scr1_hour2 = 14; // установка часов  реле1 выкл
const byte scr1_min2  = 15; // установка минут  реле1 выкл
const byte scr1_sec2  = 16; // установка секунд реле1 выкл

const byte scr2       = 20; // показ времени реле2 вкл/выкл
const byte scr2_hour1 = 21; // установка часов  реле2 вкл
const byte scr2_min1  = 22; // установка минут  реле2 вкл
const byte scr2_sec1  = 23; // установка секунд реле2 вкл
const byte scr2_hour2 = 24; // установка часов  реле2 выкл
const byte scr2_min2  = 25; // установка минут  реле2 выкл
const byte scr2_sec2  = 26; // установка секунд реле2 выкл

const byte scr3       = 30; // показ времени реле3 вкл/выкл
const byte scr3_hour1 = 31; // установка часов  реле3 вкл
const byte scr3_min1  = 32; // установка минут  реле3 вкл
const byte scr3_sec1  = 33; // установка секунд реле3 вкл
const byte scr3_hour2 = 34; // установка часов  реле3 выкл
const byte scr3_min2  = 35; // установка минут  реле3 выкл
const byte scr3_sec2  = 36; // установка секунд реле3 выкл

const byte scr4       = 40; // показ времени реле4 вкл/выкл
const byte scr4_hour1 = 41; // установка часов  реле4 вкл
const byte scr4_min1  = 42; // установка минут  реле4 вкл
const byte scr4_sec1  = 43; // установка секунд реле4 вкл
const byte scr4_hour2 = 44; // установка часов  реле4 выкл
const byte scr4_min2  = 45; // установка минут  реле4 выкл
const byte scr4_sec2  = 46; // установка секунд реле4 выкл

const byte scr5      = 50;
const byte scr5_hour = 51; // установка времени часы
const byte scr5_min  = 52; // установка времени минуты
const byte scr5_sec  = 53; // установка времени секунд
const byte scr5_res  = 54; // установка времени секунд
byte scr; // номер экрана
unsigned long past;// фик времени в этом экране
byte var;// переменная для редактирования
dTime Time;// переменая времени
void go(byte s) {
  scr = s;
  past = millis();
  lcd.clear();
  switch (s) {
    case scr0: { // 0- экран
        lcd << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.setCursor(9, 0);
        Relay[0].viev(); lcd << F(" ");
        Relay[1].viev(); lcd << F(" ");
        lcd.setCursor(9, 1);
        Relay[2].viev(); lcd << F(" ");
        Relay[3].viev(); lcd << F(" ");
        lcd.show();
      }
      Btn.Do = [] {};
      JoyLR.Do1 = [] {};
      JoyLR.Do2 = [] {go(scr1);};
      break;
    case scr1: { // ------------------------------1- экран
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[0].timeON.hour();
        go(scr1_hour1);
      };
      JoyLR.Do1 = [] {go(scr0);};
      JoyLR.Do2 = [] {go(scr2);};
      break;
    case scr1_hour1: { // установка часов  реле1 вкл
        lcd  << F("Re1>") << var << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setHour(var);
        var = Relay[0].timeON.minute();
        go(scr1_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour1);
      };
      break;
    case scr1_min1: { // установка минут  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(">") << var << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr1_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min1);
      };
      break;
    case scr1_sec1: { // установка секунд  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[0].timeOFF.hour();
        go(scr1_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec1);
      };
      break;
    case scr1_hour2: { // установка часов  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setHour(var);
        var = Relay[0].timeOFF.minute();
        go(scr1_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour2);
      };
      break;
    case scr1_min2: { // установка минут  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[0].timeOFF.hour() << F(">") << var                     << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr1_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min2);
      };
      break;
    case scr1_sec2: { // установка секунд  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setSecond(var);
        go(scr1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec2);
      };
      break;
    case scr2: { //------------------------------------------------ 2- экран
        lcd  << F("Re2 ")  << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[1].timeON.hour();
        go(scr2_hour1);
      };
      JoyLR.Do1 = [] {go(scr1);};
      JoyLR.Do2 = [] {go(scr3);};
      break;
    case scr2_hour1: { // установка часов  реле2 вкл
        lcd  << F("Re2>") << var << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setHour(var);
        var = Relay[1].timeON.minute();
        go(scr2_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour1);
      };
      break;
    case scr2_min1: { // установка минут  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(">") << var << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setMinute(var);
        var = Relay[1].timeON.second();
        go(scr2_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min1);
      };
      break;
    case scr2_sec1: { // установка секунд  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setSecond(var);
        var = Relay[1].timeOFF.hour();
        go(scr2_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec1);
      };
      break;
    case scr2_hour2: { // установка часов  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setHour(var);
        var = Relay[1].timeOFF.minute();
        go(scr2_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour2);
      };
      break;
    case scr2_min2: { // установка минут  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[1].timeOFF.hour() << F(">") << var                     << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setMinute(var);
        var = Relay[1].timeOFF.second();
        go(scr2_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min2);
      };
      break;
    case scr2_sec2: { // установка секунд  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setSecond(var);
        go(scr2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec2);
      };
      break;
    case scr3: { //---------------------------------- 3- экран
        lcd  << F("Re3 ")  << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[2].timeON.hour();
        go(scr3_hour1);
      };
      JoyLR.Do1 = [] {go(scr2);};
      JoyLR.Do2 = [] {go(scr4);};
      break;
    case scr3_hour1: { // установка часов  реле3 вкл
        lcd  << F("Re3>") << var << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setHour(var);
        var = Relay[2].timeON.minute();
        go(scr3_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour1);
      };
      break;
    case scr3_min1: { // установка минут  реле1 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(">") << var << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setMinute(var);
        var = Relay[2].timeON.second();
        go(scr3_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min1);
      };
      break;
    case scr3_sec1: { // установка секунд  реле3 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setSecond(var);
        var = Relay[2].timeOFF.hour();
        go(scr3_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec1);
      };
      break;
    case scr3_hour2: { // установка часов  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeOFF.setHour(var);
        var = Relay[2].timeOFF.minute();
        go(scr3_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour2);
      };
      break;
    case scr3_min2: { // установка минут  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[2].timeOFF.hour() << F(">") << var                     << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr3_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min2);
      };
      break;
    case scr3_sec2: { // установка секунд  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr3);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec2);
      };
      break;
    case scr4: { // 4- экран
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[3].timeON.hour();
        go(scr4_hour1);
      };
      JoyLR.Do1 = [] {go(scr3);};
      JoyLR.Do2 = [] {go(scr5);};
      break;
    case scr4_hour1: { // установка часов  реле4 вкл
        lcd  << F("Re4>") << var << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeON.setHour(var);
        var = Relay[3].timeON.minute();
        go(scr4_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour1);
      };
      break;
    case scr4_min1: { // установка минут  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(">") << var << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr4_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min1);
      };
      break;
    case scr4_sec1: { // установка секунд  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[3].timeOFF.hour();
        go(scr4_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec1);
      };
      break;
    case scr4_hour2: { // установка часов  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setHour(var);
        var = Relay[3].timeOFF.minute();
        go(scr4_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour2);
      };
      break;
    case scr4_min2: { // установка минут  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[3].timeOFF.hour() << F(">") << var                     << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setMinute(var);
        var = Relay[3].timeOFF.second();
        go(scr4_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min2);
      };
      break;
    case scr4_sec2: { // установка секунд  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr4);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec2);
      };
      break;
    case scr5: { // 5- экран
        lcd << F("SetTime:") << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.show();
      }
      Btn.Do    = [] {
        Time = now;
        go(scr5_hour);
      };
      JoyLR.Do1 = [] {go(scr4);};
      JoyLR.Do2 = [] {go(scr0);};
      break;
    case scr5_hour: {
        lcd << F("SetTime>") << Time.hh << F(":") << Time.mm << F(":") << Time.ss;
        lcd.show();
      }
      Btn.Do    = [] {go(scr5_min);};
      JoyLR.Do1 = [] {
        if (Time.hh > 0)Time.hh--;
        go(scr5_hour);
      };
      JoyLR.Do2 = [] {
        if (Time.hh < 23)Time.hh++;
        go(scr5_hour);
      };
      break;
    case scr5_min: {
        lcd << F("SetTime:") << Time.hh << F(">") << Time.mm << F(":") << Time.ss ;
        lcd.show();
      }
      Btn.Do    = [] {go(scr5_sec);};
      JoyLR.Do1 = [] {
        if (Time.mm > 0)Time.mm--;
        go(scr5_min);
      };
      JoyLR.Do2 = [] {
        if (Time.mm < 59)Time.mm++;
        go(scr5_min);
      };
      break;
    case scr5_sec: {
        lcd << F("SetTime:") << Time.hh << F(":") << Time.mm << F(">") << Time.ss;
        lcd.show();
      }
      Btn.Do = [] {
        rtc.write(Time);
        now = Time;
        go(scr5);
      };
      JoyLR.Do1 = [] {
        if (Time.ss > 0)Time.ss--;
        go(scr5_sec);
      };
      JoyLR.Do2 = [] {
        if (Time.ss < 59)Time.ss++;
        go(scr5_sec);
      };
      break;
  }
}
void menuInit() {
  lcd.lightON();
  now = rtc.read();
  JoyUD.Do1 = [] {lcd.lightON();};
  JoyUD.Do2 = [] {lcd.lightOFF();};
  go(scr0);
}
void menuRun() {
  if (scr != scr0 && millis() - past >= 3000)go(scr0);
  if (scr == scr0 && millis() - past >= 500)go(scr0);
}
//-----------------------------
void setup() {
  lcd.init();
  //rtc.write(F("00:00:00"));
  rtc.write(F(__TIME__));//(для первичной настройки часов)
  now = rtc.read();
  setZero();////(для первичной настройки устройства)
  for (int i = 0; i < RelayNum; i++)Relay[i].init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
}
void loop() {
  now_ = now;
  now = rtc.read();
  if (now_.time() - now.time() > 10)
    for (int i = 0; i < RelayNum; i++)Relay[i].reset();
  for (int i = 0; i < RelayNum; i++)Relay[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone пишет:

delayMicroseconds(4500); // wait min 4.1ms

А точно 4500 - это 4.1ms?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ворота пишет:
А точно 4500 - это 4.1ms?
А откуда мне  знать. Этот код пришлось брать из стандартных библиотек, да и комментарий оттуда же. Так-что  все притензии к автору :) И да там написано не меньше 4.1ms , а 4.5ms это побольше будет так что все Ок
ПС: Похоже передыдущий скетч не был избавлен от ошибок. Так что новый вариант.

/* часы с ручной установкой времени на DS3231*/
// Оборудование
// Ардуино Нано
// lcd1602_i2c  -- I2C
// модуль DS3231 -- I2C
// ардуино джойстик кнопка A0 потенциометры A1,A2
// модуль реле 2,3,4,5
//---------------lcd---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd1602_i2c-----------------------------
// даташит https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf
// на русском http://www.melt.aha.ru/pdf/mt-16s2h.pdf
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_lightON 0x08
#define LCD_lightOFF 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _lightONval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _lightONval = LCD_lightOFF;
      expanderWrite(_lightONval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void lightON(void) {
      _lightONval = LCD_lightON;
      expanderWrite(0);
    }
    void lightOFF(void) {
      _lightONval = LCD_lightOFF;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _lightONval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x27);//0x3F
//-----часы-----------------------
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
class dTime {
  protected:
  public:
    byte hh, mm, ss;
    unsigned long time() {
      return ((hh * 24 + mm) * 60 + ss);
    }
    dTime(unsigned long t = 0)
      : hh(t / 60 / 60 % 24), mm(t / 60 % 60), ss(t % 60) {}
    dTime(byte h, byte m, byte s)
      : hh(h), mm(m), ss(s) {}
    dTime(const dTime& t)//      : hh(copy.hh), mm(copy.mm), ss(copy.ss)
    {
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
    }
    dTime(const char* time) {
      hh = conv2d(time);
      mm = conv2d(time + 3);
      ss = conv2d(time + 6);
    }
    dTime(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      hh = conv2d(buff);
      mm = conv2d(buff + 3);
      ss = conv2d(buff + 6);
    }
    dTime& operator=(const dTime& t) {
      if (this == &t)
        return *this;
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
      return *this;
    }
};

#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F
#include <Wire.h>
uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.endTransmission();

  Wire.requestFrom(addr, (byte)1);
  return Wire.read();
}
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.write((byte)val);
  Wire.endTransmission();
}
uint8_t bcd2bin (uint8_t val) {
  return val - 6 * (val >> 4);
}
uint8_t bin2bcd (uint8_t val) {
  return val + 6 * (val / 10);
}
class RTC_DS3231 {
  public:
    void write(dTime t) {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0); // start at location 0
      Wire.write(bin2bcd(t.ss));
      Wire.write(bin2bcd(t.mm));
      Wire.write(bin2bcd(t.hh));
      Wire.endTransmission();
      uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
      statreg &= ~0x80; // flip OSF bit
      write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
    }
    dTime read() {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0);
      Wire.endTransmission();
      Wire.requestFrom(DS3231_ADDRESS, 7);
      uint8_t s = bcd2bin(Wire.read() & 0x7F);
      uint8_t m = bcd2bin(Wire.read());
      uint8_t h = bcd2bin(Wire.read());
      return dTime(h, m, s);
    }
};
RTC_DS3231  rtc;// часы
dTime now, now_; //текущее время
//--------------Реле------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;

} timer_t;
class cl_timer {
  protected:
    timer_t *adr;
  public:
    cl_timer(timer_t *a): adr(a) {}
    void save(unsigned long t = 0) {
      setHour(t / 60 / 60 % 24);
      setMinute(t / 60  % 60);
      setSecond(t % 60);
    }
    void save(const char* time) {
      setHour(conv2d(time));
      setMinute(conv2d(time + 3));
      setSecond(conv2d(time + 6));
    }
    void save(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      setHour(conv2d(buff));
      setMinute(conv2d(buff + 3));
      setSecond(conv2d(buff + 6));
    }
    byte hour() {
      return eeprom_read_byte(&(adr->hour));
    };
    byte minute() {
      return eeprom_read_byte(&(adr->minute));
    };
    byte second() {
      return eeprom_read_byte(&(adr->second));
    };
    byte time() {
      return ((hour() * 24 + minute()) * 60 + second());
    };

    void setHour(byte h) {
      eeprom_write_byte(&adr->hour, h);
    }
    void setMinute(byte m) {
      eeprom_write_byte(&adr->minute, m);
    }
    void setSecond(byte s) {
      eeprom_write_byte(&adr->second, s);
    }
};
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Relay {
  protected:
    byte pin;
    byte state;
    void set(byte s) {
      state = s;
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case sON:
          digitalWrite(pin, LOW);
          break;
        case sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    cl_timer timeON, timeOFF;
    Cl_Relay(byte p, cl_timer t1, cl_timer t2)
      : pin(p), timeON(t1), timeOFF(t2) {}
    void init() {
      pinMode(pin, OUTPUT);
      set(sOFF) ;
    }
    void run() {
      switch (state) {
        case sOFF:
          if (now.time() >= timeON.time())set(sON);
          break;
        case sON:
          if (now.time() >= timeOFF.time())set(sEND);
          break;
        case sEND: break;
      }
    }
    void reset() {
      set(sOFF) ;
    }
    void viev() {
      switch (state) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
};
const byte RelayNum = 4; //кол-во реле
timer_t EEMEM adr[RelayNum * 2];
Cl_Relay Relay[RelayNum] = {
  Cl_Relay(/*пин*/2, &adr[0], &adr[1]),// 1-е реле
  Cl_Relay(/*пин*/3, &adr[2], &adr[3]),// 2-е реле
  Cl_Relay(/*пин*/4, &adr[4], &adr[5]),// 3-е реле
  Cl_Relay(/*пин*/5, &adr[6], &adr[7]) // 4-е реле
};
// первичные настройки в EEPROM
void setZero() {
  Relay[0].timeON.save(F("00:00:30")); Relay[0].timeOFF.save(F("00:02:30"));// 1-е реле
  Relay[1].timeON.save(F("00:01:00")); Relay[1].timeOFF.save(F("00:03:00"));// 2-е реле
  Relay[2].timeON.save(F("00:01:30")); Relay[2].timeOFF.save(F("00:03:30"));// 3-е реле
  Relay[3].timeON.save(F("00:02:00")); Relay[3].timeOFF.save(F("00:04:00"));// 4-е реле
}
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------меню----------------
const byte scr0 = 0; // показ времени

const byte scr1       = 10; // показ времени реле1 вкл/выкл
const byte scr1_hour1 = 11; // установка часов  реле1 вкл
const byte scr1_min1  = 12; // установка минут  реле1 вкл
const byte scr1_sec1  = 13; // установка секунд реле1 вкл
const byte scr1_hour2 = 14; // установка часов  реле1 выкл
const byte scr1_min2  = 15; // установка минут  реле1 выкл
const byte scr1_sec2  = 16; // установка секунд реле1 выкл

const byte scr2       = 20; // показ времени реле2 вкл/выкл
const byte scr2_hour1 = 21; // установка часов  реле2 вкл
const byte scr2_min1  = 22; // установка минут  реле2 вкл
const byte scr2_sec1  = 23; // установка секунд реле2 вкл
const byte scr2_hour2 = 24; // установка часов  реле2 выкл
const byte scr2_min2  = 25; // установка минут  реле2 выкл
const byte scr2_sec2  = 26; // установка секунд реле2 выкл

const byte scr3       = 30; // показ времени реле3 вкл/выкл
const byte scr3_hour1 = 31; // установка часов  реле3 вкл
const byte scr3_min1  = 32; // установка минут  реле3 вкл
const byte scr3_sec1  = 33; // установка секунд реле3 вкл
const byte scr3_hour2 = 34; // установка часов  реле3 выкл
const byte scr3_min2  = 35; // установка минут  реле3 выкл
const byte scr3_sec2  = 36; // установка секунд реле3 выкл

const byte scr4       = 40; // показ времени реле4 вкл/выкл
const byte scr4_hour1 = 41; // установка часов  реле4 вкл
const byte scr4_min1  = 42; // установка минут  реле4 вкл
const byte scr4_sec1  = 43; // установка секунд реле4 вкл
const byte scr4_hour2 = 44; // установка часов  реле4 выкл
const byte scr4_min2  = 45; // установка минут  реле4 выкл
const byte scr4_sec2  = 46; // установка секунд реле4 выкл

const byte scr5      = 50;
const byte scr5_hour = 51; // установка времени часы
const byte scr5_min  = 52; // установка времени минуты
const byte scr5_sec  = 53; // установка времени секунд
const byte scr5_res  = 54; // установка времени секунд
byte scr; // номер экрана
unsigned long past;// фик времени в этом экране
byte var;// переменная для редактирования
dTime Time;// переменая времени
void go(byte s) {
  scr = s;
  past = millis();
  lcd.clear();
  switch (s) {
    case scr0: { // 0- экран
        lcd << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.setCursor(9, 0);
        Relay[0].viev(); lcd << F(" ");
        Relay[1].viev(); lcd << F(" ");
        lcd.setCursor(9, 1);
        Relay[2].viev(); lcd << F(" ");
        Relay[3].viev(); lcd << F(" ");
        lcd.show();
      }
      Btn.Do = [] {};
      JoyLR.Do1 = [] {};
      JoyLR.Do2 = [] {go(scr1);};
      break;
    case scr1: { // ------------------------------1- экран
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[0].timeON.hour();
        go(scr1_hour1);
      };
      JoyLR.Do1 = [] {go(scr0);};
      JoyLR.Do2 = [] {go(scr2);};
      break;
    case scr1_hour1: { // установка часов  реле1 вкл
        lcd  << F("Re1>") << var << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setHour(var);
        var = Relay[0].timeON.minute();
        go(scr1_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour1);
      };
      break;
    case scr1_min1: { // установка минут  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(">") << var << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr1_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min1);
      };
      break;
    case scr1_sec1: { // установка секунд  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[0].timeOFF.hour();
        go(scr1_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec1);
      };
      break;
    case scr1_hour2: { // установка часов  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setHour(var);
        var = Relay[0].timeOFF.minute();
        go(scr1_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour2);
      };
      break;
    case scr1_min2: { // установка минут  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[0].timeOFF.hour() << F(">") << var                     << F(":") << Relay[0].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr1_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min2);
      };
      break;
    case scr1_sec2: { // установка секунд  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setSecond(var);
        go(scr1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec2);
      };
      break;
    case scr2: { //------------------------------------------------ 2- экран
        lcd  << F("Re2 ")  << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[1].timeON.hour();
        go(scr2_hour1);
      };
      JoyLR.Do1 = [] {go(scr1);};
      JoyLR.Do2 = [] {go(scr3);};
      break;
    case scr2_hour1: { // установка часов  реле2 вкл
        lcd  << F("Re2>") << var << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setHour(var);
        var = Relay[1].timeON.minute();
        go(scr2_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour1);
      };
      break;
    case scr2_min1: { // установка минут  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(">") << var << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setMinute(var);
        var = Relay[1].timeON.second();
        go(scr2_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min1);
      };
      break;
    case scr2_sec1: { // установка секунд  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeON.setSecond(var);
        var = Relay[1].timeOFF.hour();
        go(scr2_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec1);
      };
      break;
    case scr2_hour2: { // установка часов  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setHour(var);
        var = Relay[1].timeOFF.minute();
        go(scr2_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour2);
      };
      break;
    case scr2_min2: { // установка минут  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[1].timeOFF.hour() << F(">") << var                     << F(":") << Relay[1].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setMinute(var);
        var = Relay[1].timeOFF.second();
        go(scr2_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min2);
      };
      break;
    case scr2_sec2: { // установка секунд  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setSecond(var);
        go(scr2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec2);
      };
      break;
    case scr3: { //---------------------------------- 3- экран
        lcd  << F("Re3 ")  << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[2].timeON.hour();
        go(scr3_hour1);
      };
      JoyLR.Do1 = [] {go(scr2);};
      JoyLR.Do2 = [] {go(scr4);};
      break;
    case scr3_hour1: { // установка часов  реле3 вкл
        lcd  << F("Re3>") << var << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setHour(var);
        var = Relay[2].timeON.minute();
        go(scr3_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour1);
      };
      break;
    case scr3_min1: { // установка минут  реле1 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(">") << var << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setMinute(var);
        var = Relay[2].timeON.second();
        go(scr3_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min1);
      };
      break;
    case scr3_sec1: { // установка секунд  реле3 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeON.setSecond(var);
        var = Relay[2].timeOFF.hour();
        go(scr3_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec1);
      };
      break;
    case scr3_hour2: { // установка часов  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[2].timeOFF.setHour(var);
        var = Relay[2].timeOFF.minute();
        go(scr3_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour2);
      };
      break;
    case scr3_min2: { // установка минут  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[2].timeOFF.hour() << F(">") << var                     << F(":") << Relay[2].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr3_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min2);
      };
      break;
    case scr3_sec2: { // установка секунд  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr3);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec2);
      };
      break;
    case scr4: { // 4- экран
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[3].timeON.hour();
        go(scr4_hour1);
      };
      JoyLR.Do1 = [] {go(scr3);};
      JoyLR.Do2 = [] {go(scr5);};
      break;
    case scr4_hour1: { // установка часов  реле4 вкл
        lcd  << F("Re4>") << var << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeON.setHour(var);
        var = Relay[3].timeON.minute();
        go(scr4_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour1);
      };
      break;
    case scr4_min1: { // установка минут  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(">") << var << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr4_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min1);
      };
      break;
    case scr4_sec1: { // установка секунд  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[3].timeOFF.hour();
        go(scr4_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec1);
      };
      break;
    case scr4_hour2: { // установка часов  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setHour(var);
        var = Relay[3].timeOFF.minute();
        go(scr4_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour2);
      };
      break;
    case scr4_min2: { // установка минут  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[3].timeOFF.hour() << F(">") << var                     << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setMinute(var);
        var = Relay[3].timeOFF.second();
        go(scr4_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min2);
      };
      break;
    case scr4_sec2: { // установка секунд  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(">") << var;
        lcd.show();
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr4);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec2);
      };
      break;
    case scr5: { // 5- экран
        lcd << F("SetTime:") << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.show();
      }
      Btn.Do    = [] {
        Time = now;
        go(scr5_hour);
      };
      JoyLR.Do1 = [] {go(scr4);};
      JoyLR.Do2 = [] {go(scr0);};
      break;
    case scr5_hour: {
        lcd << F("SetTime>") << Time.hh << F(":") << Time.mm << F(":") << Time.ss;
        lcd.show();
      }
      Btn.Do    = [] {go(scr5_min);};
      JoyLR.Do1 = [] {
        if (Time.hh > 0)Time.hh--;
        go(scr5_hour);
      };
      JoyLR.Do2 = [] {
        if (Time.hh < 23)Time.hh++;
        go(scr5_hour);
      };
      break;
    case scr5_min: {
        lcd << F("SetTime:") << Time.hh << F(">") << Time.mm << F(":") << Time.ss ;
        lcd.show();
      }
      Btn.Do    = [] {go(scr5_sec);};
      JoyLR.Do1 = [] {
        if (Time.mm > 0)Time.mm--;
        go(scr5_min);
      };
      JoyLR.Do2 = [] {
        if (Time.mm < 59)Time.mm++;
        go(scr5_min);
      };
      break;
    case scr5_sec: {
        lcd << F("SetTime:") << Time.hh << F(":") << Time.mm << F(">") << Time.ss;
        lcd.show();
      }
      Btn.Do = [] {
        rtc.write(Time);
        now = Time;
        for (int i = 0; i < RelayNum; i++)Relay[i].reset();
        go(scr5);
      };
      JoyLR.Do1 = [] {
        if (Time.ss > 0)Time.ss--;
        go(scr5_sec);
      };
      JoyLR.Do2 = [] {
        if (Time.ss < 59)Time.ss++;
        go(scr5_sec);
      };
      break;
  }
}
void menuInit() {
  lcd.lightON();
  now = rtc.read();
  JoyUD.Do1 = [] {lcd.lightON();};
  JoyUD.Do2 = [] {lcd.lightOFF();};
  go(scr0);
}
void menuRun() {
  if (scr != scr0 && millis() - past >= 3000)go(scr0);
  if (scr == scr0 && millis() - past >= 500)go(scr0);
}
//-----------------------------
void setup() {
  lcd.init();
  //rtc.write(F("00:00:00"));
  rtc.write(F(__TIME__));//(для первичной настройки часов)
  now = rtc.read();
  setZero();////(для первичной настройки устройства)
  for (int i = 0; i < RelayNum; i++)Relay[i].init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
}
void loop() {
  now_ = now;
  now = rtc.read();
  if (now_.hh == 23 && now.hh == 0)
    for (int i = 0; i < RelayNum; i++)Relay[i].reset();
  for (int i = 0; i < RelayNum; i++)Relay[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А это мало кого заинтересует

/**/
class Cl_lcd: public Print {
  protected:
  public:
    void init() {
      Serial.begin(9600);
    }
    inline size_t write(uint8_t value) {
      Serial.write(value);
      return 1;
    }
};
typedef Cl_lcd& (*pDo)(Cl_lcd&);
inline Cl_lcd & operator << (Cl_lcd &s, pDo Do) {
  Do(s);
  return s;
}
inline Cl_lcd & operator << (Cl_lcd &s, const char *n) {
  s.print(n);
  return s;
}
Cl_lcd& clear(Cl_lcd& s) {
  s.print("<clear>");
  return s;
}
Cl_lcd lcd;
//------------------------------
class Cl_Data {
  protected:
    byte value;
  public:
    Cl_Data (byte v): value(v) {}
    friend Cl_lcd & operator << (Cl_lcd &s, Cl_Data obj) {
      s.print(obj.value);
      return s;
    }
};
Cl_Data Data(5);
//---------------------------
void setup() {
  lcd.init();
  clear(lcd) << "aa:" << Data << " bbb" << clear;
}

void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Специализация шаблонов функций

template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
template <> inline Print & operator << (Print &s, byte n) {
  if (n < 10)s.print(" ");
  s.print(n);
  return s;
}
void setup() {
  Serial.begin(9600);
  byte time = 9;
  Serial << "T:" << time << " :" << time << ":" << time;
}
void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну пока так.

/* часы с ручной установкой времени на DS3231*/
// Оборудование
// Ардуино Нано
// lcd1602_i2c  -- I2C
// модуль DS3231 -- I2C
// ардуино джойстик кнопка A0 потенциометры A1,A2
// модуль на 4x-реле 2,3,4,5
//---------------lcd---------------------------------------------

//------дисплей lcd1602_i2c-----------------------------
// даташит <a href="https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf" title="https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf" rel="nofollow">https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf</a>
// на русском <a href="http://www.melt.aha.ru/pdf/mt-16s2h.pdf" title="http://www.melt.aha.ru/pdf/mt-16s2h.pdf" rel="nofollow">http://www.melt.aha.ru/pdf/mt-16s2h.pdf</a>
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_lightON 0x08
#define LCD_lightOFF 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _lightONval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _lightONval = LCD_lightOFF;
      expanderWrite(_lightONval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void lightON(void) {
      _lightONval = LCD_lightON;
      expanderWrite(0);
    }
    void lightOFF(void) {
      _lightONval = LCD_lightOFF;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _lightONval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};

typedef Cl_lcd1602_i2c& (*pDo1)(Cl_lcd1602_i2c&);
template <typename T> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, T n) {
  s.print(n);
  return s;
}
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, pDo1 Do) {
  Do(s);
  return s;
}
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, byte n) {
  if (n < 10)s.print("0");
  s.print(n);
  return s;
}
Cl_lcd1602_i2c& clear(Cl_lcd1602_i2c& s) {
  s.clear();
  return s;
}
Cl_lcd1602_i2c& show(Cl_lcd1602_i2c& s) {
  s.show();
  return s;
}
Cl_lcd1602_i2c lcd(0x27);//0x3F
//-----часы-----------------------
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
class dTime {
  protected:
  public:
    byte hh, mm, ss;
    unsigned long time() {
      return ((hh * 24 + mm) * 60 + ss);
    }
    dTime(unsigned long t = 0)
      : hh(t / 60 / 60 % 24), mm(t / 60 % 60), ss(t % 60) {}
    dTime(byte h, byte m, byte s)
      : hh(h), mm(m), ss(s) {}
    dTime(const dTime& t)//      : hh(copy.hh), mm(copy.mm), ss(copy.ss)
    {
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
    }
    dTime(const char* time) {
      hh = conv2d(time);
      mm = conv2d(time + 3);
      ss = conv2d(time + 6);
    }
    dTime(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      hh = conv2d(buff);
      mm = conv2d(buff + 3);
      ss = conv2d(buff + 6);
    }
    dTime& operator=(const dTime& t) {
      if (this == &t)
        return *this;
      hh = t.hh;
      mm = t.mm;
      ss = t.ss;
      return *this;
    }
};

#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F
#include <Wire.h>
uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.endTransmission();

  Wire.requestFrom(addr, (byte)1);
  return Wire.read();
}
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.write((byte)val);
  Wire.endTransmission();
}
uint8_t bcd2bin (uint8_t val) {
  return val - 6 * (val >> 4);
}
uint8_t bin2bcd (uint8_t val) {
  return val + 6 * (val / 10);
}
class RTC_DS3231 {
  public:
    void write(dTime t) {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0); // start at location 0
      Wire.write(bin2bcd(t.ss));
      Wire.write(bin2bcd(t.mm));
      Wire.write(bin2bcd(t.hh));
      Wire.endTransmission();
      uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
      statreg &= ~0x80; // flip OSF bit
      write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
    }
    dTime read() {
      Wire.beginTransmission(DS3231_ADDRESS);
      Wire.write((byte)0);
      Wire.endTransmission();
      Wire.requestFrom(DS3231_ADDRESS, 7);
      uint8_t s = bcd2bin(Wire.read() & 0x7F);
      uint8_t m = bcd2bin(Wire.read());
      uint8_t h = bcd2bin(Wire.read());
      return dTime(h, m, s);
    }
};
RTC_DS3231  rtc;// часы
dTime now, now_; //текущее время
//--------------Реле------------------------------------------------
typedef struct {
  byte hour;
  byte minute;
  byte second;

} timer_t;
class cl_timer {
  protected:
    timer_t *adr;
  public:
    cl_timer(timer_t *a): adr(a) {}
    void save(unsigned long t = 0) {
      setHour(t / 60 / 60 % 24);
      setMinute(t / 60  % 60);
      setSecond(t % 60);
    }
    void save(const char* time) {
      setHour(conv2d(time));
      setMinute(conv2d(time + 3));
      setSecond(conv2d(time + 6));
    }
    void save(const __FlashStringHelper* time) {
      char buff[8];
      memcpy_P(buff, time, 8);
      setHour(conv2d(buff));
      setMinute(conv2d(buff + 3));
      setSecond(conv2d(buff + 6));
    }
    byte hour() {
      return eeprom_read_byte(&(adr->hour));
    };
    byte minute() {
      return eeprom_read_byte(&(adr->minute));
    };
    byte second() {
      return eeprom_read_byte(&(adr->second));
    };
    byte time() {
      return ((hour() * 24 + minute()) * 60 + second());
    };

    void setHour(byte h) {
      eeprom_write_byte(&adr->hour, h);
    }
    void setMinute(byte m) {
      eeprom_write_byte(&adr->minute, m);
    }
    void setSecond(byte s) {
      eeprom_write_byte(&adr->second, s);
    }
};
/*состояния таймера*/
const byte sOFF = 0;
const byte sON  = 1;
const byte sEND = 2;
class Cl_Relay {
  protected:
    byte pin;
    byte state;
    void set(byte s) {
      state = s;
      switch (s) {
        case sOFF:
          digitalWrite(pin, HIGH);
          break;
        case sON:
          digitalWrite(pin, LOW);
          break;
        case sEND:
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    cl_timer timeON, timeOFF;
    Cl_Relay(byte p, cl_timer t1, cl_timer t2)
      : pin(p), timeON(t1), timeOFF(t2) {}
    void init() {
      pinMode(pin, OUTPUT);
      set(sOFF) ;
    }
    void run() {
      switch (state) {
        case sOFF:
          if (now.time() >= timeON.time())set(sON);
          break;
        case sON:
          if (now.time() >= timeOFF.time())set(sEND);
          break;
        case sEND: break;
      }
    }
    void reset() {
      set(sOFF) ;
    }
    void viev() {
      switch (state) {
        case sOFF:
          lcd << F("OFF");
          break;
        case  sON:
          lcd << F("ON ");
          break;
        case  sEND:
          lcd << F("END");
          break;
      }
    }
};

const byte RelayNum = 4; //кол-во реле
timer_t EEMEM adr[RelayNum * 2];
Cl_Relay Relay[RelayNum] = {
  Cl_Relay(/*пин*/2, &adr[0], &adr[1]),// 1-е реле
  Cl_Relay(/*пин*/3, &adr[2], &adr[3]),// 2-е реле
  Cl_Relay(/*пин*/4, &adr[4], &adr[5]),// 3-е реле
  Cl_Relay(/*пин*/5, &adr[6], &adr[7]) // 4-е реле
};
// первичные настройки в EEPROM
void setZero() {
  Relay[0].timeON.save(F("00:00:30")); Relay[0].timeOFF.save(F("00:02:30"));// 1-е реле
  Relay[1].timeON.save(F("00:01:00")); Relay[1].timeOFF.save(F("00:03:00"));// 2-е реле
  Relay[2].timeON.save(F("00:01:30")); Relay[2].timeOFF.save(F("00:03:30"));// 3-е реле
  Relay[3].timeON.save(F("00:02:00")); Relay[3].timeOFF.save(F("00:04:00"));// 4-е реле
}
//---кнопкa-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      switch (s) {
        case false:
          break;
        case true:
          Do();
          break;
      }
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn Btn(/*пин*/A0);
//-------------------------------------------
const byte st1 = 0;
const byte st0 = 1;
const byte st2 = 2;
class Cl_joystic {
  protected:
    byte pin;
    byte state;
    unsigned long past;
    void set(byte s) {
      state = s;
      past = millis();
      switch (s) {
        case st0:
          break;
        case st1:
          Do1();
          break;
        case st2:
          Do2();
          break;
      }
    }
  public:
    Cl_joystic(byte p): pin(p) {}
    pDo Do1 = [] {};
    pDo Do2 = [] {};
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= 100) {
        int tmp = analogRead(pin);
        switch (state) {
          case st1:
            if (tmp > 450)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
          case st0:
            if (tmp < 400)set(st1);
            else if (tmp > 600)set(st2);
            break;
          case st2:
            if (tmp < 550)set(st0);
            if (millis() - past >= 300)set(st0);
            break;
        }
      }
    }
};
Cl_joystic JoyLR(/*пин*/A1);
Cl_joystic JoyUD(/*пин*/A2);
//---------меню----------------
const byte scr0 = 0; // показ времени

const byte scr1       = 10; // показ времени реле1 вкл/выкл
const byte scr1_hour1 = 11; // установка часов  реле1 вкл
const byte scr1_min1  = 12; // установка минут  реле1 вкл
const byte scr1_sec1  = 13; // установка секунд реле1 вкл
const byte scr1_hour2 = 14; // установка часов  реле1 выкл
const byte scr1_min2  = 15; // установка минут  реле1 выкл
const byte scr1_sec2  = 16; // установка секунд реле1 выкл

const byte scr2       = 20; // показ времени реле2 вкл/выкл
const byte scr2_hour1 = 21; // установка часов  реле2 вкл
const byte scr2_min1  = 22; // установка минут  реле2 вкл
const byte scr2_sec1  = 23; // установка секунд реле2 вкл
const byte scr2_hour2 = 24; // установка часов  реле2 выкл
const byte scr2_min2  = 25; // установка минут  реле2 выкл
const byte scr2_sec2  = 26; // установка секунд реле2 выкл

const byte scr3       = 30; // показ времени реле3 вкл/выкл
const byte scr3_hour1 = 31; // установка часов  реле3 вкл
const byte scr3_min1  = 32; // установка минут  реле3 вкл
const byte scr3_sec1  = 33; // установка секунд реле3 вкл
const byte scr3_hour2 = 34; // установка часов  реле3 выкл
const byte scr3_min2  = 35; // установка минут  реле3 выкл
const byte scr3_sec2  = 36; // установка секунд реле3 выкл

const byte scr4       = 40; // показ времени реле4 вкл/выкл
const byte scr4_hour1 = 41; // установка часов  реле4 вкл
const byte scr4_min1  = 42; // установка минут  реле4 вкл
const byte scr4_sec1  = 43; // установка секунд реле4 вкл
const byte scr4_hour2 = 44; // установка часов  реле4 выкл
const byte scr4_min2  = 45; // установка минут  реле4 выкл
const byte scr4_sec2  = 46; // установка секунд реле4 выкл

const byte scr5      = 50; // показ времени
const byte scr5_hour = 51; // установка времени часы
const byte scr5_min  = 52; // установка времени минуты
const byte scr5_sec  = 53; // установка времени секунд
byte scr; // номер экрана
unsigned long past;// фик времени в этом экране
byte var;// переменная для редактирования
dTime Time;// переменая времени
void go(byte s) {
  scr = s;
  past = millis();
  lcd << clear;
  switch (s) {
    case scr0: { // 0- экран
        lcd << now.hh << F(":") << now.mm << F(":") << now.ss ;
        lcd.setCursor(9, 0);
        Relay[0].viev(); lcd  << F(" "); Relay[1].viev();
        lcd.setCursor(9, 1);
        Relay[2].viev(); lcd  << F(" "); Relay[3].viev(); lcd << show;
      }
      Btn.Do = [] {};
      JoyLR.Do1 = [] {};
      JoyLR.Do2 = [] {go(scr1);};
      break;
    case scr1: { // ------------------------------1- экран
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        var = Relay[0].timeON.hour();
        go(scr1_hour1);
      };
      JoyLR.Do1 = [] {go(scr0);};
      JoyLR.Do2 = [] {go(scr2);};
      break;
    case scr1_hour1: { // установка часов  реле1 вкл
        lcd  << F("Re1>") << var << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeON.setHour(var);
        var = Relay[0].timeON.minute();
        go(scr1_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour1);
      };
      break;
    case scr1_min1: { // установка минут  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(">") << var << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr1_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min1);
      };
      break;
    case scr1_sec1: { // установка секунд  реле1 вкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[0].timeOFF.hour();
        go(scr1_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec1);
      };
      break;
    case scr1_hour2: { // установка часов  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[0].timeOFF.minute() << F(":") << Relay[0].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setHour(var);
        var = Relay[0].timeOFF.minute();
        go(scr1_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr1_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_hour2);
      };
      break;
    case scr1_min2: { // установка минут  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[0].timeOFF.hour() << F(">") << var                     << F(":") << Relay[0].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr1_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_min2);
      };
      break;
    case scr1_sec2: { // установка секунд  реле1 выкл
        lcd  << F("Re1 ") << Relay[0].timeON.hour() << F(":") << Relay[0].timeON.minute() << F(":") << Relay[0].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[0].timeOFF.hour() << F(":") << Relay[0].timeOFF.minute() << F(">") << var << show;
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setSecond(var);
        go(scr1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr1_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr1_sec2);
      };
      break;
    case scr2: { //------------------------------------------------ 2- экран
        lcd  << F("Re2 ")  << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        var = Relay[1].timeON.hour();
        go(scr2_hour1);
      };
      JoyLR.Do1 = [] {go(scr1);};
      JoyLR.Do2 = [] {go(scr3);};
      break;
    case scr2_hour1: { // установка часов  реле2 вкл
        lcd  << F("Re2>") << var << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[1].timeON.setHour(var);
        var = Relay[1].timeON.minute();
        go(scr2_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour1);
      };
      break;
    case scr2_min1: { // установка минут  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(">") << var << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[1].timeON.setMinute(var);
        var = Relay[1].timeON.second();
        go(scr2_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min1);
      };
      break;
    case scr2_sec1: { // установка секунд  реле2 вкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[1].timeON.setSecond(var);
        var = Relay[1].timeOFF.hour();
        go(scr2_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec1);
      };
      break;
    case scr2_hour2: { // установка часов  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[1].timeOFF.minute() << F(":") << Relay[1].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setHour(var);
        var = Relay[1].timeOFF.minute();
        go(scr2_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr2_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_hour2);
      };
      break;
    case scr2_min2: { // установка минут  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[1].timeOFF.hour() << F(">") << var                     << F(":") << Relay[1].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setMinute(var);
        var = Relay[1].timeOFF.second();
        go(scr2_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_min2);
      };
      break;
    case scr2_sec2: { // установка секунд  реле2 выкл
        lcd  << F("Re2 ") << Relay[1].timeON.hour() << F(":") << Relay[1].timeON.minute() << F(":") << Relay[1].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[1].timeOFF.hour() << F(":") << Relay[1].timeOFF.minute() << F(">") << var << show;
      }
      Btn.Do    = [] {
        Relay[1].timeOFF.setSecond(var);
        go(scr2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr2_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr2_sec2);
      };
      break;
    case scr3: { //---------------------------------- 3- экран
        lcd  << F("Re3 ")  << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        var = Relay[2].timeON.hour();
        go(scr3_hour1);
      };
      JoyLR.Do1 = [] {go(scr2);};
      JoyLR.Do2 = [] {go(scr4);};
      break;
    case scr3_hour1: { // установка часов  реле3 вкл
        lcd  << F("Re3>") << var << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[2].timeON.setHour(var);
        var = Relay[2].timeON.minute();
        go(scr3_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour1);
      };
      break;
    case scr3_min1: { // установка минут  реле1 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(">") << var << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[2].timeON.setMinute(var);
        var = Relay[2].timeON.second();
        go(scr3_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min1);
      };
      break;
    case scr3_sec1: { // установка секунд  реле3 вкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[2].timeON.setSecond(var);
        var = Relay[2].timeOFF.hour();
        go(scr3_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec1);
      };
      break;
    case scr3_hour2: { // установка часов  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[2].timeOFF.minute() << F(":") << Relay[2].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[2].timeOFF.setHour(var);
        var = Relay[2].timeOFF.minute();
        go(scr3_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr3_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_hour2);
      };
      break;
    case scr3_min2: { // установка минут  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[2].timeOFF.hour() << F(">") << var                     << F(":") << Relay[2].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeOFF.setMinute(var);
        var = Relay[0].timeOFF.second();
        go(scr3_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_min2);
      };
      break;
    case scr3_sec2: { // установка секунд  реле3 выкл
        lcd  << F("Re3 ") << Relay[2].timeON.hour() << F(":") << Relay[2].timeON.minute() << F(":") << Relay[2].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[2].timeOFF.hour() << F(":") << Relay[2].timeOFF.minute() << F(">") << var << show;
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr3);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr3_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr3_sec2);
      };
      break;
    case scr4: { // 4- экран
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second();
        lcd.show();
      }
      Btn.Do    = [] {
        var = Relay[3].timeON.hour();
        go(scr4_hour1);
      };
      JoyLR.Do1 = [] {go(scr3);};
      JoyLR.Do2 = [] {go(scr5);};
      break;
    case scr4_hour1: { // установка часов  реле4 вкл
        lcd  << F("Re4>") << var << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[3].timeON.setHour(var);
        var = Relay[3].timeON.minute();
        go(scr4_min1);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour1);
      };
      break;
    case scr4_min1: { // установка минут  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(">") << var << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeON.setMinute(var);
        var = Relay[0].timeON.second();
        go(scr4_sec1);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min1);
      };
      break;
    case scr4_sec1: { // установка секунд  реле4 вкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(">") << var;
        lcd.setCursor(4, 1);
        lcd  << Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[0].timeON.setSecond(var);
        var = Relay[3].timeOFF.hour();
        go(scr4_hour2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec1);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec1);
      };
      break;
    case scr4_hour2: { // установка часов  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(3, 1);
        lcd << F(">") << var                       << F(":") << Relay[3].timeOFF.minute() << F(":") << Relay[3].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setHour(var);
        var = Relay[3].timeOFF.minute();
        go(scr4_min2);
      };
      JoyLR.Do1 = [] {
        if (var < 23)var++;
        go(scr4_hour2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_hour2);
      };
      break;
    case scr4_min2: { // установка минут  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd               << Relay[3].timeOFF.hour() << F(">") << var                     << F(":") << Relay[3].timeOFF.second() << show;
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setMinute(var);
        var = Relay[3].timeOFF.second();
        go(scr4_sec2);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_min2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_min2);
      };
      break;
    case scr4_sec2: { // установка секунд  реле4 выкл
        lcd  << F("Re4 ") << Relay[3].timeON.hour() << F(":") << Relay[3].timeON.minute() << F(":") << Relay[3].timeON.second();
        lcd.setCursor(4, 1);
        lcd  <<             Relay[3].timeOFF.hour() << F(":") << Relay[3].timeOFF.minute() << F(">") << var << show;
      }
      Btn.Do    = [] {
        Relay[3].timeOFF.setSecond(var);
        go(scr4);
      };
      JoyLR.Do1 = [] {
        if (var < 59)var++;
        go(scr4_sec2);
      };
      JoyLR.Do2 = [] {
        if (var > 0)var--;
        go(scr4_sec2);
      };
      break;
    case scr5: { // 5- экран
        lcd << F("SetTime:") << now.hh << F(":") << now.mm << F(":") << now.ss << show;;
      }
      Btn.Do    = [] {
        Time = now;
        go(scr5_hour);
      };
      JoyLR.Do1 = [] {go(scr4);};
      JoyLR.Do2 = [] {go(scr0);};
      break;
    case scr5_hour: {
        lcd << F("SetTime>") << Time.hh << F(":") << Time.mm << F(":") << Time.ss << show;
      }
      Btn.Do    = [] {go(scr5_min);};
      JoyLR.Do1 = [] {
        if (Time.hh > 0)Time.hh--;
        go(scr5_hour);
      };
      JoyLR.Do2 = [] {
        if (Time.hh < 23)Time.hh++;
        go(scr5_hour);
      };
      break;
    case scr5_min: {
        lcd << F("SetTime:") << Time.hh << F(">") << Time.mm << F(":") << Time.ss << show;
      }
      Btn.Do    = [] {go(scr5_sec);};
      JoyLR.Do1 = [] {
        if (Time.mm > 0)Time.mm--;
        go(scr5_min);
      };
      JoyLR.Do2 = [] {
        if (Time.mm < 59)Time.mm++;
        go(scr5_min);
      };
      break;
    case scr5_sec: {
        lcd << F("SetTime:") << Time.hh << F(":") << Time.mm << F(">") << Time.ss << show;
      }
      Btn.Do = [] {
        rtc.write(Time);
        now = Time;
        for (int i = 0; i < RelayNum; i++)Relay[i].reset();
        go(scr5);
      };
      JoyLR.Do1 = [] {
        if (Time.ss > 0)Time.ss--;
        go(scr5_sec);
      };
      JoyLR.Do2 = [] {
        if (Time.ss < 59)Time.ss++;
        go(scr5_sec);
      };
      break;
  }
}
void menuInit() {
  lcd.lightON();
  now = rtc.read();
  JoyUD.Do1 = [] {lcd.lightON();};
  JoyUD.Do2 = [] {lcd.lightOFF();};
  go(scr0);
}
void menuRun() {
  if (scr != scr0 && millis() - past >= 3000)go(scr0);
  if (scr == scr0 && millis() - past >= 500)go(scr0);
  if (scr == scr5 && millis() - past >= 500)go(scr5);
}
//-----------------------------
void setup() {
  lcd.init();
  //rtc.write(F("00:00:00"));
  rtc.write(F(__TIME__));//(для первичной настройки часов)
  now = rtc.read();
  setZero();////(для первичной настройки устройства)
  for (int i = 0; i < RelayNum; i++)Relay[i].init();
  Btn.init();
  JoyLR.init();
  JoyUD.init();
  menuInit();
}
void loop() {
  now_ = now;
  now = rtc.read();
  if (now_.hh == 23 && now.hh == 0) // если настал новый день
    for (int i = 0; i < RelayNum; i++)Relay[i].reset();// то сбросить реле
  for (int i = 0; i < RelayNum; i++)Relay[i].run();
  Btn.run();
  JoyLR.run();
  JoyUD.run();
  menuRun();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

так "мысли вслух"

/**/
class Cl_data {//<-недостаток2 - класс должен быть объявлен заранее
  public:
    byte value, value1;//<- недостаток - данные должны быть открыты
    Cl_data(byte v, byte v1)
      : value(v), value1(v1) {}
};
// специализация шаблона <<
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
template <> inline Print & operator << (Print &s, byte n) {
  if (n < 10)s.print("0");
  s.print(n);
  return s;
}
template <> inline Print & operator << (Print &s, Cl_data n) {
  return s << "data:" << n.value << "," << n.value1;
}
Cl_data data(5, 20);
void setup() {
  Serial.begin(9600);
  byte time = 9;
  Serial << "T:" << time << "  " << data;
}
void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
typedef HardwareSerial& (*pDo1)(HardwareSerial&);
//-------часы блок.h-------------------------------
uint8_t conv2d(const char* p);
class dTime {
  protected:
  public:
    byte hour, minute, second;
    dTime(unsigned long t = 0);
    dTime(byte h, byte m, byte s);
    dTime(const dTime& t);
    dTime(const char* time);
    dTime(const __FlashStringHelper* time);
    unsigned long time();
    dTime& operator=(const dTime& t);
};
uint8_t conv2d(const char* p);
//-------часы блок.cpp-------------------------------
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
dTime::dTime(unsigned long t)
  : hour(t / 60 / 60 % 24), minute(t / 60 % 60), second(t % 60) {}
dTime::dTime(const dTime& t)//      : hour(copy.hour), minute(copy.minute), second(copy.second)
{
  hour = t.hour;
  minute = t.minute;
  second = t.second;
}
dTime::dTime(byte h, byte m, byte s)
  : hour(h), minute(m), second(s) {}
dTime::dTime(const char* time) {
  hour = conv2d(time);
  minute = conv2d(time + 3);
  second = conv2d(time + 6);
}
dTime::dTime(const __FlashStringHelper* time) {
  char buff[8];
  memcpy_P(buff, time, 8);
  hour = conv2d(buff);
  minute = conv2d(buff + 3);
  second = conv2d(buff + 6);
}
unsigned long dTime::time() {
  return ((hour * 24 + minute) * 60 + second);
}
dTime&  dTime::operator=(const dTime& t) {
  if (this == &t)
    return *this;
  hour = t.hour;
  minute = t.minute;
  second = t.second;
  return *this;
}
dTime now("01:01:01");
//-----------------------------------
// специализация шаблона <<
template <typename T> inline HardwareSerial & operator << (HardwareSerial &s, T n) {
  s.print(n);
  return s;
}
template <> inline HardwareSerial & operator << (HardwareSerial &s, pDo1 Do) {
  Do(s);
  return s;
}
template <> inline HardwareSerial & operator << (HardwareSerial &s, byte n) {
  if (n < 10)s.print("0");
  s.print(n);
  return s;
}
template <> inline HardwareSerial & operator << (HardwareSerial &s, dTime obj) {
  return s << "time:" << obj.hour << ":" << obj.minute << ":" << obj.second ;
}
HardwareSerial & endl(HardwareSerial & streem) {
  streem << "\n";
  return streem;
}
void setup() {
  Serial.begin(9600);
  now = dTime(F(__TIME__));
  Serial << now << endl;
  Serial << now << endl;
  Serial << now << endl;
}
void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/*
Не забудьте подключить часы DS3231 на I2C
*/
typedef HardwareSerial& (*pDo1)(HardwareSerial&);
//-------часы блок.h-------------------------------
#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F

#include <Wire.h>
class dTime {
  protected:
  public:
    byte hour, minute, second;
    dTime(unsigned long t = 0);
    dTime(byte h, byte m, byte s);
    dTime(const dTime& t);
    dTime(const char* time);
    dTime(const __FlashStringHelper* time);
    unsigned long time();
    dTime& operator=(const dTime& t);
};
class RTC_DS3231 {
  public:
    void write(dTime t);// записать время в часы
    dTime read();// прочитать время из часов
};
uint8_t read_i2c_register(uint8_t addr, uint8_t reg);
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val);

uint8_t conv2d(const char* p);
uint8_t bcd2bin (uint8_t val);
uint8_t bin2bcd (uint8_t val);
//-------часы блок.cpp-------------------------------
dTime::dTime(unsigned long t)
  : hour(t / 60 / 60 % 24), minute(t / 60 % 60), second(t % 60) {}
dTime::dTime(const dTime& t)//      : hour(copy.hour), minute(copy.minute), second(copy.second)
{
  hour = t.hour;
  minute = t.minute;
  second = t.second;
}
dTime::dTime(byte h, byte m, byte s)
  : hour(h), minute(m), second(s) {}
dTime::dTime(const char* time) {
  hour = conv2d(time);
  minute = conv2d(time + 3);
  second = conv2d(time + 6);
}
dTime::dTime(const __FlashStringHelper* time) {
  char buff[8];
  memcpy_P(buff, time, 8);
  hour = conv2d(buff);
  minute = conv2d(buff + 3);
  second = conv2d(buff + 6);
}
unsigned long dTime::time() {
  return ((hour * 24 + minute) * 60 + second);
}
dTime&  dTime::operator=(const dTime& t) {
  if (this == &t)
    return *this;
  hour = t.hour;
  minute = t.minute;
  second = t.second;
  return *this;
}
uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.endTransmission();
  Wire.requestFrom(addr, (byte)1);
  return Wire.read();
}
void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write((byte)reg);
  Wire.write((byte)val);
  Wire.endTransmission();
}
void RTC_DS3231::write(dTime t) {
  Wire.beginTransmission(DS3231_ADDRESS);
  Wire.write((byte)0); // start at location 0
  Wire.write(bin2bcd(t.second));
  Wire.write(bin2bcd(t.minute));
  Wire.write(bin2bcd(t.hour));
  Wire.endTransmission();
  uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
  statreg &= ~0x80; // flip OSF bit
  write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}
dTime RTC_DS3231::read() {
  Wire.beginTransmission(DS3231_ADDRESS);
  Wire.write((byte)0);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_ADDRESS, 7);
  uint8_t s = bcd2bin(Wire.read() & 0x7F);
  uint8_t m = bcd2bin(Wire.read());
  uint8_t h = bcd2bin(Wire.read());
  return dTime(h, m, s);
}
uint8_t bcd2bin (uint8_t val) {
  return val - 6 * (val >> 4);
}
uint8_t bin2bcd (uint8_t val) {
  return val + 6 * (val / 10);
}
uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
//-----------------------------------
// специализация шаблона <<
template <typename T> inline HardwareSerial & operator << (HardwareSerial &s, T n) {
  s.print(n);
  return s;
}
template <> inline HardwareSerial & operator << (HardwareSerial &s, pDo1 Do) {
  Do(s);
  return s;
}
template <> inline HardwareSerial & operator << (HardwareSerial &s, byte n) {
  if (n < 10)s.print("0");
  s.print(n);
  return s;
}
template <> inline HardwareSerial & operator << (HardwareSerial &s, dTime obj) {
  return s << "time:" << obj.hour << ":" << obj.minute << ":" << obj.second ;
}
HardwareSerial & endl(HardwareSerial & streem) {
  streem << "\n";
  return streem;
}
//------------------------------------------
RTC_DS3231  rtc;// часы
dTime now("01:01:01");
//-------------------------------------------
void setup() {
  Serial.begin(9600);
  Wire.begin();
  now = dTime(F(__TIME__));// для первичной настройки часов
  rtc.write(now);
}
void loop() {
  now = rtc.read();
  Serial << now << endl;
  delay(1000);
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
typedef byte state_t;
const state_t sOFF = 0;
const state_t sON  = 1;
const state_t sEND = 2;

const char* viev(state_t s) {
  const char *pOFF PROGMEM = "sOFF";
  const char *pON  PROGMEM = "pON";
  const char *pEND PROGMEM = "pEND";
  const char *const MAP[] PROGMEM = {pOFF, pON, pEND};
  return MAP[s];
}
void setup() {
  Serial.begin(9600);
  for (state_t i = sOFF; i <= sEND; i++)
    Serial.println(viev(i));
}
void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
#define VIEV( n, a,b,c,d)\
  reinterpret_cast<const __FlashStringHelper *>( \
      __extension__(\
  { static const char str1[] PROGMEM = a;\
    static const char str2[] PROGMEM = b;\
    static const char str3[] PROGMEM = c;\
    static const char str4[] PROGMEM = d;\
    static const char* const Arr[] PROGMEM = {str1, str2, str3, str4};\
    Arr[n];\
  }\
                   )\
                                               )
//-------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(
    reinterpret_cast<const __FlashStringHelper *>(
      __extension__(
  { static const char str1[] PROGMEM = "str1qwe";
    static const char str2[] PROGMEM = "str2qwe";
    static const char str3[] PROGMEM = "str3qwe";
    static const char str4[] PROGMEM = "str4qwe";
    static const char* const Arr[] PROGMEM = {str1, str2, str3, str4};
    Arr[2];
  }
      )
    )
  );
  int a=0;
  Serial.println(VIEV( a,"1---","2----", "3---", "4---"));
}

void loop() {

}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
//------------- дисплей-----------------------
//--------------устройство---------------------
const byte dOFF  = 0;// устройство выключено
const byte dLOW  = 1;// устройство включено низкий уровень
const byte dHIGH = 2;// устройство включено высокий уровень
unsigned long devPast;
byte state;
void set(const byte s) {
  devPast = millis();
  state = s;
  switch (s) {
    case dOFF: break;
    case dLOW: break;
    case dHIGH: break;
  }
}
void devInit() {
  set(dOFF);
}
void devRun() {}
//------- кнопки ---------------------------
typedef void (*pDo)();
class Cl_Btn {
  protected:
    const byte pin;
    unsigned long past;
    bool state;
  public:
    pDo Do = [] {};
    Cl_Btn(const byte p)
      : pin(p) {}
    void init() {};
    void run() {};
};
Cl_Btn Left  (/*пин*/2);
Cl_Btn Right (/*пин*/3);
Cl_Btn Select(/*пин*/4);
//------------меню--------------------
const byte scr0  = 0;// главный экран
const byte scr1  = 1;// пуск/стоп
const byte scr2  = 2;// установка длительности
const byte scr3  = 3;// установка периода
const byte scr4  = 4;// установка ШИМ
unsigned long past;
byte scr;// текущий экран
void go(const byte s) {
  scr = s;
  past = millis();
  switch (s) {
    case scr0: break;
    case scr1: break;
    case scr2: break;
    case scr3: break;
    case scr4: break;
  }
}
void menuInit() {
  go(scr0);
}
void menuRun() {
  if (scr != scr0 && millis() - past >= 10000)go(scr0);
  if (scr == scr0 && millis() - past >= 1000)go(scr0);
}
//-------------------------------
void setup() {
  devInit();
  Left.init();
  Right.init();
  Select.init();
  menuInit();
}
void loop() {
  devRun();
  Left.run();
  Right.run();
  Select.run();
  menuRun();
}
/**/

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

С какой целью в строке №30 описана переменная Do, которая потом нигде не используется?

sadman41
Offline
Зарегистрирован: 19.10.2016

Стратегический запас.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ворота пишет:

С какой целью в строке №30 описана переменная Do, которая потом нигде не используется?

/**/
//------------- дисплей-----------------------
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_lightON 0x08
#define LCD_lightOFF 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _lightONval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // ждем не меньше 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // ждем не меньше 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _lightONval = LCD_lightOFF;
      expanderWrite(_lightONval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void lightON(void) {
      _lightONval = LCD_lightON;
      expanderWrite(0);
    }
    void lightOFF(void) {
      _lightONval = LCD_lightOFF;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _lightONval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};

typedef Cl_lcd1602_i2c& (*pDo1)(Cl_lcd1602_i2c&);
template <typename T> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, T n) {
  s.print(n);
  return s;
}
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, pDo1 Do) {
  Do(s);
  return s;
}
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, byte n) {
  if (n < 10)s.print("0");
  s.print(n);
  return s;
}
Cl_lcd1602_i2c& clear(Cl_lcd1602_i2c& s) {
  s.clear();
  return s;
}
Cl_lcd1602_i2c& show(Cl_lcd1602_i2c& s) {
  s.show();
  return s;
}
Cl_lcd1602_i2c lcd(0x27);//0x3F
//--------------устройство---------------------
const byte dOFF  = 0;// устройство выключено
const byte dLOW  = 1;// устройство включено низкий уровень
const byte dHIGH = 2;// устройство включено высокий уровень
unsigned long devPast;
byte state;
void set(const byte s) {
  devPast = millis();
  state = s;
  switch (s) {
    case dOFF: break;
    case dLOW: break;
    case dHIGH: break;
  }
}
void devInit() {
  set(dOFF);
}
void devRun() {}
//------- кнопки ---------------------------
typedef void (*pDo)();
class Cl_Btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      if (s) Do();
    }
  public:
    Cl_Btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_Btn Left  (/*пин*/2);
Cl_Btn Right (/*пин*/3);
Cl_Btn Select(/*пин*/4);
//------------меню--------------------
const byte scr0  = 0;// главный экран
const byte scr1  = 1;// пуск/стоп
const byte scr2  = 2;// установка длительности
const byte scr3  = 3;// установка периода
const byte scr4  = 4;// установка ШИМ
unsigned long past;
byte scr;// текущий экран
void go(const byte s) {
  scr = s;
  past = millis();
  lcd << clear;
  switch (s) {
    case scr0: {// главный экран
        lcd << F("scr0")  << show;
      }
      Left.Do = [] {};
      Right.Do = [] {go(scr1);};
      Select.Do = [] {};
      break;
    case scr1: { // пуск/стоп
        lcd << F("scr1")  << show;
      }
      Left.Do = [] {go(scr0);};
      Right.Do = [] {go(scr2);};
      Select.Do = [] {};
      break;
    case scr2: { // установка длительности
        lcd << F("scr2")  << show;
      }
      Left.Do = [] {go(scr1);};
      Right.Do = [] {go(scr3);};
      Select.Do = [] {};
      break;
    case scr3: { // установка периода
        lcd << F("scr3")  << show;
      }
      Left.Do = [] {go(scr2);};
      Right.Do = [] {go(scr4);};
      Select.Do = [] {};
      break;
    case scr4: { // установка ШИМ
        lcd << F("scr4")  << show;
      }
      Left.Do = [] {go(scr3);};
      Right.Do = [] {};
      Select.Do = [] {};
      break;
  }
}
void menuInit() {
  lcd.lightON();
  go(scr0);
}
void menuRun() {
  if (scr != scr0 && millis() - past >= 10000)go(scr0);
  if (scr == scr0 && millis() - past >= 1000)go(scr0);
}
//-------------------------------
void setup() {
  lcd.init();
  devInit();
  Left.init();
  Right.init();
  Select.init();
  menuInit();
}
void loop() {
  devRun();
  Left.run();
  Right.run();
  Select.run();
  menuRun();
}
/**/

Поэтапное развитие проекта.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Даже компилятор замечает обкуренность автора :)

... :210:22: warning: switch condition has type bool [-Wswitch-bool]

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вррота, вы завязывайте с травой. Пользуйтесь провереными рецептами.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Так это компилятору надо завязывать. Он от твоего кода ох%евает - не я :)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

До меня дошли слухи, что до народа дошли слухи, что я использую лямда функции не правильно. Сообщаю. Они не правдивы. Лямда-функции это очень простой иструмент и не надо носится с ним как с чемоданом без ручки. Отказаться жалко, а использовать страшно.
Возьмем этот скетч

typedef int num_t; //<-- создаем тип
num_t aaa=5; // создаем переменную этого типа
//---------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.print(aaa); //<- используем эту переменую для вывода
}
void loop() {
}

Вам страшно использовать переменные. Нет. А чего здесь у Вас комплексы полезли.

typedef void(*pDo)();  //<-- создаем тип указатель на функцию
pDo Do = []{}; // создаем переменую указатель на функцию и присваиваем ей значение лемдафункция
void setup() {
  Do();//< - используем уже эту переменную как функцию
}
void loop() {

}

А так 

typedef int(*pDo)();  //<-- создаем тип указатель на функцию
pDo Do = [] { return 5;}; // создаем переменую указатель на функцию и присваиваем ей значение лемдафункция
//-----------------------------------
void setup() {
  Serial.begin(9600);
  Serial.print(Do());
}
void loop() {

}