4-х канальное реле времени (Arduino)

На рисунке показана схема 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{");}

Comments

  1. А возможно ли в этой схеме реализовать автоматическое включение подсветки после нажатия MENU и отключение подсветки после последнего обращения к кнопке по истечении, ну скажем 5-7 сек? Чтобы подсветка постоянно не горела.

    1. Да, можно. Вам нужно добавить транзисторный ключ в схему подсветки, а на базу транзистора через 4,7 кОм с любого свободного пина ардуино подавать управляющий сигнал.

  2. Тоже столкнулся с проблемой отображения воскресенья на экране. Использую ds3231. Читал, что делали изменения, но не понял в каких строках. Можете подсказать.

              1. Да, отображаются. Не отображается только в режиме MENU «Вск», т.е. пустое место. И при переборе дней недели в обратную сторону, т.е. нажимаем «-» ничего не происходит — пустое место.

Добавить комментарий

Войти с помощью: