Как стать автором
Обновить

Экономим электричество или таймер времени для ночного тарифа в электросетях

Время на прочтение30 мин
Количество просмотров85K
Как часто вам приходится настраивать различные таймеры? Будильник на смартфоне, таймер на хлебопечке, чтобы к завтраку был свежий хлеб, да и мало ли когда нужно что-то начать. Не менее важной оказывается задача вовремя отключить или закончить действие.

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

Итак, стоит задача включать электрический котел отопления для обогрева дома в ночной период времени, когда тарификация хоть немного щадящая. Что из этого получилось — смотрите ниже.

image

Покупать готовое реле времени за 6-8 тысяч рублей (не говорим о простых девайсах, втыкаемых в розетку), которые будут замыкать нужные контакты по срабатыванию событий или по времени, просто неспортивно. Кроме того, контроллер с аналогичными функциями, а то и с хорошим запасом функционала обойдется раза в 4 дешевле, не говоря о разминке для мозгов. Началось все в новогодние праздники.

Задача работы в строго отведенное время требует знать текущее время и задать границы работы. Все бы хорошо, но желательно менять время работы и иногда подстраивать часы. Кроме того, удобнее реализовать задачу в виде конечного устройства, которое не будет требовать наличия компьютера для смены параметров. Также на контроллер будут повешены дополнительные функции, но это в версии 2.0, а пока — таймер времени.

Отсюда определился список устройств, необходимых для выполнения задачи:

1. Arduino Nano (чем дешевле модуль, тем лучше, так как задачи не ресурсоёмкие);
2. Модуль времени RTC;
3. Модуль реле ( 2 реле);
4. Адаптер питания для ардуино. Был выбран DC-DC преобразователь-стабилизатор 12В-5В;
5. Дисплей 4х20 символов для красоты (в наличии были 4-х строчный и 2-х строчный);
6. Адаптер I2C для дисплея.

Вот так это оказалось соединено в итоге:

image

Собрать это все на макетке было делом достаточно простым. Изучая Хабр, я давненько приметил работу с I2C -шиной и уж больно мне понравился дизайн часов товарища, поэтому я позаимствовал часть его кода и сделал основные часы в таком же стиле.

Дальше шел долгий процесс изучения работы с EEPROM и модулем часов, чтобы при сбое питания таймер времени и сами часы не сбивались. Поначалу часы выключались, но длительное изучение форумов привело к мысли, что в модуле RTC стоит Li-ION аккумулятор и он просто сел от долгого путешествия из Китая в Россию. Поддержка питанием в течении пары суток позволила восполнить разряд и больше время не сбивалось.

Осталось соединить все модули покрепче, написать код и начать отладку.

Скетч реле времени
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib


#include <EEPROM.h>
#include <Wire.h>
#include <DS1307.h>
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
#define timePIN 10
#define RELE_1 12 //объявляем работу 1 реле на пине 7
#define RELE_2 11 //объявляем работу 2 реле на пине 8

//на пин A4 цепляем SDA монитора и SDA часов
//на пин A5 цепляем SCL монитора и SCL часов


int FullMinutesTimerOn = EEPROM.read(0);
int FullMinutesTimerOff = EEPROM.read(2); 
int rtc[7];
byte rr[7];
int ledPin =  13;
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display
int button1 = 10; //кнопка на пин D10
int button2 = 9; //кнопка на пин D9
int button3 = 8; //кнопка на пин D8
int button4 = 7; //кнопка на пин D7
int button5 = 6; //кнопка на пин D6
int led = 5;
int rejim=0; //переменная режима изменения настроек таймера
int PrevSec=0;
int CurSec=0;
boolean lastButton=LOW;


