Ошибка в коде

Sadovog
Offline
Зарегистрирован: 07.01.2017

Ребят, нашел в инете код, подходящий для моего проекта, но попытавшись скопмелировать его, напоролся на ошибки, которые уже битых 4 часа не могу осмыслить и убрать. Помогите пожалуйста, а то руки опускаются

Arduino: 1.8.0 (Windows 7), Плата:"Arduino/Genuino Uno"
 
C:\Users\Р?лья\Desktop\water\water.ino: In function 'void setup()':
 
water:311: error: a function-definition is not allowed here before '{' token
 
water:619: error: expected '}' at end of input
 
exit status 1
a function-definition is not allowed here before '{' token
#include <EEPROM.h>

#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#define LEFT 0
#define CENTER 1
#define RIGHT 2

#define RelayModesCount 4
#define KeyFirst 2
#define KeyLast 6

LiquidCrystal_I2C lcd (0x27,20,4);
RTC_DS1307 RTC; // RTC Modul
DHT dht(7, DHT21); // pin, type
volatile boolean Blinker = true;
volatile long BlinkerTime;
volatile byte ButtonPress[8];
const String RelayModeNames[] = {"OFF", "ON", "Once", "Daily"};

int aKey1 = 0;
int aKey2 = 0;

DateTime NowDate;

boolean DoBlink(void)
{
boolean Result = false;
long NBlinkerTime = millis();
if (Blinker)
{
if (NBlinkerTime - BlinkerTime > 200)
{
digitalWrite(8, HIGH);
BlinkerTime = NBlinkerTime;
Blinker = false;
Result = true;
}
}
else
{
if (NBlinkerTime - BlinkerTime > 300 )
{
digitalWrite(8, LOW);
BlinkerTime = NBlinkerTime;
Blinker = true;
}

}
return Result;
}
String BlinkString(String string, byte Cur, byte ItemsCount)
{
String result = string;
byte len = string.length();
if (!Blinker && Cur == ItemsCount)
{
for (byte i = 0; i < len; i++) result.setCharAt(i, ' ');
}
return result;
}

/********************************************************************************************************/
/********************************** Объявление классов *********************************************/
/********************************************************************************************************/

class TMenu
{
public:
byte _ItemsCount;
TMenu *Parent;
String *MenuName;
boolean ItemIsValue;
byte CurrentItem;

TMenu **Items;
String *ItemsName;
// byte ItemsCount(void);
byte ItemsCount(void) {
return _ItemsCount;
};
bool AddItem(TMenu *NewItem);

virtual void Print(void);
void OnKey(byte KeyNum);
void ChangeItem(byte value);

virtual void Increment(void);
virtual void Decrement(void);

virtual void OnSet(void);
DateTime CheckDateTime(DateTime OldDate, int Increment, byte DatePart);
};

class TNoMenu: public TMenu
{
public:
void Print(void);
TNoMenu(TMenu *ParentMenu) {
MenuName = 0;
CurrentItem = 0;
_ItemsCount = 0;
Parent = ParentMenu;
Items = 0;
ItemsName = 0;
ItemIsValue = false;
};
void Increment(void) {};
void Decrement(void) {};
void OnSet(void) {};

};

class TSelectMenu: public TMenu
{
public:
void Print(void);
TSelectMenu(TMenu *ParentMenu, String NewName) {
MenuName = new String(NewName);
CurrentItem = 0;
_ItemsCount = 0;
Parent = ParentMenu;
Items = 0;
ItemsName = 0;
ItemIsValue = false;
};
void Increment(void) {};
void Decrement(void) {};
void OnSet(void) {};
};

class TTimeMenu: public TMenu
{
public:
void Print(void);
DateTime *SetDateTime;
long OldDateTime;
TTimeMenu(TMenu *ParentMenu, String NewName, DateTime *ParamDate) {
MenuName = new String(NewName);
CurrentItem = 0; _ItemsCount = 6; Parent = ParentMenu; Items = 0; ItemsName = 0;
ItemIsValue = true; OldDateTime = millis();
SetDateTime = ParamDate;
};
void Increment(void) {
*SetDateTime = CheckDateTime (*SetDateTime, 1, CurrentItem);
};
void Decrement(void) {
*SetDateTime = CheckDateTime (*SetDateTime, -1, CurrentItem);
};
void OnSet(void) {
RTC.adjust(*SetDateTime);
};
void SecondTimer(void) {
long TmpDateTime = millis(); if (TmpDateTime - OldDateTime > 1000) {
OldDateTime = TmpDateTime;
*SetDateTime = *SetDateTime + 1;
};
};
};
class TRelayMenu: public TMenu
{
public:
byte RelayNumber;
byte RelayMode;
// byte Shedule=0;
boolean OnceBit;
DateTime RelayOn;
DateTime RelayOff;
TRelayMenu(TMenu *ParentMenu, byte NewNumber, String NewName) {
MenuName = new String(NewName);
CurrentItem = 0; _ItemsCount = 11; Parent = ParentMenu; Items = 0; ItemsName = 0; ItemIsValue = true, OnceBit = false;
RelayNumber = NewNumber;
RelayMode = 0;
RelayOn = DateTime(2015, 1, 1, 23, 00, 00);
RelayOff = DateTime(2015, 1, 1, 07, 00, 00);
};
void Print(void);
void Increment(void) {
if (!CurrentItem) {
RelayMode++;
if ( RelayMode >= RelayModesCount) RelayMode = 0;
}
else if (CurrentItem < 6) RelayOn = CheckDateTime (RelayOn, 1, CurrentItem - 1);
else RelayOff = CheckDateTime (RelayOff, 1, CurrentItem - 6);
};
void Decrement(void) {
if (!CurrentItem) {
RelayMode--;
if ( RelayMode > 127) RelayMode = RelayModesCount - 1;
}
else if (CurrentItem < 6) RelayOn = CheckDateTime (RelayOn, -1, CurrentItem - 1);
else RelayOff = CheckDateTime (RelayOff, -1, CurrentItem - 6);
};

boolean CheckDaily(void);

void OnSet(void) {
///// здесь надо записать реле в память

byte p_address = RelayNumber * 16;
EEPROM.write(p_address, RelayMode);

EEPROM.write(p_address + 1, byte(RelayOn.year() - 2000));
EEPROM.write(p_address + 2, byte(RelayOn.month() ));
EEPROM.write(p_address + 3, byte(RelayOn.day() ));
EEPROM.write(p_address + 4, byte(RelayOn.hour() ));
EEPROM.write(p_address + 5, byte(RelayOn.minute() ));

EEPROM.write(p_address + 6, byte(RelayOff.year() - 2000));
EEPROM.write(p_address + 7, byte(RelayOff.month() ));
EEPROM.write(p_address + 8, byte(RelayOff.day() ));
EEPROM.write(p_address + 9, byte(RelayOff.hour() ));
EEPROM.write(p_address + 10, byte(RelayOff.minute() ));
};
};

/********************************************************************************************************/
/******************************** Конец объявления классов ******************************************/
/********************************************************************************************************/

TMenu *CurrentMenu = 0;
TNoMenu *NoMenu = 0;
TSelectMenu *SelectMenu;
TTimeMenu *TimeMenu;

TRelayMenu *RelayMenu[4];

/********************************************************************************************************************************************/
/********************************************************************************************************************************************/
/********************************************************************************************************************************************/
void setup()
{
NoMenu = new TNoMenu(0);
SelectMenu = new TSelectMenu (NoMenu, "NoMenu");
TimeMenu = new TTimeMenu(SelectMenu, "Time Setup", &NowDate);

SelectMenu->AddItem(TimeMenu);

byte p_address;
DateTime DTFlesh;
for (int i = 0; i < 4; i++)
{
// здесь надо добавить загрузку параметров из флеша
RelayMenu[i] = new TRelayMenu (SelectMenu, i, "Relay " + String(i + 1));
SelectMenu->AddItem(RelayMenu[i]);

p_address = i * 16;

RelayMenu[i]->RelayMode = EEPROM.read(p_address);

DTFlesh = DateTime(int(EEPROM.read(p_address + 1) + 2000), EEPROM.read(p_address + 2), EEPROM.read(p_address + 3), EEPROM.read(p_address + 4), EEPROM.read(p_address + 5), 0 );
RelayMenu[i]->RelayOn = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);

DTFlesh = DateTime(int(EEPROM.read(p_address + 6) + 2000), EEPROM.read(p_address + 7), EEPROM.read(p_address + 8), EEPROM.read(p_address + 9), EEPROM.read(p_address + 10), 0 );
RelayMenu[i]->RelayOff = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);
}

