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

Покупать готовое реле времени за 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); }