byte LT[8] = 
{


  B00111,
  B01111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte UB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte RT[8] =
{

  B11100,
  B11110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte LL[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01111,
  B00111
};
byte LB[8] =
{
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};
byte LR[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11110,
  B11100
};
byte MB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111
};
byte block[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
// loop counter
int count = 0;



void setup () {
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd
  PORTC |=_BV(3);  // VCC PINC3
  pinMode(ledPin, OUTPUT);  
  pinMode(timePIN, OUTPUT); 
  pinMode(RELE_1, OUTPUT); //инициируем реле только на выход  
  pinMode(RELE_2, OUTPUT); //инициируем реле только на выход
  digitalWrite(RELE_1, HIGH); // запускаем реле выключенными
  digitalWrite(RELE_2, HIGH); // запускаем реле выключенными 
  
  RTC.get(rtc,true);
  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  lcd.home();

  lcd.createChar(0,LT);
  lcd.createChar(1,UB);
  lcd.createChar(2,RT);
  lcd.createChar(3,LL);
  lcd.createChar(4,LB);
  lcd.createChar(5,LR);
  lcd.createChar(6,MB);
  lcd.createChar(7,block);

  // sets the LCD's rows and colums:
  lcd.clear();  



  RTC.SetOutput(DS1307_SQW32KHZ);
  pinMode(led, OUTPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(button3, INPUT);
}



void custom0(int x)
{ // uses segments to build the number 0

  lcd.setCursor(x,0); // set cursor to column 0, line 0 (first row)
  lcd.write(0);  // call each segment to create
  lcd.write(1);  // top half of the number
  lcd.write(2);
  lcd.setCursor(x, 1); // set cursor to colum 0, line 1 (second row)
  lcd.write(3);  // call each segment to create
  lcd.write(4);  // bottom half of the number
  lcd.write(5);
}

void custom1(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(2);
  lcd.print(" ");
  lcd.setCursor(x,1);
  lcd.write(4);
  lcd.write(7);
  lcd.write(4);
}

void custom2(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(4);
}

void custom3(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5); 
}

void custom4(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(4);
  lcd.write(7);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom5(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5);
}

void custom6(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom7(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom8(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom9(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);

}

void digitalClockDisplay(){
  // digital clock display of the time
  

  printDigits(rtc[2]/10,0); 
  printDigits(rtc[2]%10,4); 

  printDigits(rtc[1]/10,9);
  printDigits(rtc[1]%10,13);

   
  if (rtc[0]%10%2==0){
    lcd.setCursor(7, 0);
    lcd.print("+ ");
    lcd.setCursor(7, 1);
    lcd.print(" +");
    lcd.setCursor(3, 1);
    lcd.print("+");
    lcd.setCursor(12, 0);
    lcd.print("+");
    lcd.setCursor(3, 0);
    lcd.print(" ");
    lcd.setCursor(12, 1);
    lcd.print(" ");
  }
  else
  {
    lcd.setCursor(7, 0);
    lcd.print(" +");
    lcd.setCursor(7, 1);
    lcd.print("+ ");
    lcd.setCursor(3, 0);
    lcd.print("+");
    lcd.setCursor(12, 1);
    lcd.print("+");
    lcd.setCursor(3, 1);
    lcd.print(" ");
    lcd.setCursor(12, 0);
    lcd.print(" ");
  }
  //нарисовали двоеточие

}



void printDigits(int digits, int x){
  // utility function for digital clock display: prints preceding colon and leading 0

  switch (digits) {
  case 0:  
    custom0(x);
    break;
  case 1:  
    custom1(x);
    break;
  case 2:  
    custom2(x);
    break;
  case 3:  
    custom3(x);
    break;
  case 4:  
    custom4(x);
    break;
  case 5:  
    custom5(x);
    break;
  case 6:  
    custom6(x);
    break;
  case 7:  
    custom7(x);
    break;
  case 8:  
    custom8(x);
    break;
  case 9:  
    custom9(x);
    break;

  }


}


void loop () {
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1]; //присваиваем минуты
  int Second = rtc[0]; // присваиваем секунды
  int FullMinutes = Hour * 60 + Minute; //приводим значение текущего времени к минутам
  int FullMinutesTimerOn= hourOn*60+minOn; //приводим значение ВКЛЮЧЕНИЯ таймера к минутам
  int FullMinutesTimerOff= hourOff*60+minOff; //приводим значение ВЫКЛЮЧЕНИЯ таймера к минутам
  int sutki=0; // по умолчанию, таймер работает в одних сутках
  
  if (hourOff-hourOn < 0) sutki=1; //если время выключения на следующие сутки, то включаем триггер сутки=1
  else sutki=0;
  
  if (sutki==1 && (FullMinutes >= FullMinutesTimerOn || FullMinutes <= FullMinutesTimerOff) ) 
{
lcd.setCursor(16, 2);
lcd.print("VKL1"); 
digitalWrite(RELE_1, LOW);
 // если сутки перескакивают, то проверяем время оператором ИЛИ
}
else if (sutki==1)
{
  lcd.print("    ");
    digitalWrite(RELE_1, HIGH);
}
  
  if (sutki == 0 && (FullMinutes >= FullMinutesTimerOn && FullMinutes <= FullMinutesTimerOff )) 
  {
    lcd.setCursor(16, 2);
    lcd.print("VKL0");
   digitalWrite(RELE_1, LOW);
  } // если сутки НЕ перескакивают, то проверяем время оператором И
  else if (sutki == 0) 
  {
    lcd.print("    ");
    digitalWrite(RELE_1, HIGH);
  }
  
  RTC.get(rtc,true);
  digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
  strokatimera();
           
if (rejim==0) 
  {
    lcd.setCursor(0, 2);
    lcd.print ("ojidayu komandi");
    }
     if (rejim==1) 
  {
    setTimerOn();
    }
  if (rejim==2) 
  {
      setTimerOff();
  }
  if (rejim==3) 
  {
      setTime();
    }

if (digitalRead (button5) == HIGH) 
{ 
  rejim++;
  if (rejim>3) rejim=0;
  lcd.clear();
  //}
}
  
}

void setTimerOn() 
{
  int hourOn= EEPROM.read(110); 
  int minOn= EEPROM.read(111); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VKL");
  
      if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     hourOn++;
    if (hourOn >=24) hourOn=0;
        }
   
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minOn++;
    if (minOn >=60) 
    {
      minOn=0;
      hourOn++;
      if (hourOn >=24) hourOn=0;
    }
    }
 strokatimera();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(110, hourOn);
      EEPROM.write(111, minOn);
      lcd.clear();
      }
    }

void setTimerOff() 
{
  int hourOff= EEPROM.read(112); 
  int minOff= EEPROM.read(113); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VIKL");
  
    if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     hourOff++;
    if (hourOff >=24) hourOff=0;
        }
   
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minOff++;
    if (minOff >=60) 
    {
      minOff=0;
      hourOff++;
      if (hourOff >=24) hourOff=0;
    }
    }
 strokatimera();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(112, hourOff);
      EEPROM.write(113, minOff);
      lcd.clear();
      }
}

void setTime()
{
  lcd.setCursor(0, 2);
  //lcd.print ("nastroika time_test");
   lcd.print ("pustaya nastroika");
}

void strokatimera()
{
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
    lcd.print(hourOn);
    lcd.print(":");
    lcd.print(minOn); 
    lcd.print("-");
    lcd.print(hourOff);
    lcd.print(":");
    lcd.print(minOff);
  }
 


А вот так это работает:



Для меня осталось загадкой, почему контроллер не хочет реагировать на нажатие отдельных кнопок изменения минут и часов, но охотно реагирует на нажатие другой кнопки, меняя минуты. Исходя из этого, допилил код до рабочего, хотя и индусского состояния, так как первый релиз таймера надо запускать в работу, а с остальным разбираться позже. Грешу на перегрев при пайке, хотя вывод на эти контакты стандартного Blink дает нормальное напряжение на пине. На данный момент пин D6 позволяет войти в меню изменения, а пин D9 листает минуты. Может кто подскажет, если сталкивался с подобным?

P.S. Уже после написания статьи я столкнулся с тем, что задачи, поставленные перед контроллером, надо расширять. Дело в том, что данный контроллер управляет электрическим котлом в дачном доме, а с ростом температуры стала повышаться влажность. Пришлось добавить в систему вентиляции канальный вентилятор аналогичный этому:

image

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

Действующий код
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib


#include <EEPROM.h>
#include <Wire.h>
#include <DS1307.h>
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
//#define timePIN 10
#define RELE_1 12 //объявляем работу 1 реле на пине 7
#define RELE_2 11 //объявляем работу 2 реле на пине 8


//на пин A4 цепляем SDA монитора и SDA часов
//на пин A5 цепляем SCL монитора и SCL часов


