На рисунке показана схема 4-х канального реле времени на основе Arduino, уст-во содержит минимальный набор внешних элементов, просто в изготовлении и использовании. Ранее на страницах 8-и канальное реле времени (Arduino) и 4-х канальное реле времени (Arduino) были показаны примеры создания многоканальных реле времени на основе Arduino, на этой странице аналогичные реле времени но с большим функционалом. Главной особенностью этого реле времени является возможность установки времени включения и выключения реле для каждого дня недели.
Все установленные значения времени включения и выключения реле для каждого дня недели сохраняются в энергонезависимой памяти. В реле времени используется плата Arduino Nano или Uno, LCD дисплей 84×48 Nokia 5110, четыре кнопки управления, модуль часов реального времени на базе микросхемы DS3231 со встроенным аккумулятором и модуль четырех канального реле.
Реле времени содержит четыре кнопки управления:
- Menu — 5 режимов, 1 — основное меню, 2-5 переход к настройкам времени срабатывания реле
- ОК — перебор параметров при настройке реле (день недели, время включения и выключения минуты и часы)
- «+» и «-» — увеличение или уменьшения времени часов и минут, перебор для недели.
Настраивать реле времени достаточно просто, правда параметров очень много, необходимо задать время включения и выключения для каждого дня недели и для каждого реле. Если необходимо чтобы реле не срабатывало в определенный день недели, нужно время включения установить больше или равным времени выключения.
В основном меню (при подачи питания на плату) на первых двух строках индикатора выводится текущее дата и время, остальные строки отображают состояние реле (ON OFF), на самой нижней строке выводится температура датчика установленного в часах реального времени DS3231.
Если в часах реального времени не установленно время, то необходимо раскомментировать строчку:
// clock.setDateTime(__DATE__, __TIME__); // Устанавливаем время на часах, основываясь на времени компиляции скетча
Записать скетч в Arduino, затем закомментировать строчку и снова записать скетч в Arduino. Будет установлено время компиляции, которое с текущем будет отличаться на несколько секунд.
В скетче используются следующие библиотеки:
DS3231.zip — библиотека часов реального времени
pcd8544.zip — библиотека Nokia5110 LCD (библиотека частично русифицирована, поэтому для правильного отображения символов используйте именно эту библиотеку )
EEPROMEx.zip — #include <EEPROMex.h> — для старой версии Arduino IDE, для последних версий #include <EEPROM.h>, библиотеку устанавливать не нужно.
#include <Wire.h> #include <SPI.h> #include <PCD8544.h> #include <DS3231.h> #include <EEPROMex.h> DS3231 clock;RTCDateTime DateTime; PCD8544 lcd; // RST,CE,DC,DIN,CLK VCC,BL,GND (3,4,5,6,7 +3.3V,200 OM +3.3V, GND) char * mes[12]{"/)&",",e&","Map$","A;p","Ma]","^_)`","^_{`","A&}","Ce)","Ok$","Ho*","#ek"}; char * den[7]{"Bck","!o)","B$p","Cp(","'$&","!*$","C@["}; int i,n,ok,menu,x,w,mem,d_mem,t,n_d,ind0,ind1,ind2,ind3; int m0_on[7],h0_on[7],m0_of[7],h0_of[7]; int m1_on[7],h1_on[7],m1_of[7],h1_of[7]; int m2_on[7],h2_on[7],m2_of[7],h2_of[7]; int m3_on[7],h3_on[7],m3_of[7],h3_of[7]; static const byte gradus[] = { B00000110,B00001001,B00001001,B00000110,B00000000 };// градус void setup(){ Serial.begin(9600);Wire.begin();clock.begin(); // clock.setDateTime(__DATE__, __TIME__); // Устанавливаем время на часах, основываясь на времени компиляции скетча lcd.begin(84, 48);lcd.setContrast(70);// контрастность 0-127 pinMode(A0,INPUT); // menu pinMode(A1,INPUT); // + pinMode(A2,INPUT); // - pinMode(A3,INPUT); // ok pinMode(9,OUTPUT);pinMode(10,OUTPUT);pinMode(11,OUTPUT);pinMode(12,OUTPUT);// выходы реле lcd.createChar(0, gradus); for(d_mem=0;d_mem<7;d_mem++){mem++;m0_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h0_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m0_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h0_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m1_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h1_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m1_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h1_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m2_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h2_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m2_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h2_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m3_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h3_on[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;m3_of[d_mem]=EEPROM.read(mem);} for(d_mem=0;d_mem<7;d_mem++){mem++;h3_of[d_mem]=EEPROM.read(mem);} if(EEPROM.read(100)==255){for(mem=0;mem<120;mem++){EEPROM.update(mem,0);}}// если ячейка памяти №100 равна 255 установить все значения реле времени на 0 (код работает только при первом включении) mem=0; } void loop(){ ///////////////////////////// дата время /////////////////////////////// DateTime=clock.getDateTime();// опрос времени lcd.setCursor(0,0); lcd.print(clock.dateFormat("H:i:s ", DateTime));// выводим часы, минуты и секунды lcd.print(" ");for(i=0;i<7;i++){if(DateTime.dayOfWeek==i){lcd.print(den[i]);}}lcd.print(" ");// день недели lcd.setCursor(0,1);lcd.print(" ");lcd.print(DateTime.day);lcd.print(" "); // дата for(i=0;i<13;i++){if(DateTime.month==i){lcd.print(mes[i-1]);}}lcd.print(" "); // месяц lcd.print(DateTime.year);lcd.print(" "); // год lcd.setCursor(0,2);lcd.print("--------------"); //////////////////////////////////////////////////////////////////////// if(analogRead(A0)>900){menu++;w=1;mem=0;ok=0;n=0;lcd.clear();if(menu>4||menu<0){menu=0;}} // перебор реле 1...4 x++; if(x>1){x=0;} // мигание регулировки параметров /////////////////////////////////////// Реле 1 ///////////////////////// if(menu==1){ if(analogRead(A3)>900){ok++;}if(ok>4){ok=0;} ///// кнопка ОК - перебор параметров реле if(analogRead(A1)>900&&ok==0){n++;}if(analogRead(A2)>900&&ok==0){n--;}if(n>6||n<0){n=0;} //// день недели 0...6 lcd.setCursor(0,3);lcd.print(" Pe{e 1 ");if(x==0&&ok==0){lcd.print(" ");}else{lcd.print(den[n]);}lcd.print(" "); // вывод дня недели if(analogRead(A1)>900&&ok==1){m0_on[n]++;}if(analogRead(A2)>900&&ok==1){m0_on[n]--;}if(m0_on[n]>59||m0_on[n]<0){m0_on[n]=0;} if(analogRead(A1)>900&&ok==2){h0_on[n]++;}if(analogRead(A2)>900&&ok==2){h0_on[n]--;}if(h0_on[n]>23||h0_on[n]<0){h0_on[n]=0;} if(analogRead(A1)>900&&ok==3){m0_of[n]++;}if(analogRead(A2)>900&&ok==3){m0_of[n]--;}if(m0_of[n]>59||m0_of[n]<0){m0_of[n]=0;} if(analogRead(A1)>900&&ok==4){h0_of[n]++;}if(analogRead(A2)>900&&ok==4){h0_of[n]--;}if(h0_of[n]>23||h0_of[n]<0){h0_of[n]=0;} lcd.setCursor(0,4);lcd.print(" "); if(x==0&&ok==2){lcd.print(" ");}else{if(h0_on[n]<10){lcd.print("0");}lcd.print(h0_on[n]);}lcd.print(":"); if(x==0&&ok==1){lcd.print(" ");}else{if(m0_on[n]<10){lcd.print("0");}lcd.print(m0_on[n]);}lcd.print(" "); if(x==0&&ok==4){lcd.print(" ");}else{if(h0_of[n]<10){lcd.print("0");}lcd.print(h0_of[n]);}lcd.print(":"); if(x==0&&ok==3){lcd.print(" ");}else{if(m0_of[n]<10){lcd.print("0");}lcd.print(m0_of[n]);} lcd.setCursor(0,5);str6();} /////////////////////////////////////////////////////////////////////// /////////////////////////////////////// Реле 2 ///////////////////////// if(menu==2){ if(analogRead(A3)>900){ok++;}if(ok>4){ok=0;} ///// кнопка ОК - перебор параметров реле if(analogRead(A1)>900&&ok==0){n++;}if(analogRead(A2)>900&&ok==0){n--;}if(n>6||n<0){n=0;} //// день недели 0...6 lcd.setCursor(0,3);lcd.print(" Pe{e 2 ");if(x==0&&ok==0){lcd.print(" ");}else{lcd.print(den[n]);}lcd.print(" "); // вывод дня недели if(analogRead(A1)>900&&ok==1){m1_on[n]++;}if(analogRead(A2)>900&&ok==1){m1_on[n]--;}if(m1_on[n]>59||m1_on[n]<0){m1_on[n]=0;} if(analogRead(A1)>900&&ok==2){h1_on[n]++;}if(analogRead(A2)>900&&ok==2){h1_on[n]--;}if(h1_on[n]>23||h1_on[n]<0){h1_on[n]=0;} if(analogRead(A1)>900&&ok==3){m1_of[n]++;}if(analogRead(A2)>900&&ok==3){m1_of[n]--;}if(m1_of[n]>59||m1_of[n]<0){m1_of[n]=0;} if(analogRead(A1)>900&&ok==4){h1_of[n]++;}if(analogRead(A2)>900&&ok==4){h1_of[n]--;}if(h1_of[n]>23||h1_of[n]<0){h1_of[n]=0;} lcd.setCursor(0,4);lcd.print(" "); if(x==0&&ok==2){lcd.print(" ");}else{if(h1_on[n]<10){lcd.print("0");}lcd.print(h1_on[n]);}lcd.print(":"); if(x==0&&ok==1){lcd.print(" ");}else{if(m1_on[n]<10){lcd.print("0");}lcd.print(m1_on[n]);}lcd.print(" "); if(x==0&&ok==4){lcd.print(" ");}else{if(h1_of[n]<10){lcd.print("0");}lcd.print(h1_of[n]);}lcd.print(":"); if(x==0&&ok==3){lcd.print(" ");}else{if(m1_of[n]<10){lcd.print("0");}lcd.print(m1_of[n]);} lcd.setCursor(0,5);str6();} /////////////////////////////////////////////////////////////////////// /////////////////////////////////////// Реле 3 ///////////////////////// if(menu==3){ if(analogRead(A3)>900){ok++;}if(ok>4){ok=0;} ///// кнопка ОК - перебор параметров реле if(analogRead(A1)>900&&ok==0){n++;}if(analogRead(A2)>900&&ok==0){n--;}if(n>6||n<0){n=0;} //// день недели 0...6 lcd.setCursor(0,3);lcd.print(" Pe{e 3 ");if(x==0&&ok==0){lcd.print(" ");}else{lcd.print(den[n]);}lcd.print(" "); // вывод дня недели if(analogRead(A1)>900&&ok==1){m2_on[n]++;}if(analogRead(A2)>900&&ok==1){m2_on[n]--;}if(m2_on[n]>59||m2_on[n]<0){m2_on[n]=0;} if(analogRead(A1)>900&&ok==2){h2_on[n]++;}if(analogRead(A2)>900&&ok==2){h2_on[n]--;}if(h2_on[n]>23||h2_on[n]<0){h2_on[n]=0;} if(analogRead(A1)>900&&ok==3){m2_of[n]++;}if(analogRead(A2)>900&&ok==3){m2_of[n]--;}if(m2_of[n]>59||m2_of[n]<0){m2_of[n]=0;} if(analogRead(A1)>900&&ok==4){h2_of[n]++;}if(analogRead(A2)>900&&ok==4){h2_of[n]--;}if(h2_of[n]>23||h2_of[n]<0){h2_of[n]=0;} lcd.setCursor(0,4);lcd.print(" "); if(x==0&&ok==2){lcd.print(" ");}else{if(h2_on[n]<10){lcd.print("0");}lcd.print(h2_on[n]);}lcd.print(":"); if(x==0&&ok==1){lcd.print(" ");}else{if(m2_on[n]<10){lcd.print("0");}lcd.print(m2_on[n]);}lcd.print(" "); if(x==0&&ok==4){lcd.print(" ");}else{if(h2_of[n]<10){lcd.print("0");}lcd.print(h2_of[n]);}lcd.print(":"); if(x==0&&ok==3){lcd.print(" ");}else{if(m2_of[n]<10){lcd.print("0");}lcd.print(m2_of[n]);} lcd.setCursor(0,5);str6();} /////////////////////////////////////////////////////////////////////// /////////////////////////////////////// Реле 4 ///////////////////////// if(menu==4){ if(analogRead(A3)>900){ok++;}if(ok>4){ok=0;} ///// кнопка ОК - перебор параметров реле if(analogRead(A1)>900&&ok==0){n++;}if(analogRead(A2)>900&&ok==0){n--;}if(n>6||n<0){n=0;} //// день недели 0...6 lcd.setCursor(0,3);lcd.print(" Pe{e 4 ");if(x==0&&ok==0){lcd.print(" ");}else{lcd.print(den[n]);}lcd.print(" "); // вывод дня недели if(analogRead(A1)>900&&ok==1){m3_on[n]++;}if(analogRead(A2)>900&&ok==1){m3_on[n]--;}if(m3_on[n]>59||m3_on[n]<0){m3_on[n]=0;} if(analogRead(A1)>900&&ok==2){h3_on[n]++;}if(analogRead(A2)>900&&ok==2){h3_on[n]--;}if(h3_on[n]>23||h3_on[n]<0){h3_on[n]=0;} if(analogRead(A1)>900&&ok==3){m3_of[n]++;}if(analogRead(A2)>900&&ok==3){m3_of[n]--;}if(m3_of[n]>59||m3_of[n]<0){m3_of[n]=0;} if(analogRead(A1)>900&&ok==4){h3_of[n]++;}if(analogRead(A2)>900&&ok==4){h3_of[n]--;}if(h3_of[n]>23||h3_of[n]<0){h3_of[n]=0;} lcd.setCursor(0,4);lcd.print(" "); if(x==0&&ok==2){lcd.print(" ");}else{if(h3_on[n]<10){lcd.print("0");}lcd.print(h3_on[n]);}lcd.print(":"); if(x==0&&ok==1){lcd.print(" ");}else{if(m3_on[n]<10){lcd.print("0");}lcd.print(m3_on[n]);}lcd.print(" "); if(x==0&&ok==4){lcd.print(" ");}else{if(h3_of[n]<10){lcd.print("0");}lcd.print(h3_of[n]);}lcd.print(":"); if(x==0&&ok==3){lcd.print(" ");}else{if(m3_of[n]<10){lcd.print("0");}lcd.print(m3_of[n]);} lcd.setCursor(0,5);str6();} /////////////////////////////////////////////////////////////////////// //////////////////// управление реле ////////////////////////////////// t=DateTime.hour*100+DateTime.minute; // текущее время, например: 1026 = 10 часов 26 минут n_d=DateTime.dayOfWeek; // текущий день недели 0...6 пон...вос if(t>=(h0_on[n_d]*100+m0_on[n_d])&&t<(h0_of[n_d]*100+m0_of[n_d])&&(h0_on[n_d]*100+m0_on[n_d])!=(h0_of[n_d]*100+m0_of[n_d])){digitalWrite(9,HIGH);ind0=1;} else{digitalWrite(9,LOW);ind0=0;} if(t>=(h1_on[n_d]*100+m1_on[n_d])&&t<(h1_of[n_d]*100+m1_of[n_d])&&(h1_on[n_d]*100+m1_on[n_d])!=(h1_of[n_d]*100+m1_of[n_d])){digitalWrite(10,HIGH);ind1=1;}else{digitalWrite(10,LOW);ind1=0;} if(t>=(h2_on[n_d]*100+m2_on[n_d])&&t<(h2_of[n_d]*100+m2_of[n_d])&&(h2_on[n_d]*100+m2_on[n_d])!=(h2_of[n_d]*100+m2_of[n_d])){digitalWrite(11,HIGH);ind2=1;}else{digitalWrite(11,LOW);ind2=0;} if(t>=(h3_on[n_d]*100+m3_on[n_d])&&t<(h3_of[n_d]*100+m3_of[n_d])&&(h3_on[n_d]*100+m3_on[n_d])!=(h3_of[n_d]*100+m3_of[n_d])){digitalWrite(12,HIGH);ind3=1;}else{digitalWrite(12,LOW);ind3=0;} ////////////////////////////////////////////////////////////////////// delay(100); if(menu==0){ lcd.setCursor(0,3);if(ind0==0){lcd.print(" P1 OFF");}else{lcd.print(" P1 ON ");}if(ind1==0){lcd.print(" P2 OFF ");}else{lcd.print(" P2 ON ");} lcd.setCursor(0,4);if(ind2==0){lcd.print(" P3 OFF");}else{lcd.print(" P3 ON ");}if(ind3==0){lcd.print(" P4 OFF ");}else{lcd.print(" P4 ON ");} lcd.setCursor(0,5);lcd.print(" Te~;ep. ");lcd.print(clock.readTemperature(),1);lcd.write(0);lcd.print("C"); } ///////////////////////////////// EEPROM ////////////////////////////// if(w==1){ for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m0_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h0_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m0_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h0_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m1_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h1_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m1_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h1_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m2_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h2_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m2_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h2_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m3_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h3_on[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,m3_of[d_mem]);} for(d_mem=0;d_mem<7;d_mem++){mem++;EEPROM.update(mem,h3_of[d_mem]);} w=0;} if(DateTime.hour==0&&DateTime.minute==0&&DateTime.second==0){lcd.clear();}// сбор экрана каждые сутки в 0ч 0м 0с }///// loop void str6(){lcd.print(" Bk{ B?k{");}
А возможно ли в этой схеме реализовать автоматическое включение подсветки после нажатия MENU и отключение подсветки после последнего обращения к кнопке по истечении, ну скажем 5-7 сек? Чтобы подсветка постоянно не горела.
Да, можно. Вам нужно добавить транзисторный ключ в схему подсветки, а на базу транзистора через 4,7 кОм с любого свободного пина ардуино подавать управляющий сигнал.
Тоже столкнулся с проблемой отображения воскресенья на экране. Использую ds3231. Читал, что делали изменения, но не понял в каких строках. Можете подсказать.
Попробуйте этот скетч — http://forum.rcl-radio.ru/viewtopic.php?pid=2715#p2715
Загрузил скетч с форума. Воскресенье появилось на основном экране, а вот в меню «Вск» пропало.
Обновите скетч, я внес исправления.
Ничего не изменилось 🙁
Другие дни недели отображаются?
Да, отображаются. Не отображается только в режиме MENU «Вск», т.е. пустое место. И при переборе дней недели в обратную сторону, т.е. нажимаем «-» ничего не происходит — пустое место.
Пока не пойму почему не работает, внес правки в скетч — http://forum.rcl-radio.ru/viewtopic.php?pid=2715#p2715
Вроде заработало. Сейчас погоняю по настройкам. Спасибо за помощь!
Понимаю что истек срок давности. Возможно сделать опрос датчика влажности (замкнут/разомкнут) и не включать реле если замкнут.