Суточный таймер

Тема в разделе "Arduino & Shields", создана пользователем KIMAS, 11 апр 2017.

  1. KIMAS

    KIMAS Нуб

    Уважаемые знатоки. Помогите переделать скеч. Сейчас 4 реле. Нужно 8 реле чтобы включались и выключались по времени. И самое трудное для меня это переделать меню. Может ка кто упростить выкинуть лишнее.
    Код (C++):
    #include <EEPROM.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
    volatile boolean Blinker = true;
    volatile long BlinkerTime;
    volatile byte ButtonPress[8];
    const String RelayModeNames[] = {"OFF", "ON", "Once", "Daily"};

    int aKey1 = 0;
    int aKey2 = 0;
     

    Вложения:

  2. KIMAS

    KIMAS Нуб

    Код (C++):
    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.init();
      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(2017, 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 *********************/
     
  3. KIMAS

    KIMAS Нуб

    Код (C++):
      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);
      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);
          }
        }
      }
    [/code]
     
  4. KIMAS

    KIMAS Нуб

    В 1 пост не смог загрузить скеч. :(