int FullMinutesTimerOn = EEPROM.read(0);
int FullMinutesTimerOff = EEPROM.read(2); 
int rtc[7];
byte rr[7];
int ledPin =  13;
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display
int button1 = 10; //кнопка на пин D10
int button2 = 9; //кнопка на пин D9
int button3 = 8; //кнопка на пин D8
int button4 = 7; //кнопка на пин D7
int button5 = 6; //кнопка на пин D6
int led = 5;
int rejim=0; //переменная режима изменения настроек таймера
int PrevSec=0;
int CurSec=0;
boolean lastButton=LOW;


byte LT[8] = 
{


  B00111,
  B01111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte UB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte RT[8] =
{

  B11100,
  B11110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte LL[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01111,
  B00111
};
byte LB[8] =
{
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};
byte LR[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11110,
  B11100
};
byte MB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111
};
byte block[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
// loop counter
int count = 0;



void setup () {
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd
  PORTC |=_BV(3);  // VCC PINC3
  pinMode(ledPin, OUTPUT);  
  //pinMode(timePIN, OUTPUT); 
  pinMode(RELE_1, OUTPUT); //инициируем реле только на выход  
  pinMode(RELE_2, OUTPUT); //инициируем реле только на выход
  digitalWrite(RELE_1, HIGH); // запускаем реле выключенными
  digitalWrite(RELE_2, HIGH); // запускаем реле выключенными 
  
  RTC.get(rtc,true);
  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  lcd.home();

  lcd.createChar(0,LT);
  lcd.createChar(1,UB);
  lcd.createChar(2,RT);
  lcd.createChar(3,LL);
  lcd.createChar(4,LB);
  lcd.createChar(5,LR);
  lcd.createChar(6,MB);
  lcd.createChar(7,block);

  // sets the LCD's rows and colums:
  lcd.clear();  



  RTC.SetOutput(DS1307_SQW32KHZ);
  pinMode(led, OUTPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(button3, INPUT);
}



void custom0(int x)
{ // uses segments to build the number 0

  lcd.setCursor(x,0); // set cursor to column 0, line 0 (first row)
  lcd.write(0);  // call each segment to create
  lcd.write(1);  // top half of the number
  lcd.write(2);
  lcd.setCursor(x, 1); // set cursor to colum 0, line 1 (second row)
  lcd.write(3);  // call each segment to create
  lcd.write(4);  // bottom half of the number
  lcd.write(5);
}

void custom1(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(2);
  lcd.print(" ");
  lcd.setCursor(x,1);
  lcd.write(4);
  lcd.write(7);
  lcd.write(4);
}

void custom2(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(4);
}

void custom3(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5); 
}

void custom4(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(4);
  lcd.write(7);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom5(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5);
}

void custom6(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom7(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom8(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom9(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);

}

void digitalClockDisplay(){
  // digital clock display of the time
  

  printDigits(rtc[2]/10,0); 
  printDigits(rtc[2]%10,4); 

  printDigits(rtc[1]/10,9);
  printDigits(rtc[1]%10,13);

   
  if (rtc[0]%10%2==0){
    lcd.setCursor(7, 0);
    lcd.print("+ ");
    lcd.setCursor(7, 1);
    lcd.print(" +");
    lcd.setCursor(3, 1);
    lcd.print("+");
    lcd.setCursor(12, 0);
    lcd.print("+");
    lcd.setCursor(3, 0);
    lcd.print(" ");
    lcd.setCursor(12, 1);
    lcd.print(" ");
  }
  else
  {
    lcd.setCursor(7, 0);
    lcd.print(" +");
    lcd.setCursor(7, 1);
    lcd.print("+ ");
    lcd.setCursor(3, 0);
    lcd.print("+");
    lcd.setCursor(12, 1);
    lcd.print("+");
    lcd.setCursor(3, 1);
    lcd.print(" ");
    lcd.setCursor(12, 0);
    lcd.print(" ");
  }
  //нарисовали двоеточие

}



void printDigits(int digits, int x){
  // utility function for digital clock display: prints preceding colon and leading 0

  switch (digits) {
  case 0:  
    custom0(x);
    break;
  case 1:  
    custom1(x);
    break;
  case 2:  
    custom2(x);
    break;
  case 3:  
    custom3(x);
    break;
  case 4:  
    custom4(x);
    break;
  case 5:  
    custom5(x);
    break;
  case 6:  
    custom6(x);
    break;
  case 7:  
    custom7(x);
    break;
  case 8:  
    custom8(x);
    break;
  case 9:  
    custom9(x);
    break;

  }


}


void loop () {
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  int minVent= EEPROM.read(114); //время работы вентилятора
  
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1]; //присваиваем минуты
  int Second = rtc[0]; // присваиваем секунды
  int FullMinutes = Hour * 60 + Minute; //приводим значение текущего времени к минутам
  int FullMinutesTimerOn= hourOn*60+minOn; //приводим значение ВКЛЮЧЕНИЯ таймера к минутам
  int FullMinutesTimerOff= hourOff*60+minOff; //приводим значение ВЫКЛЮЧЕНИЯ таймера к минутам
  int sutki=0; // по умолчанию, таймер работает в одних сутках
  
  if (hourOff-hourOn < 0) sutki=1; //если время выключения на следующие сутки, то включаем триггер сутки=1
  else sutki=0;
    
  if (sutki==1 && (FullMinutes >= FullMinutesTimerOn || FullMinutes <= FullMinutesTimerOff) ) 
{
lcd.setCursor(16, 2);
lcd.print("VKL1"); 
digitalWrite(RELE_1, LOW);
 // если сутки перескакивают, то проверяем время оператором ИЛИ
}
else if (sutki==1)
{
  lcd.print("    ");
    digitalWrite(RELE_1, HIGH);
}
  
  if (sutki == 0 && (FullMinutes >= FullMinutesTimerOn && FullMinutes <= FullMinutesTimerOff )) 
  {
    lcd.setCursor(16, 2);
    lcd.print("VKL0");
   digitalWrite(RELE_1, LOW);
  } // если сутки НЕ перескакивают, то проверяем время оператором И
  else if (sutki == 0) 
  {
    lcd.print("    ");
    digitalWrite(RELE_1, HIGH);
  }
  
  if ((Minute >= 0 && Minute <= minVent) && (Hour >= 9 && Hour <= 21))
  {
    lcd.setCursor(17, 1);
    lcd.print("VEN");
    digitalWrite(RELE_2, LOW);
  }
  if (Minute >= 0 && Minute > minVent)
    {
    lcd.setCursor(17, 1);
    lcd.print("   ");
    digitalWrite(RELE_2, HIGH);
   }
  
  RTC.get(rtc,true);
  digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
  strokatimera();
           
if (rejim==0) 
  {
    lcd.setCursor(0, 2);
    lcd.print ("ojidayu komandi");
    }
     if (rejim==1) 
     {
      setTimerOn();
     }
   if (rejim==2) 
   {
      setTimerOff();
   }
  if (rejim==3) 
  {
      setTime();
    }
  if (rejim==4)
  {
  setVent();
  }  

if (digitalRead (button5) == HIGH) 
{ 
  rejim++;
  if (rejim>4) rejim=0;
  lcd.clear();
  //}
}
  
}

void setTimerOn() 
{
  int hourOn= EEPROM.read(110); 
  int minOn= EEPROM.read(111); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VKL");
  
      if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
      hourOn++;
      if (hourOn >=24) hourOn=0;
      }
   
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minOn++;
    if (minOn >=60) 
    {
      minOn=0;
      hourOn++;
      if (hourOn >=24) hourOn=0;
    }
    }
 strokatimera();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(110, hourOn);
      EEPROM.write(111, minOn);
      lcd.clear();
      }
    }