for (byte i = KeyFirst; i < KeyLast; i++)
{
pinMode(i, INPUT); //Keypad 2-«menu» 3-"-" 4-"+" 5-«SET»
digitalWrite(i, HIGH); //setup Resistor input2Vcc
ButtonPress[i] = true;
}
pinMode(8, OUTPUT); //LED
pinMode(9, OUTPUT);
for (byte i = 10; i < 14; i++)
{
pinMode(i, OUTPUT); // relay i
digitalWrite(i, HIGH);
}

pinMode (A2, INPUT_PULLUP);
pinMode (A3, INPUT_PULLUP);

Serial.begin(9600); // Used to type in characters
digitalWrite(8, LOW);
digitalWrite(9, HIGH);

lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines and turn on backlight
RTC.begin();

lcd.noBacklight();
delay(150);
lcd.backlight();

NowDate = RTC.now();
//проверка времени
if ( NowDate.year() > 2000 && NowDate.year() < 2114 &&
NowDate.month() > 0 && NowDate.month() < 13 &&
NowDate.day() > 0 && NowDate.day() < 32 &&
NowDate.hour() >= 0 && NowDate.hour() < 24 &&
NowDate.minute() >= 0 && NowDate.minute() < 60 &&
NowDate.second() >= 0 && NowDate.second() < 60 )
{
CurrentMenu = NoMenu;
}
else
{
lcd.setCursor(2, 1);
lcd.print("Clock Failure!");
delay(700);
RTC.adjust(DateTime(2015, 1, 1, 00, 00, 00));
CurrentMenu = TimeMenu;
}



void loop()
 {       
        /********* KEYPAD BUNCLE, 5 keys, from 2 to 6 *********/
        byte NButtonPress[8] = {0, 0, 0, 0, 0, 0, 0, 0};
        byte NButtonRelease[8] = {0, 0, 0, 0, 0, 0, 0, 0};
        const byte ButtonTry = 3;
        
        aKey1 = analogRead (2);
        aKey2 = analogRead (3);
        byte aKeyNum=0;
        
        /**************** check for key pressed or released ****************/
        for (byte i = 0; i < 3; i++)
                  {
                  delay(15);
                  if (aKey1< 64) aKeyNum=2;//AnalogKey 1 = Dig2
                  else if (aKey1<128) aKeyNum=6;//Analog key 3 = D4
                  else if (aKey1<256) aKeyNum=4;//key 5=d6
                  else if (aKey2< 64) aKeyNum=1;//key 6 = menu
                  else if (aKey2<128) aKeyNum=3;//analogkey 2 = D3
                  else if (aKey2<256) aKeyNum=5;//key 4 =d5
                  else aKeyNum=0; // no key
                  
                  for (byte j = KeyFirst; j < KeyLast; j++) // Read ports 2...6
                          {
                          if (digitalRead(j) == LOW || aKeyNum==j)
                                {
                                NButtonPress[j]++;
                                NButtonRelease[j] = 0;
                                }
                                else
                          {
                          NButtonPress [ j ] = 0;
                          NButtonRelease[j]++;
                          delay(5);
                    }
                          }


/*************** Do key process ******************/
// byte m;

for (byte j = KeyFirst; j < KeyLast; j++)
{
if (NButtonPress[ j ] >= ButtonTry  ButtonPress[ j ] == false)
{
ButtonPress[j] = true;
CurrentMenu->OnKey(j);
}
else
{
if (NButtonRelease[j] >= ButtonTry && ButtonPress[j] == true)
{
ButtonPress[j] = false;
}
}
}
/***************** Relay Check *********************/

CurrentMenu->Print();
DoBlink();
}

void LcdPrint(byte string, String str, byte Align)
{
byte StrTrim1;
byte StrTrim2;
lcd.setCursor(0, string); //Start at character 0 on line 0
switch (Align)
{
case RIGHT:

break;

case CENTER:
StrTrim1 = byte((20 - str.length()) / 2);
StrTrim2 = 20 - str.length() - StrTrim1;
for (byte k = 0; k < StrTrim1; k++) lcd.print(" ");
lcd.print(str);
for (byte k = 0; k < StrTrim2; k++) lcd.print(" ");
break;

default:
lcd.print(str);
StrTrim1 = 20 - str.length();
for (byte k = 0; k < StrTrim1; k++) lcd.print(" ");
}
}

void TNoMenu::Print(void)
{
NowDate = RTC.now();
String Ddate;
Ddate = " R1-" + RelayModeNames[RelayMenu[0]->RelayMode] + " R2-" + RelayModeNames[RelayMenu[1]->RelayMode];
LcdPrint(0, Ddate, CENTER);
Ddate = " R3-" + RelayModeNames[RelayMenu[2]->RelayMode] + " R4-" + RelayModeNames[RelayMenu[3]->RelayMode];
LcdPrint(1, Ddate, CENTER);
Ddate = String (NowDate.year()) + "/" + String(NowDate.month()) + "/" + String(NowDate.day()) + " " + String (NowDate.hour()) + ":" + String(NowDate.minute()) + ":" + String(NowDate.second());
LcdPrint(2, Ddate, CENTER);
Ddate = "Temp " + String (int(dht.readTemperature())) + "C, Hum " + String(int(dht.readHumidity())) + "%";
LcdPrint(3, Ddate, CENTER);

RelayCheck();
}

void TTimeMenu::Print(void)
{
SecondTimer();
String Ddate = BlinkString(String((*SetDateTime).year()), CurrentItem, 0) + "/" +
BlinkString(String( (*SetDateTime).month()), CurrentItem, 1) + "/" +
BlinkString(String((*SetDateTime).day()), CurrentItem, 2) + " ";
LcdPrint(1, Ddate, CENTER);
Ddate = BlinkString(String ((*SetDateTime).hour()), CurrentItem, 3) + ":" +
BlinkString(String((*SetDateTime).minute()), CurrentItem, 4) + ":" +
BlinkString(String((*SetDateTime).second()), CurrentItem, 5);
LcdPrint(2, Ddate, CENTER);

LcdPrint(3, " ", CENTER);
RelayCheck();
}

void TMenu::OnKey(byte KeyNum)
{
switch (KeyNum)
{
case 3: // — if (ItemIsValue) Decrement();
else ChangeItem(-1);
break;
case 4: // +
if (ItemIsValue) Increment();
else ChangeItem(1);
break;
case 5: // SET
if (ItemIsValue)
{
OnSet();
ChangeItem(+1);
}
else // вход в подменю
{
if (Items && ItemsCount())
{
if (CurrentMenu->ItemsCount())
{
CurrentMenu = CurrentMenu->Items[CurrentMenu->CurrentItem];
CurrentMenu->CurrentItem = 0;
}
}
}
break;
default: // 2 -menu
if (Parent) CurrentMenu = CurrentMenu->Parent; //(TMenu *) &NoMenu;
else
{
CurrentMenu = SelectMenu;
CurrentMenu->CurrentItem = 0;
}
}
}

void TMenu::ChangeItem(byte value)
{
CurrentItem += value;
if (CurrentItem > 128) CurrentItem = ItemsCount() - 1;
else if (CurrentItem > ItemsCount() - 1) CurrentItem = 0;
}

boolean TMenu::AddItem(TMenu *NewItem)
{
if (!Items) Items = new TMenu *[_ItemsCount = 1];
else Items = (TMenu **)realloc((void *)Items, (_ItemsCount = _ItemsCount + 1) * sizeof(void *));
Items[_ItemsCount - 1] = NewItem;
}

DateTime TMenu::CheckDateTime(DateTime OldDate, int Increment, byte DatePart)
{
int DTmin[6] = {2000, 1, 1, 0, 0, 0};
int DTmax[6] = {2199, 12, 31, 23, 59, 59};

int DT[6];
int diff;

DT[0] = OldDate.year();
DT[1] = OldDate.month();
DT[2] = OldDate.day();
DT[3] = OldDate.hour();
DT[4] = OldDate.minute();
DT[5] = OldDate.second();
DT[DatePart] = DT[DatePart] + Increment;

if (DT[1] == 1 || DT[1] == 3 || DT[1] == 5 || DT[1] == 7 || DT[1] == 8 || DT[1] == 10 || DT[1] == 12) DTmax[2] = 31;
else if (DT[1] == 2)
{
if ((DT[0] % 4 == 0 && DT[0] % 100 != 0) || (DT[0] % 400 == 0)) DTmax[2] = 29;
else DTmax[2] = 28;
}
else DTmax[2] = 30;

for (byte i = 0; i < 6; i++)
{
if (DT[i] > DTmax[i]) DT[i] = DTmin[i];
else if (DT[i] < DTmin[i]) DT[i] = DTmax[i];
}

return DateTime(DT[0], DT[1], DT[2], DT[3], DT[4], DT[5]);

}

void TSelectMenu::Print(void)
{
NowDate = RTC.now();
byte shift = 0;
if (CurrentItem > 3) shift = CurrentItem - 3;
for (byte i = 0; i < 4; i++)
{
if ((CurrentItem - shift) == i) //Blinker
{
LcdPrint(i, ">> " + * (Items[i + shift]->MenuName) + " <<", CENTER);
}
else LcdPrint(i, *(Items[i + shift]->MenuName), CENTER);
}
RelayCheck();
}

void TRelayMenu::Print(void)
{

String DData;
NowDate = RTC.now();
LcdPrint(0, (*MenuName) + "[" + BlinkString(RelayModeNames[RelayMode], CurrentItem, 0) + "]", CENTER);
DData = "On:";
switch (RelayMode)
{
case 3: //Daily
// DData = DData + " ";
if (CurrentItem > 0 && CurrentItem < 4) CurrentItem = 4;
break;
default:
DData = DData + BlinkString(String(RelayOn.year(), DEC), CurrentItem, 1) + "/" + BlinkString(String( RelayOn.month(), DEC), CurrentItem, 2) +
"/" + BlinkString(String( RelayOn.day(), DEC), CurrentItem, 3);
}
DData = DData + " " + BlinkString(String (RelayOn.hour(), DEC), CurrentItem, 4) + ":" + BlinkString(String(RelayOn.minute(), DEC), CurrentItem, 5);
LcdPrint(1, DData, CENTER);
DData = "Off:";
switch (RelayMode)
{
case 3: //Daily
// DData = DData + " ";
if (CurrentItem > 5 && CurrentItem < 9) CurrentItem = 9;
break;
default:
DData = DData + BlinkString(String(RelayOff.year(), DEC), CurrentItem, 6) + "/" + BlinkString(String( RelayOff.month(), DEC), CurrentItem, 7) +
"/" + BlinkString(String( RelayOff.day(), DEC), CurrentItem, 8);
}
DData = DData + " " + BlinkString(String (RelayOff.hour(), DEC), CurrentItem, 9) + ":" + BlinkString(String(RelayOff.minute(), DEC), CurrentItem, 10);
LcdPrint(2, DData, CENTER);
LcdPrint(3, " ", CENTER);
}

boolean TRelayMenu::CheckDaily(void)
{
int TimeOn = 60 * int(RelayOn.hour()) + int(RelayOn.minute());
int TimeOff = 60 * int(RelayOff.hour()) + int(RelayOff.minute());
int NowTime = 60 * int(NowDate.hour()) + int(NowDate.minute());
boolean result; // true = время включения больше времени выключения
if ( TimeOn > TimeOff )
{
if (NowTime <= TimeOff || NowTime >= TimeOn ) result = true;
else result = false;
}
else
{
if (NowTime <= TimeOff && NowTime >= TimeOn ) result = true;
else result = false;
};
return result;

}

void RelayCheck (void)
{
boolean OnceBitCheck;
for (byte i = 0; i < 4; i++)
    {
    switch (RelayMenu[i]->RelayMode)
        {
        case 1: //relay 0n
        digitalWrite(i + 10, LOW);
        
        break;
        case 2: //Once;
        OnceBitCheck = (NowDate.unixtime() > RelayMenu[i]->RelayOn.unixtime() && NowDate.unixtime()<RelayMenu[i]->RelayOff.unixtime());
        
        if (OnceBitCheck) RelayMenu[i]->OnceBit = true;
        else if (RelayMenu[i]->OnceBit)
            {
            RelayMenu[i]->RelayMode = 0;
            byte p_address = RelayMenu[i]->RelayNumber * 16;
            EEPROM.write(p_address, RelayMenu[i]->RelayMode);
            }
            digitalWrite(i + 10, !OnceBitCheck);
            break;
            case 3: //Daily
            digitalWrite(i + 10, !(RelayMenu[i]->CheckDaily()));
            break;
            default: //relay 0ff
            digitalWrite(i + 10, HIGH);
        }
    }
}

 

 
Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Перед 

void loop()

поставьте 

}

