Как часто вам приходится настраивать различные таймеры? Будильник на смартфоне, таймер на хлебопечке, чтобы к завтраку был свежий хлеб, да и мало ли когда нужно что-то начать. Не менее важной оказывается задача вовремя отключить или закончить действие.
Так я столкнулся с задачей автоматизации включения и отключения электроприбора. Можно было бы воспользоваться типовой розеткой с реле времени, но включать надо необычную нагрузку, поэтому контроллер и только контроллер.
Итак, стоит задача включать электрический котел отопления для обогрева дома в ночной период времени, когда тарификация хоть немного щадящая. Что из этого получилось — смотрите ниже.
Покупать готовое реле времени за 6-8 тысяч рублей (не говорим о простых девайсах, втыкаемых в розетку), которые будут замыкать нужные контакты по срабатыванию событий или по времени, просто неспортивно. Кроме того, контроллер с аналогичными функциями, а то и с хорошим запасом функционала обойдется раза в 4 дешевле, не говоря о разминке для мозгов. Началось все в новогодние праздники.
Задача работы в строго отведенное время требует знать текущее время и задать границы работы. Все бы хорошо, но желательно менять время работы и иногда подстраивать часы. Кроме того, удобнее реализовать задачу в виде конечного устройства, которое не будет требовать наличия компьютера для смены параметров. Также на контроллер будут повешены дополнительные функции, но это в версии 2.0, а пока — таймер времени.
Отсюда определился список устройств, необходимых для выполнения задачи:
1. Arduino Nano (чем дешевле модуль, тем лучше, так как задачи не ресурсоёмкие);
2. Модуль времени RTC;
3. Модуль реле ( 2 реле);
4. Адаптер питания для ардуино. Был выбран DC-DC преобразователь-стабилизатор 12В-5В;
5. Дисплей 4х20 символов для красоты (в наличии были 4-х строчный и 2-х строчный);
6. Адаптер I2C для дисплея.
Вот так это оказалось соединено в итоге:
Собрать это все на макетке было делом достаточно простым. Изучая Хабр, я давненько приметил работу с I2C -шиной и уж больно мне понравился дизайн часов товарища, поэтому я позаимствовал часть его кода и сделал основные часы в таком же стиле.
Дальше шел долгий процесс изучения работы с EEPROM и модулем часов, чтобы при сбое питания таймер времени и сами часы не сбивались. Поначалу часы выключались, но длительное изучение форумов привело к мысли, что в модуле RTC стоит Li-ION аккумулятор и он просто сел от долгого путешествия из Китая в Россию. Поддержка питанием в течении пары суток позволила восполнить разряд и больше время не сбивалось.
Осталось соединить все модули покрепче, написать код и начать отладку.
А вот так это работает:
Для меня осталось загадкой, почему контроллер не хочет реагировать на нажатие отдельных кнопок изменения минут и часов, но охотно реагирует на нажатие другой кнопки, меняя минуты. Исходя из этого, допилил код до рабочего, хотя и индусского состояния, так как первый релиз таймера надо запускать в работу, а с остальным разбираться позже. Грешу на перегрев при пайке, хотя вывод на эти контакты стандартного Blink дает нормальное напряжение на пине. На данный момент пин D6 позволяет войти в меню изменения, а пин D9 листает минуты. Может кто подскажет, если сталкивался с подобным?
P.S. Уже после написания статьи я столкнулся с тем, что задачи, поставленные перед контроллером, надо расширять. Дело в том, что данный контроллер управляет электрическим котлом в дачном доме, а с ростом температуры стала повышаться влажность. Пришлось добавить в систему вентиляции канальный вентилятор аналогичный этому:
… и на второе реле повесить его включение. Опытным путем было установлено, что удачнее всего будет включать его каждый час на заданный промежуток времени. При этом включается он только с 9 до 21 часа, а ночью тепло из дома не выбрасывается. Регулировка времени включенного состояния также производится с кнопок, а вот время работы пока зашито в программе. На данный момент вытяжка включается на 10 минут каждый час. Оставлен задел на то, чтобы включать вытяжку автоматически, когда включается освещение в ванной или туалете.
Текущий код, который уверенно работает уже месяц, ниже:
В дальнейшем этот контроллер планируется подключить к OpenHab, чтобы удаленно наблюдать и управлять системой отопления и вентиляции дома.
Версия 1.1 прошивки, которая позволяет:
Столкнулся с тем, что регулярная работа вытяжки заметно выстужает дом в сильные морозы, выбрсывая тплый воздух за пределы помещения. Добавил в меню пункт выключения вытяжки. По включению освещения в туалете и ванной вытяжка работает всегда. Также поправил некоторые моменты в прошивке.
Так я столкнулся с задачей автоматизации включения и отключения электроприбора. Можно было бы воспользоваться типовой розеткой с реле времени, но включать надо необычную нагрузку, поэтому контроллер и только контроллер.
Итак, стоит задача включать электрический котел отопления для обогрева дома в ночной период времени, когда тарификация хоть немного щадящая. Что из этого получилось — смотрите ниже.
Покупать готовое реле времени за 6-8 тысяч рублей (не говорим о простых девайсах, втыкаемых в розетку), которые будут замыкать нужные контакты по срабатыванию событий или по времени, просто неспортивно. Кроме того, контроллер с аналогичными функциями, а то и с хорошим запасом функционала обойдется раза в 4 дешевле, не говоря о разминке для мозгов. Началось все в новогодние праздники.
Задача работы в строго отведенное время требует знать текущее время и задать границы работы. Все бы хорошо, но желательно менять время работы и иногда подстраивать часы. Кроме того, удобнее реализовать задачу в виде конечного устройства, которое не будет требовать наличия компьютера для смены параметров. Также на контроллер будут повешены дополнительные функции, но это в версии 2.0, а пока — таймер времени.
Отсюда определился список устройств, необходимых для выполнения задачи:
1. Arduino Nano (чем дешевле модуль, тем лучше, так как задачи не ресурсоёмкие);
2. Модуль времени RTC;
3. Модуль реле ( 2 реле);
4. Адаптер питания для ардуино. Был выбран DC-DC преобразователь-стабилизатор 12В-5В;
5. Дисплей 4х20 символов для красоты (в наличии были 4-х строчный и 2-х строчный);
6. Адаптер I2C для дисплея.
Вот так это оказалось соединено в итоге:
Собрать это все на макетке было делом достаточно простым. Изучая Хабр, я давненько приметил работу с 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. Уже после написания статьи я столкнулся с тем, что задачи, поставленные перед контроллером, надо расширять. Дело в том, что данный контроллер управляет электрическим котлом в дачном доме, а с ростом температуры стала повышаться влажность. Пришлось добавить в систему вентиляции канальный вентилятор аналогичный этому:
… и на второе реле повесить его включение. Опытным путем было установлено, что удачнее всего будет включать его каждый час на заданный промежуток времени. При этом включается он только с 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);
}