void setTimerOff() 
{
  int hourOff= EEPROM.read(112); 
  int minOff= EEPROM.read(113); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VIKL");
  
    if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
       hourOff++;
       if (hourOff >=24) hourOff=0;
      }
   
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minOff++;
    if (minOff >=60) 
    {
      minOff=0;
      hourOff++;
      if (hourOff >=24) hourOff=0;
     }
    }
 strokatimera();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(112, hourOff);
      EEPROM.write(113, minOff);
      lcd.clear();
      }
}

void setTime()
{
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1];
  //lcd.clear();
  lcd.setCursor(0, 2);
  lcd.print ("nastroika time");
  RTC.get(rtc,true);
  
  //lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
   // lcd.print(Hour);
   // lcd.print(":");
   // lcd.print(Minute);
  
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    Minute++;
    if (Minute >=60) 
    {
      Minute=0;
      Hour++;
      if (Hour >=24) Hour=0;
    }
   }
 
    if (digitalRead(button2) == HIGH)
    {
      RTC.set(DS1307_MIN,Minute);
      RTC.set(DS1307_HR,Hour);
      lcd.clear();
      }
  
   
}

void strokatimera()
{
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  int minVent= EEPROM.read(114);
  lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
    lcd.print(hourOn);
    lcd.print(":");
    lcd.print(minOn); 
    lcd.print("-");
    lcd.print(hourOff);
    lcd.print(":");
    lcd.print(minOff);
    lcd.print("  ");
    lcd.print("VENT:");
    lcd.print(minVent);
    
  }
    
void setVent()
{
  
  int minVent= EEPROM.read(114); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika Vent");
  
      if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minVent++;
    if (minVent >=60) 
    {
      minVent=0;
     }
    }
 
 strokatimera();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(114, minVent);
      lcd.clear();
     }
    }


В дальнейшем этот контроллер планируется подключить к OpenHab, чтобы удаленно наблюдать и управлять системой отопления и вентиляции дома.