и будет Вам счастье (наверное).

Sadovog
Offline
Зарегистрирован: 07.01.2017

выдает это

:\Users\Р?лья\Desktop\water\water.ino: In function 'void loop()':
 
water:354: error: expected ')' before 'ButtonPress'
 
water:374: error: a function-definition is not allowed here before '{' token
 
water:619: error: expected '}' at end of input
 
exit status 1
expected ')' before 'ButtonPress'
 
xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

В строке 372 тоже поставте скобку закрывающую.

И Crt-T в IDE почаще нажимайте.

sir_kimas
Offline
Зарегистрирован: 01.08.2016

Ребята. Подскажите что за ошибка. "C:\Users\Dmitriy\AppData\Local\Temp\arduino_modified_sketch_784566\sketch_apr10c.ino: In member function 'virtual void TNoMenu::Print()':

 
sketch_apr10c:412: error: 'RelayCheck' was not declared in this scope
 
   RelayCheck();
 
              ^
 
C:\Users\Dmitriy\AppData\Local\Temp\arduino_modified_sketch_784566\sketch_apr10c.ino: In member function 'virtual void TTimeMenu::Print()':
 
sketch_apr10c:428: error: 'RelayCheck' was not declared in this scope
 
   RelayCheck();
 
              ^
 
C:\Users\Dmitriy\AppData\Local\Temp\arduino_modified_sketch_784566\sketch_apr10c.ino: In member function 'void TMenu::OnKey(byte)':
 
sketch_apr10c:436: error: expected primary-expression before 'else'
 
       else ChangeItem(-1);
 
       ^
 
sketch_apr10c:445: error: expected '(' before 'OnSet'
 
         if  OnSet();
 
             ^
 
sketch_apr10c:446: error: expected '}' before 'else'
 
         else  ChangeItem(+1);
 
         ^
 
sketch_apr10c:448: error: 'else' without a previous 'if'
 
       else // вход в подменю
 
       ^
 
sketch_apr10c:459: error: break statement not within loop or switch
 
       break;
 
       ^
 
sketch_apr10c:460: error: case label not within a switch statement
 
     default: // 2 -menu
 
     ^
 
C:\Users\Dmitriy\AppData\Local\Temp\arduino_modified_sketch_784566\sketch_apr10c.ino: In member function 'virtual void TSelectMenu::Print()':
 
sketch_apr10c:531: error: 'RelayCheck' was not declared in this scope
 
   RelayCheck();
 
              ^
 
exit status 1
'RelayCheck' was not declared in this scope
#include <EEPROM.h>

#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#define LEFT 0
#define CENTER 1
#define RIGHT 2

#define RelayModesCount 4
#define KeyFirst 2
#define KeyLast 6

LiquidCrystal_I2C lcd (0x3F, 20, 4);
RTC_DS1307 RTC; // RTC Modul
DHT dht(7, DHT21); // pin, type
volatile boolean Blinker = true;
volatile long BlinkerTime;
volatile byte ButtonPress[8];
const String RelayModeNames[] = {"OFF", "ON", "Once", "Daily"};

int aKey1 = 0;
int aKey2 = 0;

DateTime NowDate;

boolean DoBlink(void)
{
  boolean Result = false;
  long NBlinkerTime = millis();
  if (Blinker)
  {
    if (NBlinkerTime - BlinkerTime > 200)
    {
      digitalWrite(8, HIGH);
      BlinkerTime = NBlinkerTime;
      Blinker = false;
      Result = true;
    }
  }
  else
  {
    if (NBlinkerTime - BlinkerTime > 300 )
    {
      digitalWrite(8, LOW);
      BlinkerTime = NBlinkerTime;
      Blinker = true;
    }

  }
  return Result;
}
String BlinkString(String string, byte Cur, byte ItemsCount)
{
  String result = string;
  byte len = string.length();
  if (!Blinker && Cur == ItemsCount)
  {
    for (byte i = 0; i < len; i++) result.setCharAt(i, ' ');
  }
  return result;
}

/********************************************************************************************************/
/********************************** Объявление классов *********************************************/
/********************************************************************************************************/

class TMenu
{
  public:
    byte _ItemsCount;
    TMenu *Parent;
    String *MenuName;
    boolean ItemIsValue;
    byte CurrentItem;

    TMenu **Items;
    String *ItemsName;
    // byte ItemsCount(void);
    byte ItemsCount(void) {
      return _ItemsCount;
    };
    bool AddItem(TMenu *NewItem);

    virtual void Print(void);
    void OnKey(byte KeyNum);
    void ChangeItem(byte value);