Версия 1.1 прошивки, которая позволяет:
  • управлять котлом по заданному времени
  • управлять котлом по дням недели (new)
  • управлять системой вентиляции по времени (каждый час на заданное количество минут включается)
  • отображает текущий день и отопление в сегодняшнем дне (в правом верхнем углу экрана номер дня и + либо — режим включения сегодня


Добавлена работа по дням
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib


#include <EEPROM.h>
#include <Wire.h>
#include <DS1307.h>
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
//#define timePIN 10
#define RELE_1 12 //объявляем работу 1 реле на пине 7
#define RELE_2 11 //объявляем работу 2 реле на пине 8

//
//на пин A4 цепляем SDA монитора и SDA часов
//на пин A5 цепляем SCL монитора и SCL часов


int FullMinutesTimerOn = EEPROM.read(0);
int FullMinutesTimerOff = EEPROM.read(2); 
int rtc[7];
byte rr[7];
int ledPin =  13;
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display
int button1 = 10; //кнопка на пин D10
int button2 = 9; //кнопка на пин D9
int button3 = 8; //кнопка на пин D8
int button4 = 7; //кнопка на пин D7
int button5 = 6; //кнопка на пин D6
int led = 5;
int rejim=0; //переменная режима изменения настроек таймера
int i=1; //счетчик дней в меню настройки дней отопления
int PrevSec=0;
int CurSec=0;
int Day=0;
boolean lastButton=LOW;


byte LT[8] = 
{


  B00111,
  B01111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte UB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte RT[8] =
{

  B11100,
  B11110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte LL[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01111,
  B00111
};
byte LB[8] =
{
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};
byte LR[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11110,
  B11100
};
byte MB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111
};
byte block[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
// loop counter
int count = 0;



void setup () {
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd
  PORTC |=_BV(3);  // VCC PINC3
  pinMode(ledPin, OUTPUT);  
  //pinMode(timePIN, OUTPUT); 
  pinMode(RELE_1, OUTPUT); //инициируем реле только на выход  
  pinMode(RELE_2, OUTPUT); //инициируем реле только на выход
  digitalWrite(RELE_1, HIGH); // запускаем реле выключенными
  digitalWrite(RELE_2, HIGH); // запускаем реле выключенными 
  
  RTC.get(rtc,true);
  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  lcd.home();

  lcd.createChar(0,LT);
  lcd.createChar(1,UB);
  lcd.createChar(2,RT);
  lcd.createChar(3,LL);
  lcd.createChar(4,LB);
  lcd.createChar(5,LR);
  lcd.createChar(6,MB);
  lcd.createChar(7,block);

  // sets the LCD's rows and colums:
  lcd.clear();  
  RTC.SetOutput(DS1307_SQW32KHZ);
  pinMode(led, OUTPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(button3, INPUT);
}



void custom0(int x)
{ // uses segments to build the number 0

  lcd.setCursor(x,0); // set cursor to column 0, line 0 (first row)
  lcd.write(0);  // call each segment to create
  lcd.write(1);  // top half of the number
  lcd.write(2);
  lcd.setCursor(x, 1); // set cursor to colum 0, line 1 (second row)
  lcd.write(3);  // call each segment to create
  lcd.write(4);  // bottom half of the number
  lcd.write(5);
}

void custom1(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(2);
  lcd.print(" ");
  lcd.setCursor(x,1);
  lcd.write(4);
  lcd.write(7);
  lcd.write(4);
}

void custom2(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(4);
}

void custom3(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5); 
}

void custom4(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(4);
  lcd.write(7);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom5(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5);
}

void custom6(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom7(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom8(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom9(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);

}

void digitalClockDisplay(){
  // digital clock display of the time
  printDigits(rtc[2]/10,0); 
  printDigits(rtc[2]%10,4); 
  printDigits(rtc[1]/10,9);
  printDigits(rtc[1]%10,13);

   
  if (rtc[0]%10%2==0){
    lcd.setCursor(7, 0);
    lcd.print("+ ");
    lcd.setCursor(7, 1);
    lcd.print(" +");
    lcd.setCursor(3, 1);
    lcd.print("+");
    lcd.setCursor(12, 0);
    lcd.print("+");
    lcd.setCursor(3, 0);
    lcd.print(" ");
    lcd.setCursor(12, 1);
    lcd.print(" ");
  }
  else
  {
    lcd.setCursor(7, 0);
    lcd.print(" +");
    lcd.setCursor(7, 1);
    lcd.print("+ ");
    lcd.setCursor(3, 0);
    lcd.print("+");
    lcd.setCursor(12, 1);
    lcd.print("+");
    lcd.setCursor(3, 1);
    lcd.print(" ");
    lcd.setCursor(12, 0);
    lcd.print(" ");
  }
  //нарисовали двоеточие

}



void printDigits(int digits, int x){
  // utility function for digital clock display: prints preceding colon and leading 0

  switch (digits) {
  case 0:  
    custom0(x);
    break;
  case 1:  
    custom1(x);
    break;
  case 2:  
    custom2(x);
    break;
  case 3:  
    custom3(x);
    break;
  case 4:  
    custom4(x);
    break;
  case 5:  
    custom5(x);
    break;
  case 6:  
    custom6(x);
    break;
  case 7:  
    custom7(x);
    break;
  case 8:  
    custom8(x);
    break;
  case 9:  
    custom9(x);
    break;

  }


}


void loop () {
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  int minVent= EEPROM.read(114); //время работы вентилятора
  int rejimDay=0;
  int Day = rtc[3]; //присваиваем день
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1]; //присваиваем минуты
  int Second = rtc[0]; // присваиваем секунды
  int FullMinutes = Hour * 60 + Minute; //приводим значение текущего времени к минутам
  int FullMinutesTimerOn= hourOn*60+minOn; //приводим значение ВКЛЮЧЕНИЯ таймера к минутам
  int FullMinutesTimerOff= hourOff*60+minOff; //приводим значение ВЫКЛЮЧЕНИЯ таймера к минутам
  int sutki=0; // по умолчанию, таймер работает в одних сутках
  
  lcd.setCursor(16, 0);
  lcd.print(Day); 
  
  if (hourOff-hourOn < 0) sutki=1; //если время выключения на следующие сутки, то включаем триггер сутки=1
  else sutki=0;
  
  if (EEPROM.read(114+Day)==1 && sutki==1)
  {
    rejimDay=1;
    lcd.print("+");
  }
  else
  {
    rejimDay=0;
    lcd.print("-");
  }
  
    
  if (sutki==1 && (FullMinutes >= FullMinutesTimerOn || FullMinutes <= FullMinutesTimerOff) ) 
{
lcd.setCursor(16, 2);
lcd.print("VKL"); 
digitalWrite(RELE_1, LOW);
 // если сутки перескакивают, то проверяем время оператором ИЛИ
}
else if (sutki==1)
{
  lcd.print("   ");
    digitalWrite(RELE_1, HIGH);
}
  
  if (sutki == 0 && (FullMinutes >= FullMinutesTimerOn && FullMinutes <= FullMinutesTimerOff )) 
  {
    lcd.setCursor(16, 2);
    lcd.print("VKL");
   digitalWrite(RELE_1, LOW);
  } // если сутки НЕ перескакивают, то проверяем время оператором И
  else if (sutki == 0) 
  {
    lcd.print("   ");
    digitalWrite(RELE_1, HIGH);
  }
  
  if ((Minute >= 0 && Minute <= minVent) && (Hour >= 9 && Hour <= 21))
  {
    lcd.setCursor(17, 1);
    lcd.print("VEN");
    digitalWrite(RELE_2, LOW);
  }
  if (Minute >= 0 && Minute > minVent)
    {
    lcd.setCursor(17, 1);
    lcd.print("   ");
    digitalWrite(RELE_2, HIGH);
  }
  
  RTC.get(rtc,true);

           
  if (rejim==0) 
    {
    lcd.setCursor(0, 2);
    lcd.print ("ojidayu komandi");
    strokatimera();
    digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
    }
   if (rejim==1) 
   {
    setTimerOn();
   }
  if (rejim==2) 
  {
      setTimerOff();
  }
  if (rejim==3) 
  {
      setTime();
    }
  if (rejim==4)
  {
  setVent();
  }  
  if (rejim==5)
  {
  setTimerDay1();
  } 
  

if (digitalRead (button5) == HIGH) 
{ 
  rejim++;
  delay(100);
  if (rejim>5) rejim=0;
  lcd.clear();
  //}
}
  
}

void setTimerOn() 
{
  int hourOn= EEPROM.read(110); 
  int minOn= EEPROM.read(111); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VKL");
  
      if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     hourOn++;
    if (hourOn >=24) hourOn=0;
        }
   
  if (digitalRead(button2)==HIGH) //нажимая нижнюю кнопку меняем минуты
  {
    minOn++;
    if (minOn >=60) 
    {
      minOn=0;
      hourOn++;
      if (hourOn >=24) hourOn=0;
    }
    }
 strokatimera();
 digitalClockDisplay();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(110, hourOn);
      EEPROM.write(111, minOn);
      lcd.clear();
      }
    }

void setTimerOff() 
{
  int hourOff= EEPROM.read(112); 
  int minOff= EEPROM.read(113); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VIKL");
  
    if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     hourOff++;
    if (hourOff >=24) hourOff=0;
        }
   
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minOff++;
    if (minOff >=60) 
    {
      minOff=0;
      hourOff++;
      if (hourOff >=24) hourOff=0;
    }
    }
 strokatimera();
 digitalClockDisplay();
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(112, hourOff);
      EEPROM.write(113, minOff);
      lcd.clear();
      }
}

void setTime()
{
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1];
  //lcd.clear();
  lcd.setCursor(0, 2);
  lcd.print ("nastroika time");
  RTC.get(rtc,true);
  digitalClockDisplay();
  //lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
   // lcd.print(Hour);
   // lcd.print(":");
   // lcd.print(Minute);
  
  if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    Minute++;
    if (Minute >=60) 
    {
      Minute=0;
      Hour++;
      if (Hour >=24) Hour=0;
    }
    }
 
    if (digitalRead(button2) == HIGH)
    {
      RTC.set(DS1307_MIN,Minute);
      RTC.set(DS1307_HR,Hour);
      lcd.clear();
      }
  
   
}

void strokatimera()
{
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  int minVent= EEPROM.read(114);
  lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
    lcd.print(hourOn);
    lcd.print(":");
    lcd.print(minOn); 
    lcd.print("-");
    lcd.print(hourOff);
    lcd.print(":");
    lcd.print(minOff);
    lcd.print("  ");
    lcd.print("VENT:");
    lcd.print(minVent);
    
  }
    
void setVent()
{
  strokatimera();
  int minVent= EEPROM.read(114); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika Vent");
  
      if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minVent++;
    if (minVent >=60) 
    {
      minVent=0;
     }
   }
 
 digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(114, minVent);
      lcd.clear();
    }
}
void setTimerDay1()
{
  
  int z;
  //lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print ("nastroika dney");
  //lcd.setCursor(0, 1);
    
   lcd.setCursor (0,3);
   lcd.print (EEPROM.read(115));
   lcd.print (" ");
   lcd.print (EEPROM.read(116));
   lcd.print (" ");
   lcd.print (EEPROM.read(117));
   lcd.print (" ");
   lcd.print (EEPROM.read(118));
   lcd.print (" ");
   lcd.print (EEPROM.read(119));
   lcd.print (" ");
   lcd.print (EEPROM.read(120));
   lcd.print (" ");
   lcd.print (EEPROM.read(121));
   lcd.print (" "); 
  
  //lcd.clear();
      
    z=EEPROM.read(114+i); // присваеваем текущему дню состояние вкл/выкл из памяти
    if (i==1)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("ponedelnik");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==2)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("vtornik");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==3)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("sreda");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==4)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("chetverg");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==5)
    {
      lcd.setCursor(1, 2);
      lcd.print ("pyatnica");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==6)
    {
      lcd.setCursor(1, 2);
      lcd.print ("subbota");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==7)
    {
      lcd.setCursor(1, 2);
      lcd.print ("voskresen'e");
      lcd.print (" ");
      lcd.print (z);
    }
   
    if (digitalRead(button3)==HIGH) //переключаем дни недели
    {
      lcd.clear();
     i++;
     delay(150);
     if  (i>7) {i=1;}
    }
    
    if (digitalRead(button2)==HIGH)
    {
     delay(150);
     z=!z;
     if (z!= EEPROM.read(114+i))
      {
        EEPROM.write(114+i,z);
      }
    }
    
   
}     



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

Добавлено отключение вытяжки
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib


#include <EEPROM.h>
#include <Wire.h>
#include <DS1307.h>
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
//#define timePIN 10
#define RELE_1 11 //поменяли местами реле котла и вентиляции
#define RELE_2 12 //сейчас выключает вентиляцию, правое реле


//
//на пин A4 цепляем SDA монитора и SDA часов
//на пин A5 цепляем SCL монитора и SCL часов


int FullMinutesTimerOn = EEPROM.read(0);
int FullMinutesTimerOff = EEPROM.read(2); 
int rtc[7];
byte rr[7];
int ledPin =  13;
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display
int button1 = 10; //кнопка на пин D10
int button2 = 9; //кнопка на пин D9
int button3 = 8; //кнопка на пин D8
int button4 = 7; //кнопка на пин D7
int button5 = 6; //кнопка на пин D6
int vanna = 2; //вход с ванны на пин D2
int led = 5;
int rejim=0; //переменная режима изменения настроек таймера
int i=1; //счетчик дней в меню настройки дней отопления
int PrevSec=0;
int CurSec=0;
int Day=0;
int vannatimer=0;
boolean lastButton=LOW;


byte LT[8] = 
{


  B00111,
  B01111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte UB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte RT[8] =
{

  B11100,
  B11110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte LL[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01111,
  B00111
};
byte LB[8] =
{
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};
byte LR[8] =
{


  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11110,
  B11100
};
byte MB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111
};
byte block[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
// loop counter
int count = 0;



void setup () {
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd
  PORTC |=_BV(3);  // VCC PINC3
  pinMode(ledPin, OUTPUT);  
  //pinMode(timePIN, OUTPUT); 
  pinMode(RELE_1, OUTPUT); //инициируем реле только на выход  
  pinMode(RELE_2, OUTPUT); //инициируем реле только на выход
  digitalWrite(RELE_1, HIGH); // запускаем реле выключенными
  digitalWrite(RELE_2, HIGH); // запускаем реле выключенными
  
  
  RTC.get(rtc,true);
  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  lcd.home();

  lcd.createChar(0,LT);
  lcd.createChar(1,UB);
  lcd.createChar(2,RT);
  lcd.createChar(3,LL);
  lcd.createChar(4,LB);
  lcd.createChar(5,LR);
  lcd.createChar(6,MB);
  lcd.createChar(7,block);

  // sets the LCD's rows and colums:
  lcd.clear();  
  RTC.SetOutput(DS1307_SQW32KHZ);
  pinMode(led, OUTPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(button3, INPUT);
  pinMode(vanna, INPUT); // инициируем вход из ванной-туалета
}



void custom0(int x)
{ // uses segments to build the number 0

  lcd.setCursor(x,0); // set cursor to column 0, line 0 (first row)
  lcd.write(0);  // call each segment to create
  lcd.write(1);  // top half of the number
  lcd.write(2);
  lcd.setCursor(x, 1); // set cursor to colum 0, line 1 (second row)
  lcd.write(3);  // call each segment to create
  lcd.write(4);  // bottom half of the number
  lcd.write(5);
}

void custom1(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(2);
  lcd.print(" ");
  lcd.setCursor(x,1);
  lcd.write(4);
  lcd.write(7);
  lcd.write(4);
}

void custom2(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(4);
}

void custom3(int x)
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5); 
}

void custom4(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(4);
  lcd.write(7);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom5(int x)
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5);
}