    virtual void Increment(void);
    virtual void Decrement(void);

    virtual void OnSet(void);
    DateTime CheckDateTime(DateTime OldDate, int Increment, byte DatePart);
};

class TNoMenu: public TMenu
{
  public:
    void Print(void);
    TNoMenu(TMenu *ParentMenu) {
      MenuName = 0;
      CurrentItem = 0;
      _ItemsCount = 0;
      Parent = ParentMenu;
      Items = 0;
      ItemsName = 0;
      ItemIsValue = false;
    };
    void Increment(void) {};
    void Decrement(void) {};
    void OnSet(void) {};

};

class TSelectMenu: public TMenu
{
  public:
    void Print(void);
    TSelectMenu(TMenu *ParentMenu, String NewName) {
      MenuName = new String(NewName);
      CurrentItem = 0;
      _ItemsCount = 0;
      Parent = ParentMenu;
      Items = 0;
      ItemsName = 0;
      ItemIsValue = false;
    };
    void Increment(void) {};
    void Decrement(void) {};
    void OnSet(void) {};
};

class TTimeMenu: public TMenu
{
  public:
    void Print(void);
    DateTime *SetDateTime;
    long OldDateTime;
    TTimeMenu(TMenu *ParentMenu, String NewName, DateTime *ParamDate) {
      MenuName = new String(NewName);
      CurrentItem = 0; _ItemsCount = 6; Parent = ParentMenu; Items = 0; ItemsName = 0;
      ItemIsValue = true; OldDateTime = millis();
      SetDateTime = ParamDate;
    };
    void Increment(void) {
      *SetDateTime = CheckDateTime (*SetDateTime, 1, CurrentItem);
    };
    void Decrement(void) {
      *SetDateTime = CheckDateTime (*SetDateTime, -1, CurrentItem);
    };
    void OnSet(void) {
      RTC.adjust(*SetDateTime);
    };
    void SecondTimer(void) {
      long TmpDateTime = millis(); if (TmpDateTime - OldDateTime > 1000) {
        OldDateTime = TmpDateTime;
        *SetDateTime = *SetDateTime + 1;
      };
    };
};
class TRelayMenu: public TMenu
{
  public:
    byte RelayNumber;
    byte RelayMode;
    // byte Shedule=0;
    boolean OnceBit;
    DateTime RelayOn;
    DateTime RelayOff;
    TRelayMenu(TMenu *ParentMenu, byte NewNumber, String NewName) {
      MenuName = new String(NewName);
      CurrentItem = 0; _ItemsCount = 11; Parent = ParentMenu; Items = 0; ItemsName = 0; ItemIsValue = true, OnceBit = false;
      RelayNumber = NewNumber;
      RelayMode = 0;
      RelayOn = DateTime(2015, 1, 1, 23, 00, 00);
      RelayOff = DateTime(2015, 1, 1, 07, 00, 00);
    };
    void Print(void);
    void Increment(void) {
      if (!CurrentItem) {
        RelayMode++;
        if ( RelayMode >= RelayModesCount) RelayMode = 0;
      }
      else if (CurrentItem < 6) RelayOn = CheckDateTime (RelayOn, 1, CurrentItem - 1);
      else RelayOff = CheckDateTime (RelayOff, 1, CurrentItem - 6);
    };
    void Decrement(void) {
      if (!CurrentItem) {
        RelayMode--;
        if ( RelayMode > 127) RelayMode = RelayModesCount - 1;
      }
      else if (CurrentItem < 6) RelayOn = CheckDateTime (RelayOn, -1, CurrentItem - 1);
      else RelayOff = CheckDateTime (RelayOff, -1, CurrentItem - 6);
    };

    boolean CheckDaily(void);

    void OnSet(void) {
      ///// здесь надо записать реле в память

      byte p_address = RelayNumber * 16;
      EEPROM.write(p_address, RelayMode);

      EEPROM.write(p_address + 1, byte(RelayOn.year() - 2000));
      EEPROM.write(p_address + 2, byte(RelayOn.month() ));
      EEPROM.write(p_address + 3, byte(RelayOn.day() ));
      EEPROM.write(p_address + 4, byte(RelayOn.hour() ));
      EEPROM.write(p_address + 5, byte(RelayOn.minute() ));

      EEPROM.write(p_address + 6, byte(RelayOff.year() - 2000));
      EEPROM.write(p_address + 7, byte(RelayOff.month() ));
      EEPROM.write(p_address + 8, byte(RelayOff.day() ));
      EEPROM.write(p_address + 9, byte(RelayOff.hour() ));
      EEPROM.write(p_address + 10, byte(RelayOff.minute() ));
    };
};

/********************************************************************************************************/
/******************************** Конец объявления классов ******************************************/
/********************************************************************************************************/

TMenu *CurrentMenu = 0;
TNoMenu *NoMenu = 0;
TSelectMenu *SelectMenu;
TTimeMenu *TimeMenu;

TRelayMenu *RelayMenu[4];

/********************************************************************************************************************************************/
/********************************************************************************************************************************************/
/********************************************************************************************************************************************/
void setup()
{
  NoMenu = new TNoMenu(0);
  SelectMenu = new TSelectMenu (NoMenu, "NoMenu");
  TimeMenu = new TTimeMenu(SelectMenu, "Time Setup", &NowDate);

  SelectMenu->AddItem(TimeMenu);

  byte p_address;
  DateTime DTFlesh;
  for (int i = 0; i < 4; i++)
  {
    // здесь надо добавить загрузку параметров из флеша
    RelayMenu[i] = new TRelayMenu (SelectMenu, i, "Relay " + String(i + 1));
    SelectMenu->AddItem(RelayMenu[i]);

    p_address = i * 16;

    RelayMenu[i]->RelayMode = EEPROM.read(p_address);

    DTFlesh = DateTime(int(EEPROM.read(p_address + 1) + 2000), EEPROM.read(p_address + 2), EEPROM.read(p_address + 3), EEPROM.read(p_address + 4), EEPROM.read(p_address + 5), 0 );
    RelayMenu[i]->RelayOn = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);

    DTFlesh = DateTime(int(EEPROM.read(p_address + 6) + 2000), EEPROM.read(p_address + 7), EEPROM.read(p_address + 8), EEPROM.read(p_address + 9), EEPROM.read(p_address + 10), 0 );
    RelayMenu[i]->RelayOff = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);
  }

  for (byte i = KeyFirst; i < KeyLast; i++)
  {
    pinMode(i, INPUT); //Keypad 2-«menu» 3-"-" 4-"+" 5-«SET»
    digitalWrite(i, HIGH); //setup Resistor input2Vcc
    ButtonPress[i] = true;
  }
  pinMode(8, OUTPUT); //LED
  pinMode(9, OUTPUT);
  for (byte i = 10; i < 14; i++)
  {
    pinMode(i, OUTPUT); // relay i
    digitalWrite(i, HIGH);
  }

  pinMode (A2, INPUT_PULLUP);
  pinMode (A3, INPUT_PULLUP);

  Serial.begin(9600); // Used to type in characters
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);

  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines and turn on backlight
  RTC.begin();

  lcd.noBacklight();
  delay(150);
  lcd.backlight();

  NowDate = RTC.now();
  //проверка времени
  if ( NowDate.year() > 2000 && NowDate.year() < 2114 &&
       NowDate.month() > 0 && NowDate.month() < 13 &&
       NowDate.day() > 0 && NowDate.day() < 32 &&
       NowDate.hour() >= 0 && NowDate.hour() < 24 &&
       NowDate.minute() >= 0 && NowDate.minute() < 60 &&
       NowDate.second() >= 0 && NowDate.second() < 60 )
  {
    CurrentMenu = NoMenu;
  }
  else
  {
    lcd.setCursor(2, 1);
    lcd.print("Clock Failure!");
    delay(700);
    RTC.adjust(DateTime(2015, 1, 1, 00, 00, 00));
    CurrentMenu = TimeMenu;
  }
}