void custom6(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom7(int x)
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);
}

void custom8(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom9(int x)
{
  lcd.setCursor(x,0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.print(" ");
  lcd.print(" ");
  lcd.write(7);

}

void digitalClockDisplay(){
  // digital clock display of the time
  printDigits(rtc[2]/10,0); 
  printDigits(rtc[2]%10,4); 
  printDigits(rtc[1]/10,9);
  printDigits(rtc[1]%10,13);

   
  if (rtc[0]%10%2==0){
    lcd.setCursor(7, 0);
    lcd.print("+ ");
    lcd.setCursor(7, 1);
    lcd.print(" +");
    lcd.setCursor(3, 1);
    lcd.print("+");
    lcd.setCursor(12, 0);
    lcd.print("+");
    lcd.setCursor(3, 0);
    lcd.print(" ");
    lcd.setCursor(12, 1);
    lcd.print(" ");
  }
  else
  {
    lcd.setCursor(7, 0);
    lcd.print(" +");
    lcd.setCursor(7, 1);
    lcd.print("+ ");
    lcd.setCursor(3, 0);
    lcd.print("+");
    lcd.setCursor(12, 1);
    lcd.print("+");
    lcd.setCursor(3, 1);
    lcd.print(" ");
    lcd.setCursor(12, 0);
    lcd.print(" ");
  }
  //нарисовали двоеточие

}



void printDigits(int digits, int x){
  // utility function for digital clock display: prints preceding colon and leading 0

  switch (digits) {
  case 0:  
    custom0(x);
    break;
  case 1:  
    custom1(x);
    break;
  case 2:  
    custom2(x);
    break;
  case 3:  
    custom3(x);
    break;
  case 4:  
    custom4(x);
    break;
  case 5:  
    custom5(x);
    break;
  case 6:  
    custom6(x);
    break;
  case 7:  
    custom7(x);
    break;
  case 8:  
    custom8(x);
    break;
  case 9:  
    custom9(x);
    break;

  }


}


void loop () {
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  int minVent= EEPROM.read(114); //время работы вентилятора
  int Vent= EEPROM.read(122);
  int rejimDay=0;
  int Day = rtc[3]; //присваиваем день
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1]; //присваиваем минуты
  int Second = rtc[0]; // присваиваем секунды
  int FullMinutes = Hour * 60 + Minute; //приводим значение текущего времени к минутам
  int FullMinutesTimerOn= hourOn*60+minOn; //приводим значение ВКЛЮЧЕНИЯ таймера к минутам
  int FullMinutesTimerOff= hourOff*60+minOff; //приводим значение ВЫКЛЮЧЕНИЯ таймера к минутам
  int sutki=0; // по умолчанию, таймер работает в одних сутках
  
  //if (digitalRead (vanna) == HIGH) // пока свет в ванной или в туалете горит включается вентилятор
  //{
  // digitalWrite(RELE_2, LOW);
   //digitalWrite(ledPin, HIGH);
  // vannatimer=1;
  //}
  
  lcd.setCursor(16, 0);
  lcd.print(Day); 
  
  if (hourOff-hourOn < 0) sutki=1; //если время выключения на следующие сутки, то включаем триггер сутки=1
  else sutki=0;
  
  if (EEPROM.read(114+Day)==1 && sutki==1)
  {
    rejimDay=1;
    lcd.print("+");
  }
  else
  {
    rejimDay=0;
    lcd.print("-");
  }
  
    
  if ((sutki==1 && rejimDay==1) && (FullMinutes >= FullMinutesTimerOn || FullMinutes <= FullMinutesTimerOff) ) 
{
lcd.setCursor(16, 2);
lcd.print("VKL"); 
digitalWrite(RELE_1, LOW);
 // если сутки перескакивают, то проверяем время оператором ИЛИ
}
else if (sutki==1)
{
  lcd.print("   ");
    digitalWrite(RELE_1, HIGH);
}
  
  if (sutki == 0 && (FullMinutes >= FullMinutesTimerOn && FullMinutes <= FullMinutesTimerOff )) 
  {
    lcd.setCursor(16, 2);
    lcd.print("VKL");
   digitalWrite(RELE_1, LOW);
  } // если сутки НЕ перескакивают, то проверяем время оператором И
  else if (sutki == 0) 
  {
    lcd.print("   ");
    digitalWrite(RELE_1, HIGH);
  }
  
  if (((Minute >= 0 && Minute <= minVent) && (Hour >= 9 && Hour <= 21))||(digitalRead (vanna) == HIGH))
  {
    if (Vent==1)
    {
    lcd.setCursor(17, 1);
    lcd.print("VEN");
    digitalWrite(RELE_2, LOW);
    }
  }
  if ((Minute >= 0 && Minute > minVent || digitalRead (vanna) == LOW)&&(Vent==0))
    {
    lcd.setCursor(17, 1);
    lcd.print("   ");
    digitalWrite(RELE_2, HIGH);
  }
  if (digitalRead (vanna) == HIGH) digitalWrite(RELE_2, LOW); //по включению света в ванной и таулете вытяжка включается всегда
  
  RTC.get(rtc,true);

           
  if (rejim==0) 
    {
    lcd.setCursor(0, 2);
    lcd.print ("ojidayu komandi");
    strokatimera();
    digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
    }
   if (rejim==1) 
   {
    setTimerOn();
   }
  if (rejim==2) 
  {
      setTimerOff();
  }
  if (rejim==3) 
  {
      setTime();
    }
  if (rejim==4)
  {
  setVent();
  }  
  
  if (rejim==5)
  {
  setVentOnOff();
  } 
  if (rejim==6)
  {
  setTimerDay1();
  } 
  

if (digitalRead (button5) == HIGH) 
{ 
  rejim++;
  delay(100);
  if (rejim>6) rejim=0;
  lcd.clear();
  //}
}
  
}

void setTimerOn() 
{
  int hourOn= EEPROM.read(110); 
  int minOn= EEPROM.read(111); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VKL");
  
      if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     hourOn++;
    if (hourOn >=24) hourOn=0;
        }
   
  if (digitalRead(button2)==HIGH) //нажимая нижнюю кнопку меняем минуты
  {
    minOn++;
    if (minOn >=60) 
    {
      minOn=0;
      hourOn++;
      if (hourOn >=24) hourOn=0;
    }
    }
 strokatimera();
 digitalClockDisplay();
    if ((digitalRead(button2) == HIGH)||(digitalRead(button3) == HIGH))
    {
      EEPROM.write(110, hourOn);
      EEPROM.write(111, minOn);
      lcd.clear();
      }
    }