void loop()
{
  /********* KEYPAD BUNCLE, 5 keys, from 2 to 6 *********/
  byte NButtonPress[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  byte NButtonRelease[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  const byte ButtonTry = 3;

  aKey1 = analogRead (2);
  aKey2 = analogRead (3);
  byte aKeyNum = 0;

  /**************** check for key pressed or released ****************/
  for (byte i = 0; i < 3; i++)
  {
    delay(15);
    if (aKey1 < 64) aKeyNum = 2; //AnalogKey 1 = Dig2
    else if (aKey1 < 128) aKeyNum = 6; //Analog key 3 = D4
    else if (aKey1 < 256) aKeyNum = 4; //key 5=d6
    else if (aKey2 < 64) aKeyNum = 1; //key 6 = menu
    else if (aKey2 < 128) aKeyNum = 3; //analogkey 2 = D3
    else if (aKey2 < 256) aKeyNum = 5; //key 4 =d5
    else aKeyNum = 0; // no key

    for (byte j = KeyFirst; j < KeyLast; j++) // Read ports 2...6
    {
      if (digitalRead(j) == LOW || aKeyNum == j)
      {
        NButtonPress[j]++;
        NButtonRelease[j] = 0;
      }
      else
      {
        NButtonPress [ j ] = 0;
        NButtonRelease[j]++;
        delay(5);
      }
    }


    /*************** Do key process ******************/
    // byte m;

    for (byte j = KeyFirst; j < KeyLast; j++)
    {
      if (NButtonPress[j] >= ButtonTry && ButtonPress[j] == false)
      {
        ButtonPress[j] = true;
        CurrentMenu->OnKey(j);
      }
      else
      {
        if (NButtonRelease[j] >= ButtonTry && ButtonPress[j] == true)
        {
          ButtonPress[j] = false;
        }
      }
    }
    /***************** Relay Check *********************/

    CurrentMenu->Print();
    DoBlink();
  }
}
void LcdPrint(byte string, String str, byte Align)
{
  byte StrTrim1;
  byte StrTrim2;
  lcd.setCursor(0, string); //Start at character 0 on line 0
  switch (Align)
  {
    case RIGHT:

      break;

    case CENTER:
      StrTrim1 = byte((20 - str.length()) / 2);
      StrTrim2 = 20 - str.length() - StrTrim1;
      for (byte k = 0; k < StrTrim1; k++) lcd.print(" ");
      lcd.print(str);
      for (byte k = 0; k < StrTrim2; k++) lcd.print(" ");
      break;

    default:
      lcd.print(str);
      StrTrim1 = 20 - str.length();
      for (byte k = 0; k < StrTrim1; k++) lcd.print(" ");
  }
}

void TNoMenu::Print(void)
{
  NowDate = RTC.now();
  String Ddate;
  Ddate = " R1-" + RelayModeNames[RelayMenu[0]->RelayMode] + " R2-" + RelayModeNames[RelayMenu[1]->RelayMode];
  LcdPrint(0, Ddate, CENTER);
  Ddate = " R3-" + RelayModeNames[RelayMenu[2]->RelayMode] + " R4-" + RelayModeNames[RelayMenu[3]->RelayMode];
  LcdPrint(1, Ddate, CENTER);
  Ddate = String (NowDate.year()) + "/" + String(NowDate.month()) + "/" + String(NowDate.day()) + " " + String (NowDate.hour()) + ":" + String(NowDate.minute()) + ":" + String(NowDate.second());
  LcdPrint(2, Ddate, CENTER);
  Ddate = "Temp " + String (int(dht.readTemperature())) + "C, Hum " + String(int(dht.readHumidity())) + "%";
  LcdPrint(3, Ddate, CENTER);

  RelayCheck();
}

void TTimeMenu::Print(void)
{
  SecondTimer();
  String Ddate = BlinkString(String((*SetDateTime).year()), CurrentItem, 0) + "/" +
                 BlinkString(String( (*SetDateTime).month()), CurrentItem, 1) + "/" +
                 BlinkString(String((*SetDateTime).day()), CurrentItem, 2) + " ";
  LcdPrint(1, Ddate, CENTER);
  Ddate = BlinkString(String ((*SetDateTime).hour()), CurrentItem, 3) + ":" +
          BlinkString(String((*SetDateTime).minute()), CurrentItem, 4) + ":" +
          BlinkString(String((*SetDateTime).second()), CurrentItem, 5);
  LcdPrint(2, Ddate, CENTER);

  LcdPrint(3, " ", CENTER);
  RelayCheck();
}

void TMenu::OnKey(byte KeyNum)
{
  switch (KeyNum)
  {
    case 3: // — if (ItemIsValue) Decrement();
      else ChangeItem(-1);
      break;
    case 4: // +
      if (ItemIsValue) Increment();
      else ChangeItem(1);
      break;
    case 5: // SET
      if (ItemIsValue)
      {
        if  OnSet();
        else  ChangeItem(+1);
      }
      else // вход в подменю
      {
        if (Items && ItemsCount())
        {
          if (CurrentMenu->ItemsCount())
          {
            CurrentMenu = CurrentMenu->Items[CurrentMenu->CurrentItem];
            CurrentMenu->CurrentItem = 0;
          }
        }
      }
      break;
    default: // 2 -menu
      if (Parent) CurrentMenu = CurrentMenu->Parent; //(TMenu *) &NoMenu;
      else
      {
        CurrentMenu = SelectMenu;
        CurrentMenu->CurrentItem = 0;
      }
  }


void TMenu::ChangeItem(byte value)
{
  CurrentItem += value;
  if (CurrentItem > 128) CurrentItem = ItemsCount() - 1;
  else if (CurrentItem > ItemsCount() - 1) CurrentItem = 0;
}

boolean TMenu::AddItem(TMenu * NewItem)
{
  if (!Items) Items = new TMenu *[_ItemsCount = 1];
  else Items = (TMenu **)realloc((void *)Items, (_ItemsCount = _ItemsCount + 1) * sizeof(void *));
  Items[_ItemsCount - 1] = NewItem;
}

DateTime TMenu::CheckDateTime(DateTime OldDate, int Increment, byte DatePart)
{
  int DTmin[6] = {2000, 1, 1, 0, 0, 0};
  int DTmax[6] = {2199, 12, 31, 23, 59, 59};

  int DT[6];
  int diff;

  DT[0] = OldDate.year();
  DT[1] = OldDate.month();
  DT[2] = OldDate.day();
  DT[3] = OldDate.hour();
  DT[4] = OldDate.minute();
  DT[5] = OldDate.second();
  DT[DatePart] = DT[DatePart] + Increment;

  if (DT[1] == 1 || DT[1] == 3 || DT[1] == 5 || DT[1] == 7 || DT[1] == 8 || DT[1] == 10 || DT[1] == 12) DTmax[2] = 31;
  else if (DT[1] == 2)
  {
    if ((DT[0] % 4 == 0 && DT[0] % 100 != 0) || (DT[0] % 400 == 0)) DTmax[2] = 29;
    else DTmax[2] = 28;
  }
  else DTmax[2] = 30;

  for (byte i = 0; i < 6; i++)
  {
    if (DT[i] > DTmax[i]) DT[i] = DTmin[i];
    else if (DT[i] < DTmin[i]) DT[i] = DTmax[i];
  }

  return DateTime(DT[0], DT[1], DT[2], DT[3], DT[4], DT[5]);

}

void TSelectMenu::Print(void)
{
  NowDate = RTC.now();
  byte shift = 0;
  if (CurrentItem > 3) shift = CurrentItem - 3;
  for (byte i = 0; i < 4; i++)
  {
    if ((CurrentItem - shift) == i) //Blinker
    {
      LcdPrint(i, ">> " + * (Items[i + shift]->MenuName) + " <<", CENTER);
    }
    else LcdPrint(i, *(Items[i + shift]->MenuName), CENTER);
  }
  RelayCheck();
}

void TRelayMenu::Print(void)
{

  String DData;
  NowDate = RTC.now();
  LcdPrint(0, (*MenuName) + "[" + BlinkString(RelayModeNames[RelayMode], CurrentItem, 0) + "]", CENTER);
  DData = "On:";
  switch (RelayMode)
  {
    case 3: //Daily
      // DData = DData + " ";
      if (CurrentItem > 0 && CurrentItem < 4) CurrentItem = 4;
      break;
    default:
      DData = DData + BlinkString(String(RelayOn.year(), DEC), CurrentItem, 1) + "/" + BlinkString(String( RelayOn.month(), DEC), CurrentItem, 2) +
              "/" + BlinkString(String( RelayOn.day(), DEC), CurrentItem, 3);
  }
  DData = DData + " " + BlinkString(String (RelayOn.hour(), DEC), CurrentItem, 4) + ":" + BlinkString(String(RelayOn.minute(), DEC), CurrentItem, 5);
  LcdPrint(1, DData, CENTER);
  DData = "Off:";
  switch (RelayMode)
  {
    case 3: //Daily
      // DData = DData + " ";
      if (CurrentItem > 5 && CurrentItem < 9) CurrentItem = 9;
      break;
    default:
      DData = DData + BlinkString(String(RelayOff.year(), DEC), CurrentItem, 6) + "/" + BlinkString(String( RelayOff.month(), DEC), CurrentItem, 7) +
              "/" + BlinkString(String( RelayOff.day(), DEC), CurrentItem, 8);
  }
  DData = DData + " " + BlinkString(String (RelayOff.hour(), DEC), CurrentItem, 9) + ":" + BlinkString(String(RelayOff.minute(), DEC), CurrentItem, 10);
  LcdPrint(2, DData, CENTER);
  LcdPrint(3, " ", CENTER);
}

boolean TRelayMenu::CheckDaily(void)
{
  int TimeOn = 60 * int(RelayOn.hour()) + int(RelayOn.minute());
  int TimeOff = 60 * int(RelayOff.hour()) + int(RelayOff.minute());
  int NowTime = 60 * int(NowDate.hour()) + int(NowDate.minute());
  boolean result; // true = время включения больше времени выключения
  if ( TimeOn > TimeOff )
  {
    if (NowTime <= TimeOff || NowTime >= TimeOn ) result = true;
    else result = false;
  }
  else
  {
    if (NowTime <= TimeOff && NowTime >= TimeOn ) result = true;
    else result = false;
  };
  return result;

}

void RelayCheck (void)
{
  boolean OnceBitCheck;
  for (byte i = 0; i < 4; i++)
  {
    switch (RelayMenu[i]->RelayMode)
    {
      case 1: //relay 0n
        digitalWrite(i + 10, LOW);

        break;
      case 2: //Once;
        OnceBitCheck = (NowDate.unixtime() > RelayMenu[i]->RelayOn.unixtime() && NowDate.unixtime() < RelayMenu[i]->RelayOff.unixtime());

        if (OnceBitCheck) RelayMenu[i]->OnceBit = true;
        else if (RelayMenu[i]->OnceBit)
        {
          RelayMenu[i]->RelayMode = 0;
          byte p_address = RelayMenu[i]->RelayNumber * 16;
          EEPROM.write(p_address, RelayMenu[i]->RelayMode);
        }
        digitalWrite(i + 10, !OnceBitCheck);
        break;
      case 3: //Daily
        digitalWrite(i + 10, !(RelayMenu[i]->CheckDaily()));
        break;
      default: //relay 0ff
        digitalWrite(i + 10, HIGH);
    }
  }
}

 

"

T.Rook
Offline
Зарегистрирован: 05.03.2016

1. 589-619 (RelayCheck) перенесите в 398 строку перед TNoMenu::Print

2. 436  - else без конструкции if.

3. 445 - ???? что за странный if?

sir_kimas
Offline
Зарегистрирован: 01.08.2016

T.Rook пишет:

1. 589-619 (RelayCheck) перенесите в 398 строку перед TNoMenu::Print

2. 436  - else без конструкции if.

3. 445 - ???? что за странный if?

Теперь вот такая ошибка. "C:\Users\Dmitriy\AppData\Local\Temp\arduino_modified_sketch_427514\sketch_apr10c.ino: In member function 'void TMenu::OnKey(byte)':

 
sketch_apr10c:468: error: expected primary-expression before 'else'
 
       else ChangeItem(-1);
 
       ^
 
sketch_apr10c:502: error: qualified-id in declaration before '(' token
 
 void TMenu::ChangeItem(byte value)
 
                       ^
 
sketch_apr10c:509: error: qualified-id in declaration before '(' token
 
 boolean TMenu::AddItem(TMenu * NewItem)
 
                       ^
 
sketch_apr10c:516: error: qualified-id in declaration before '(' token
 
 DateTime TMenu::CheckDateTime(DateTime OldDate, int Increment, byte DatePart)
 
                              ^
 
sketch_apr10c:619: error: expected '}' at end of input
 
 }
 
 ^
 
exit status 1
expected primary-expression before 'else'
 

"

T.Rook
Offline
Зарегистрирован: 05.03.2016

ну... смотрим внимательно TMenu::onKey около 468 строки. Мне чёй-то, не очень видно :(

sir_kimas
Offline
Зарегистрирован: 01.08.2016

T.Rook пишет:

ну... смотрим внимательно TMenu::onKey около 468 строки. Мне чёй-то, не очень видно :(

#include <EEPROM.h>

#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#define LEFT 0
#define CENTER 1
#define RIGHT 2

#define RelayModesCount 4
#define KeyFirst 2
#define KeyLast 6

LiquidCrystal_I2C lcd (0x3F, 20, 4);
RTC_DS1307 RTC; // RTC Modul
DHT dht(7, DHT21); // pin, type
volatile boolean Blinker = true;
volatile long BlinkerTime;
volatile byte ButtonPress[8];
const String RelayModeNames[] = {"OFF", "ON", "Once", "Daily"};

int aKey1 = 0;
int aKey2 = 0;

DateTime NowDate;

boolean DoBlink(void)
{
  boolean Result = false;
  long NBlinkerTime = millis();
  if (Blinker)
  {
    if (NBlinkerTime - BlinkerTime > 200)
    {
      digitalWrite(8, HIGH);
      BlinkerTime = NBlinkerTime;
      Blinker = false;
      Result = true;
    }
  }
  else
  {
    if (NBlinkerTime - BlinkerTime > 300 )
    {
      digitalWrite(8, LOW);
      BlinkerTime = NBlinkerTime;
      Blinker = true;
    }

  }
  return Result;
}
String BlinkString(String string, byte Cur, byte ItemsCount)
{
  String result = string;
  byte len = string.length();
  if (!Blinker && Cur == ItemsCount)
  {
    for (byte i = 0; i < len; i++) result.setCharAt(i, ' ');
  }
  return result;
}

/********************************************************************************************************/
/********************************** Объявление классов *********************************************/
/********************************************************************************************************/

class TMenu
{
  public:
    byte _ItemsCount;
    TMenu *Parent;
    String *MenuName;
    boolean ItemIsValue;
    byte CurrentItem;

    TMenu **Items;
    String *ItemsName;
    // byte ItemsCount(void);
    byte ItemsCount(void) {
      return _ItemsCount;
    };
    bool AddItem(TMenu *NewItem);

    virtual void Print(void);
    void OnKey(byte KeyNum);
    void ChangeItem(byte value);

    virtual void Increment(void);
    virtual void Decrement(void);

    virtual void OnSet(void);
    DateTime CheckDateTime(DateTime OldDate, int Increment, byte DatePart);
};

class TNoMenu: public TMenu
{
  public:
    void Print(void);
    TNoMenu(TMenu *ParentMenu) {
      MenuName = 0;
      CurrentItem = 0;
      _ItemsCount = 0;
      Parent = ParentMenu;
      Items = 0;
      ItemsName = 0;
      ItemIsValue = false;
    };
    void Increment(void) {};
    void Decrement(void) {};
    void OnSet(void) {};

};

class TSelectMenu: public TMenu
{
  public:
    void Print(void);
    TSelectMenu(TMenu *ParentMenu, String NewName) {
      MenuName = new String(NewName);
      CurrentItem = 0;
      _ItemsCount = 0;
      Parent = ParentMenu;
      Items = 0;
      ItemsName = 0;
      ItemIsValue = false;
    };
    void Increment(void) {};
    void Decrement(void) {};
    void OnSet(void) {};
};

class TTimeMenu: public TMenu
{
  public:
    void Print(void);
    DateTime *SetDateTime;
    long OldDateTime;
    TTimeMenu(TMenu *ParentMenu, String NewName, DateTime *ParamDate) {
      MenuName = new String(NewName);
      CurrentItem = 0; _ItemsCount = 6; Parent = ParentMenu; Items = 0; ItemsName = 0;
      ItemIsValue = true; OldDateTime = millis();
      SetDateTime = ParamDate;
    };
    void Increment(void) {
      *SetDateTime = CheckDateTime (*SetDateTime, 1, CurrentItem);
    };
    void Decrement(void) {
      *SetDateTime = CheckDateTime (*SetDateTime, -1, CurrentItem);
    };
    void OnSet(void) {
      RTC.adjust(*SetDateTime);
    };
    void SecondTimer(void) {
      long TmpDateTime = millis(); if (TmpDateTime - OldDateTime > 1000) {
        OldDateTime = TmpDateTime;
        *SetDateTime = *SetDateTime + 1;
      };
    };
};
class TRelayMenu: public TMenu
{
  public:
    byte RelayNumber;
    byte RelayMode;
    // byte Shedule=0;
    boolean OnceBit;
    DateTime RelayOn;
    DateTime RelayOff;
    TRelayMenu(TMenu *ParentMenu, byte NewNumber, String NewName) {
      MenuName = new String(NewName);
      CurrentItem = 0; _ItemsCount = 11; Parent = ParentMenu; Items = 0; ItemsName = 0; ItemIsValue = true, OnceBit = false;
      RelayNumber = NewNumber;
      RelayMode = 0;
      RelayOn = DateTime(2015, 1, 1, 23, 00, 00);
      RelayOff = DateTime(2015, 1, 1, 07, 00, 00);
    };
    void Print(void);
    void Increment(void) {
      if (!CurrentItem) {
        RelayMode++;
        if ( RelayMode >= RelayModesCount) RelayMode = 0;
      }
      else if (CurrentItem < 6) RelayOn = CheckDateTime (RelayOn, 1, CurrentItem - 1);
      else RelayOff = CheckDateTime (RelayOff, 1, CurrentItem - 6);
    };
    void Decrement(void) {
      if (!CurrentItem) {
        RelayMode--;
        if ( RelayMode > 127) RelayMode = RelayModesCount - 1;
      }
      else if (CurrentItem < 6) RelayOn = CheckDateTime (RelayOn, -1, CurrentItem - 1);
      else RelayOff = CheckDateTime (RelayOff, -1, CurrentItem - 6);
    };

    boolean CheckDaily(void);

    void OnSet(void) {
      ///// здесь надо записать реле в память

      byte p_address = RelayNumber * 16;
      EEPROM.write(p_address, RelayMode);

      EEPROM.write(p_address + 1, byte(RelayOn.year() - 2000));
      EEPROM.write(p_address + 2, byte(RelayOn.month() ));
      EEPROM.write(p_address + 3, byte(RelayOn.day() ));
      EEPROM.write(p_address + 4, byte(RelayOn.hour() ));
      EEPROM.write(p_address + 5, byte(RelayOn.minute() ));

      EEPROM.write(p_address + 6, byte(RelayOff.year() - 2000));
      EEPROM.write(p_address + 7, byte(RelayOff.month() ));
      EEPROM.write(p_address + 8, byte(RelayOff.day() ));
      EEPROM.write(p_address + 9, byte(RelayOff.hour() ));
      EEPROM.write(p_address + 10, byte(RelayOff.minute() ));
    };
};

/********************************************************************************************************/
/******************************** Конец объявления классов ******************************************/
/********************************************************************************************************/

TMenu *CurrentMenu = 0;
TNoMenu *NoMenu = 0;
TSelectMenu *SelectMenu;
TTimeMenu *TimeMenu;

TRelayMenu *RelayMenu[4];

/********************************************************************************************************************************************/
/********************************************************************************************************************************************/
/********************************************************************************************************************************************/
void setup()
{
  NoMenu = new TNoMenu(0);
  SelectMenu = new TSelectMenu (NoMenu, "NoMenu");
  TimeMenu = new TTimeMenu(SelectMenu, "Time Setup", &NowDate);

  SelectMenu->AddItem(TimeMenu);

  byte p_address;
  DateTime DTFlesh;
  for (int i = 0; i < 4; i++)
  {
    // здесь надо добавить загрузку параметров из флеша
    RelayMenu[i] = new TRelayMenu (SelectMenu, i, "Relay " + String(i + 1));
    SelectMenu->AddItem(RelayMenu[i]);

    p_address = i * 16;

    RelayMenu[i]->RelayMode = EEPROM.read(p_address);

    DTFlesh = DateTime(int(EEPROM.read(p_address + 1) + 2000), EEPROM.read(p_address + 2), EEPROM.read(p_address + 3), EEPROM.read(p_address + 4), EEPROM.read(p_address + 5), 0 );
    RelayMenu[i]->RelayOn = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);

    DTFlesh = DateTime(int(EEPROM.read(p_address + 6) + 2000), EEPROM.read(p_address + 7), EEPROM.read(p_address + 8), EEPROM.read(p_address + 9), EEPROM.read(p_address + 10), 0 );
    RelayMenu[i]->RelayOff = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);
  }

  for (byte i = KeyFirst; i < KeyLast; i++)
  {
    pinMode(i, INPUT); //Keypad 2-«menu» 3-"-" 4-"+" 5-«SET»
    digitalWrite(i, HIGH); //setup Resistor input2Vcc
    ButtonPress[i] = true;
  }
  pinMode(8, OUTPUT); //LED
  pinMode(9, OUTPUT);
  for (byte i = 10; i < 14; i++)
  {
    pinMode(i, OUTPUT); // relay i
    digitalWrite(i, HIGH);
  }

  pinMode (A2, INPUT_PULLUP);
  pinMode (A3, INPUT_PULLUP);

  Serial.begin(9600); // Used to type in characters
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);

  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines and turn on backlight
  RTC.begin();

  lcd.noBacklight();
  delay(150);
  lcd.backlight();

  NowDate = RTC.now();
  //проверка времени
  if ( NowDate.year() > 2000 && NowDate.year() < 2114 &&
       NowDate.month() > 0 && NowDate.month() < 13 &&
       NowDate.day() > 0 && NowDate.day() < 32 &&
       NowDate.hour() >= 0 && NowDate.hour() < 24 &&
       NowDate.minute() >= 0 && NowDate.minute() < 60 &&
       NowDate.second() >= 0 && NowDate.second() < 60 )
  {
    CurrentMenu = NoMenu;
  }
  else
  {
    lcd.setCursor(2, 1);
    lcd.print("Clock Failure!");
    delay(700);
    RTC.adjust(DateTime(2015, 1, 1, 00, 00, 00));
    CurrentMenu = TimeMenu;
  }
}


void loop()
{
  /********* KEYPAD BUNCLE, 5 keys, from 2 to 6 *********/
  byte NButtonPress[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  byte NButtonRelease[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  const byte ButtonTry = 3;

  aKey1 = analogRead (2);
  aKey2 = analogRead (3);
  byte aKeyNum = 0;

  /**************** check for key pressed or released ****************/
  for (byte i = 0; i < 3; i++)
  {
    delay(15);
    if (aKey1 < 64) aKeyNum = 2; //AnalogKey 1 = Dig2
    else if (aKey1 < 128) aKeyNum = 6; //Analog key 3 = D4
    else if (aKey1 < 256) aKeyNum = 4; //key 5=d6
    else if (aKey2 < 64) aKeyNum = 1; //key 6 = menu
    else if (aKey2 < 128) aKeyNum = 3; //analogkey 2 = D3
    else if (aKey2 < 256) aKeyNum = 5; //key 4 =d5
    else aKeyNum = 0; // no key

    for (byte j = KeyFirst; j < KeyLast; j++) // Read ports 2...6
    {
      if (digitalRead(j) == LOW || aKeyNum == j)
      {
        NButtonPress[j]++;
        NButtonRelease[j] = 0;
      }
      else
      {
        NButtonPress [ j ] = 0;
        NButtonRelease[j]++;
        delay(5);
      }
    }


    /*************** Do key process ******************/
    // byte m;

    for (byte j = KeyFirst; j < KeyLast; j++)
    {
      if (NButtonPress[j] >= ButtonTry && ButtonPress[j] == false)
      {
        ButtonPress[j] = true;
        CurrentMenu->OnKey(j);
      }
      else
      {
        if (NButtonRelease[j] >= ButtonTry && ButtonPress[j] == true)
        {
          ButtonPress[j] = false;
        }
      }
    }
    /***************** Relay Check *********************/

    CurrentMenu->Print();
    DoBlink();
  }
}
void LcdPrint(byte string, String str, byte Align)
{
  byte StrTrim1;
  byte StrTrim2;
  lcd.setCursor(0, string); //Start at character 0 on line 0
  switch (Align)
  {
    case RIGHT:

      break;

    case CENTER:
      StrTrim1 = byte((20 - str.length()) / 2);
      StrTrim2 = 20 - str.length() - StrTrim1;
      for (byte k = 0; k < StrTrim1; k++) lcd.print(" ");
      lcd.print(str);
      for (byte k = 0; k < StrTrim2; k++) lcd.print(" ");
      break;

    default:
      lcd.print(str);
      StrTrim1 = 20 - str.length();
      for (byte k = 0; k < StrTrim1; k++) lcd.print(" ");
  }
}

void RelayCheck (void)
{
  boolean OnceBitCheck;
  for (byte i = 0; i < 4; i++)
  {
    switch (RelayMenu[i]->RelayMode)
    {
      case 1: //relay 0n
        digitalWrite(i + 10, LOW);

        break;
      case 2: //Once;
        OnceBitCheck = (NowDate.unixtime() > RelayMenu[i]->RelayOn.unixtime() && NowDate.unixtime() < RelayMenu[i]->RelayOff.unixtime());

        if (OnceBitCheck) RelayMenu[i]->OnceBit = true;
        else if (RelayMenu[i]->OnceBit)
        {
          RelayMenu[i]->RelayMode = 0;
          byte p_address = RelayMenu[i]->RelayNumber * 16;
          EEPROM.write(p_address, RelayMenu[i]->RelayMode);
        }
        digitalWrite(i + 10, !OnceBitCheck);
        break;
      case 3: //Daily
        digitalWrite(i + 10, !(RelayMenu[i]->CheckDaily()));
        break;
      default: //relay 0ff
        digitalWrite(i + 10, HIGH);
    }
  }
}

void TNoMenu::Print(void)
{
  NowDate = RTC.now();
  String Ddate;
  Ddate = " R1-" + RelayModeNames[RelayMenu[0]->RelayMode] + " R2-" + RelayModeNames[RelayMenu[1]->RelayMode];
  LcdPrint(0, Ddate, CENTER);
  Ddate = " R3-" + RelayModeNames[RelayMenu[2]->RelayMode] + " R4-" + RelayModeNames[RelayMenu[3]->RelayMode];
  LcdPrint(1, Ddate, CENTER);
  Ddate = String (NowDate.year()) + "/" + String(NowDate.month()) + "/" + String(NowDate.day()) + " " + String (NowDate.hour()) + ":" + String(NowDate.minute()) + ":" + String(NowDate.second());
  LcdPrint(2, Ddate, CENTER);
  Ddate = "Temp " + String (int(dht.readTemperature())) + "C, Hum " + String(int(dht.readHumidity())) + "%";
  LcdPrint(3, Ddate, CENTER);

  RelayCheck();
}

void TTimeMenu::Print(void)
{
  SecondTimer();
  String Ddate = BlinkString(String((*SetDateTime).year()), CurrentItem, 0) + "/" +
                 BlinkString(String( (*SetDateTime).month()), CurrentItem, 1) + "/" +
                 BlinkString(String((*SetDateTime).day()), CurrentItem, 2) + " ";
  LcdPrint(1, Ddate, CENTER);
  Ddate = BlinkString(String ((*SetDateTime).hour()), CurrentItem, 3) + ":" +
          BlinkString(String((*SetDateTime).minute()), CurrentItem, 4) + ":" +
          BlinkString(String((*SetDateTime).second()), CurrentItem, 5);
  LcdPrint(2, Ddate, CENTER);

  LcdPrint(3, " ", CENTER);
  RelayCheck();
}

void TMenu::OnKey(byte KeyNum)
{
  switch (KeyNum)
  {
    case 3: // — if (ItemIsValue) Decrement();
      else ChangeItem(-1);
      break;
    case 4: // +
      if (ItemIsValue) Increment();
      else ChangeItem(1);
      break;
    case 5: // SET
      if (ItemIsValue)
      {
        if  OnSet();
        else  ChangeItem(+1);
      }
      else // вход в подменю
      {
        if (Items && ItemsCount())
        {
          if (CurrentMenu->ItemsCount())
          {
            CurrentMenu = CurrentMenu->Items[CurrentMenu->CurrentItem];
            CurrentMenu->CurrentItem = 0;
          }
        }
      }
      break;
    default: // 2 -menu
      if (Parent) CurrentMenu = CurrentMenu->Parent; //(TMenu *) &NoMenu;
      else
      {
        CurrentMenu = SelectMenu;
        CurrentMenu->CurrentItem = 0;
      }
  }
}

  void TMenu::ChangeItem(byte value)
  {
    CurrentItem += value;
    if (CurrentItem > 128) CurrentItem = ItemsCount() - 1;
    else if (CurrentItem > ItemsCount() - 1) CurrentItem = 0;
  }

  boolean TMenu::AddItem(TMenu * NewItem)
  {
    if (!Items) Items = new TMenu *[_ItemsCount = 1];
    else Items = (TMenu **)realloc((void *)Items, (_ItemsCount = _ItemsCount + 1) * sizeof(void *));
    Items[_ItemsCount - 1] = NewItem;
  }

  DateTime TMenu::CheckDateTime(DateTime OldDate, int Increment, byte DatePart)
  {
    int DTmin[6] = {2000, 1, 1, 0, 0, 0};
    int DTmax[6] = {2199, 12, 31, 23, 59, 59};

    int DT[6];
    int diff;

    DT[0] = OldDate.year();
    DT[1] = OldDate.month();
    DT[2] = OldDate.day();
    DT[3] = OldDate.hour();
    DT[4] = OldDate.minute();
    DT[5] = OldDate.second();
    DT[DatePart] = DT[DatePart] + Increment;

    if (DT[1] == 1 || DT[1] == 3 || DT[1] == 5 || DT[1] == 7 || DT[1] == 8 || DT[1] == 10 || DT[1] == 12) DTmax[2] = 31;
    else if (DT[1] == 2)
    {
      if ((DT[0] % 4 == 0 && DT[0] % 100 != 0) || (DT[0] % 400 == 0)) DTmax[2] = 29;
      else DTmax[2] = 28;
    }
    else DTmax[2] = 30;

    for (byte i = 0; i < 6; i++)
    {
      if (DT[i] > DTmax[i]) DT[i] = DTmin[i];
      else if (DT[i] < DTmin[i]) DT[i] = DTmax[i];
    }

    return DateTime(DT[0], DT[1], DT[2], DT[3], DT[4], DT[5]);

  }

  void TSelectMenu::Print(void)
  {
    NowDate = RTC.now();
    byte shift = 0;
    if (CurrentItem > 3) shift = CurrentItem - 3;
    for (byte i = 0; i < 4; i++)
    {
      if ((CurrentItem - shift) == i) //Blinker
      {
        LcdPrint(i, ">> " + * (Items[i + shift]->MenuName) + " <<", CENTER);
      }
      else LcdPrint(i, *(Items[i + shift]->MenuName), CENTER);
    }
    RelayCheck();
  }

  void TRelayMenu::Print(void)
  {

    String DData;
    NowDate = RTC.now();
    LcdPrint(0, (*MenuName) + "[" + BlinkString(RelayModeNames[RelayMode], CurrentItem, 0) + "]", CENTER);
    DData = "On:";
    switch (RelayMode)
    {
      case 3: //Daily
        // DData = DData + " ";
        if (CurrentItem > 0 && CurrentItem < 4) CurrentItem = 4;
        break;
      default:
        DData = DData + BlinkString(String(RelayOn.year(), DEC), CurrentItem, 1) + "/" + BlinkString(String( RelayOn.month(), DEC), CurrentItem, 2) +
                "/" + BlinkString(String( RelayOn.day(), DEC), CurrentItem, 3);
    }
    DData = DData + " " + BlinkString(String (RelayOn.hour(), DEC), CurrentItem, 4) + ":" + BlinkString(String(RelayOn.minute(), DEC), CurrentItem, 5);
    LcdPrint(1, DData, CENTER);
    DData = "Off:";
    switch (RelayMode)
    {
      case 3: //Daily
        // DData = DData + " ";
        if (CurrentItem > 5 && CurrentItem < 9) CurrentItem = 9;
        break;
      default:
        DData = DData + BlinkString(String(RelayOff.year(), DEC), CurrentItem, 6) + "/" + BlinkString(String( RelayOff.month(), DEC), CurrentItem, 7) +
                "/" + BlinkString(String( RelayOff.day(), DEC), CurrentItem, 8);
    }
    DData = DData + " " + BlinkString(String (RelayOff.hour(), DEC), CurrentItem, 9) + ":" + BlinkString(String(RelayOff.minute(), DEC), CurrentItem, 10);
    LcdPrint(2, DData, CENTER);
    LcdPrint(3, " ", CENTER);
  }

  boolean TRelayMenu::CheckDaily(void)
  {
    int TimeOn = 60 * int(RelayOn.hour()) + int(RelayOn.minute());
    int TimeOff = 60 * int(RelayOff.hour()) + int(RelayOff.minute());
    int NowTime = 60 * int(NowDate.hour()) + int(NowDate.minute());
    boolean result; // true = время включения больше времени выключения
    if ( TimeOn > TimeOff )
    {
      if (NowTime <= TimeOff || NowTime >= TimeOn ) result = true;
      else result = false;
    }
    else
    {
      if (NowTime <= TimeOff && NowTime >= TimeOn ) result = true;
      else result = false;
    };
    return result;

  }

 

T.Rook
Offline
Зарегистрирован: 05.03.2016

ну блииииин.  ну там же else без if!!!!!!!

У Вас "if" закоментирован . см: case 3:

это сознательно?

 

sir_kimas
Offline
Зарегистрирован: 01.08.2016

T.Rook пишет:

ну блииииин.  ну там же else без if!!!!!!!

У Вас "if" закоментирован . см: case 3:

это сознательно?

 

УПС. Не заметил.

СПАСИБО.