void setTimerOff() 
{
  int hourOff= EEPROM.read(112); 
  int minOff= EEPROM.read(113); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika VIKL");
  
    if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     hourOff++;
    if (hourOff >=24) hourOff=0;
        }
   
  if (digitalRead(button2)==HIGH) //нажимая нижнюю кнопку меняем минуты
  {
    minOff++;
    if (minOff >=60) 
    {
      minOff=0;
      hourOff++;
      if (hourOff >=24) hourOff=0;
    }
    }
 strokatimera();
 digitalClockDisplay();
    if ((digitalRead(button2) == HIGH)||(digitalRead(button3) == HIGH))
    {
      EEPROM.write(112, hourOff);
      EEPROM.write(113, minOff);
      lcd.clear();
      }
}

void setTime()
{
  int Hour = rtc[2]; //присваиваем часы
  int Minute = rtc[1];
  //lcd.clear();
  lcd.setCursor(0, 2);
  lcd.print ("nastroika time");
  RTC.get(rtc,true);
  digitalClockDisplay();
  //lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
   // lcd.print(Hour);
   // lcd.print(":");
   // lcd.print(Minute);
  
  if (digitalRead(button2)==HIGH) //нажимая нижнюю кнопку меняем минуты
  {
    Minute++;
    if (Minute >=60) 
    {
      Minute=0;
      Hour++;
      if (Hour >=24) Hour=0;
    }
    }
    if (digitalRead(button3)==HIGH) //нажимая верхнюю кнопку меняем часы
     {  
     Hour++;
    if (Hour >=24) Hour=0;
        }
 
    if ((digitalRead(button2) == HIGH)||(digitalRead(button3) == HIGH))
    {
      RTC.set(DS1307_MIN,Minute);
      RTC.set(DS1307_HR,Hour);
      lcd.clear();
      }
  
   
}

void strokatimera()
{
  int hourOn=EEPROM.read(110); //EEPROM.read(110)
  int hourOff= EEPROM.read(112);; //EEPROM.read(112)
  int minOn= EEPROM.read(111);; //EEPROM.read(111)
  int minOff= EEPROM.read(113);; //EEPROM.read(113)
  int minVent= EEPROM.read(114);
  lcd.setCursor(0, 3); // вывод в последней строчке времени работы таймера
    lcd.print(hourOn);
    lcd.print(":");
    lcd.print(minOn); 
    lcd.print("-");
    lcd.print(hourOff);
    lcd.print(":");
    lcd.print(minOff);
    lcd.print("  ");
    lcd.print("VENT:");
    lcd.print(minVent);
    
  }
    
void setVent()
{
  strokatimera();
  int minVent= EEPROM.read(114); 
  lcd.setCursor(0, 2);
  lcd.print("nastroika Vent");
  
      if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем минуты
  {
    minVent++;
    if (minVent >=60) 
    {
      minVent=0;
     }
   }
 
 digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(114, minVent);
      lcd.clear();
    }
}




void setVentOnOff()
{
  strokatimera();
  int Vent= EEPROM.read(122); 
  lcd.setCursor(0, 2);
  lcd.print("Vent");
  if (Vent==0) lcd.print(" Off");
  if (Vent==1) lcd.print(" On");
      if (!digitalRead(button4)) //нажимая нижнюю кнопку меняем статус вкл откл
  {
    delay(100);
    Vent++;
    if (Vent >=2) 
    {
      Vent=0;
     }
   }
 
 digitalClockDisplay(); //выводим красивенькие часики на 2 строки 
    if (digitalRead(button2) == HIGH)
    {
      EEPROM.write(122, Vent);
      lcd.clear();
    }
    

}



void setTimerDay1()
{
  
  int z;
  //lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print ("nastroika dney");
  //lcd.setCursor(0, 1);
    
   lcd.setCursor (0,3);
   lcd.print (EEPROM.read(115));
   lcd.print (" ");
   lcd.print (EEPROM.read(116));
   lcd.print (" ");
   lcd.print (EEPROM.read(117));
   lcd.print (" ");
   lcd.print (EEPROM.read(118));
   lcd.print (" ");
   lcd.print (EEPROM.read(119));
   lcd.print (" ");
   lcd.print (EEPROM.read(120));
   lcd.print (" ");
   lcd.print (EEPROM.read(121));
   lcd.print (" "); 
  
  //lcd.clear();
      
    z=EEPROM.read(114+i); // присваеваем текущему дню состояние вкл/выкл из памяти
    if (i==1)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("ponedelnik");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==2)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("vtornik");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==3)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("sreda");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==4)
    {
      lcd.setCursor(1, 2); 
      lcd.print ("chetverg");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==5)
    {
      lcd.setCursor(1, 2);
      lcd.print ("pyatnica");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==6)
    {
      lcd.setCursor(1, 2);
      lcd.print ("subbota");
      lcd.print (" ");
      lcd.print (z);
    }
    if (i==7)
    {
      lcd.setCursor(1, 2);
      lcd.print ("voskresen'e");
      lcd.print (" ");
      lcd.print (z);
    }
   
    if (digitalRead(button3)==HIGH) //переключаем дни недели
    {
      lcd.clear();
     i++;
     delay(150);
     if  (i>7) {i=1;}
    }
    
    if (digitalRead(button2)==HIGH)
    {
     delay(150);
     z=!z;
     if (z!= EEPROM.read(114+i))
      {
        EEPROM.write(114+i,z);
      }
    }
    
    
    //EEPROM.write(115, 0);//понедельник
    //EEPROM.write(116, 0);//вторник
    //EEPROM.write(117, 1);//среда
    //EEPROM.write(118, 0);//четверг
    //EEPROM.write(119, 1);//пятница
    //EEPROM.write(120, 1);//суббота
    //EEPROM.write(121, 0);//воскресенье
      
     //z=EEPROM.read(114+i);
}     

Теги:
Хабы:
Всего голосов 30: ↑28 и ↓2+26
Комментарии76

Публикации

Истории

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
10 – 11 октября
HR IT & Team Lead конференция «Битва за IT-таланты»
МоскваОнлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Innopolis 2025
Иннополис