Introduction: Arduino Ultra Mega Timers
Hi! "Arduino Timer with on/off setpoint" is my most viewed instructable by far, so i got a lot of questions in the comments, inbox and youtube, about how to add minutes,seconds, days and save settings on the eeprom.... so i decided to bring an old code, made with PIC, to arduino, easier to share and make.
I tried to make this project compact, easy to use and set up, with 3 buttons and a 16x2 lcd.The interface is based on my previous instructable "Turn single screen into multiple screens". If you want to learn how this interface was made, please visit:
https://www.instructables.com/id/Arduino-LCD-16x2-Turn-Single-Screen-Into-Multiple-/
Here you have 6 codes to choose:
All timers are hours,minutes and seconds (on/off) programmables. Save data on the eeprom.
-1Timer for everyday,
-1Timer, selectable day
-4 Timers. 1 relay, for everyday
All timers has a "simple" version, that means, without lcd interface. Useful if you want to save money or don't need to chage the settings periodically.
These timers can recover the data and work even in case of power failure. The code was made to activate the relay at any moment.
We'll start from the basic timer to the more complete one.With this timer you can even turn on something for a second!
You will need:
-Arduino UNO
-LCD 16x2 (I2C)
-RTC 3231 module
-Push buttons x3
-10K resistors x3
-Relay module x1
-Breadboard,wires,etc
Watch the video!
Step 1: First Steps
First of all, we need to set up the LCD,RTC and clear the arduinos eeprom.
-LCD The lcd must have an address, declared at the beginning of the code:
LiquidCrystal_I2C lcd(0x3F,16,2);//0x3F is my lcd address, maybe not yours!
If you don't know your address, use the utility "I2C scanner" . Connect your lcd as follows:
-VCC to arduino 5V
-GND to arduino GND
-SDA to arduino analog pin 4
-SCL to arduino analog pin 5
Upload the code and open the serial monitor, the address will be displayed. Replace the address if it's not the same (0x3F) in the codes of the next steps.
Download:
https://gist.github.com/tfeldmann/5411375
-RTC We'll use the RTC 3231, but the rigth time must be programmed. Add the RTClib-master to your Arduino library. Go to File/examples/RTClib/ds3231 .Upload the code. This sketch take the Date and Time according the computer you're using (right when you compile the code) and uses that to program the RTC. If your computer time is not set right you should fix that first. Then you must press the Upload button to compile and then immediately upload.
Warning !:If you compile and then upload later, the clock will be off by that amount of time. Then open up the Serial monitor window to show that the time has been set.
Connect your rtc as follows:
-VCC to arduino 5V
-GND to arduino GND
-SDA to arduino analog pin 4
-SCL to arduino analog pin 5
If you don't know, the lcd and the rtc can be connected at the same time to the I2C bus (analog 4 SDA, analog 5 SCL).
-EEPROM clear Commonly ,eeprom values are 255 x address and we need to set these values to 0. The eeprom library is already included on your arduino IDE.
Go to File/Examples/EEPROM/eeprom_clear.
Upload the code and wait for the pin 13 led to turn on. You can check your values with the eeprom_read code.
Watch the video!
The RTC and LCD libraries used in this tutorial:
Step 2: Timer's Trick
One of the challenges here is to compare the "on time" and "off time" with the current time at every moment. One can think in something like this:
if(now hour==on hour &&now minute==on minute && now second==on second)
relay on
if(now hour==off hour&&now minute==off minute&&now second==off second)
relay off
This might work, but what if your on setpoint is 12:30:00, your off setpoint 15:45:15 and the current time is 13:00:00 ? Well, you will wait until the next day to turn on your device ! Or what if you lose power beetwen 12:30:00 and 15:45:15? The same thing:to wait for the settings to be triggered.
If you looked at my previous timer, there are a lot of if/else statements to control the relay, because time is cyclic and we need to cover all the possible scenarios. But to add minutes and seconds it´s something else. All values can be higher or lower than the on/off settings or current time and try to compare it will be a mess.
So i thought in something like military time or string number from 0 to 235959, and that's the trick of these timers. So, we convert the current time, on setpoint and off setpoint into single number.
I just will explain how the timers work,because the interface to change settings and display values,etc, can be studied in my instructable of multiple screens. Link in the intro.
First, we create the variables for the timer (on/off):
//------First Timer
byte onhour1;
byte onmin1;
byte onsec1;
byte offhour1;
byte offmin1;
byte offsec1;
A byte data type (0 to 255 unsigned) was used to store the values. A byte can be easily stored on the eeprom (1 data x address) and the bigger number will be 59 (minute or second). We take the values from the eeprom, 0 at the very beginning, because the eeprom was cleared.Where ( ) is the eeprom address.
void setup.......
//--------eePROM read values-------//
//------First Timer
onhour1=EEPROM.read(0);
onmin1=EEPROM.read(1);
onsec1=EEPROM.read(2);
offhour1=EEPROM.read(3);
offmin1=EEPROM.read(4);
offsec1=EEPROM.read(5);
These values can be changed and saved, later on with the buttons interface.
But we can't do the maths (conversion to single number) with bytes because our bigger number will be 235,959 or int =32,767 (positive) or unsigned int=65,535. So, unsigned long will be.
We create another variable to convert byte into unsigned long. Also, the final values to work with: on_Time1 and off_Time1
//------To convert first timer into Single number
unsigned long on_Time1;
unsigned long on_hour1;
unsigned long on_min1;
unsigned long on_sec1;
unsigned long off_Time1;
unsigned long off_hour1;
unsigned long off_min1;
unsigned long off_sec1;
//-------To convert clock into single number
unsigned long Time;
unsigned long Hour;
unsigned long Min;
unsigned long Sec;
The conversion is executed in the void loop. For the current time, we take the values from the rtc with the library function now() ,hour, minute, second and assign this values to Hour,Min and Sec. "Time" is the result of the sum of Hour*10000 ; Min*100 and Sec.
Example: 15:45:34 = (15*10000 + 45*100 + 34) = 154,534
//-------------Conversion----------//
//---------Converting clock time into single number
Hour = now.hour();
Min = now.minute();
Sec = now.second();
Time = (Hour*10000+ Min*100 +Sec*1);
And the same with the on/off settings. Here we take the values from the beginning (byte) and assign these values as follows:
//--------Converting firt timer on/off into single number
on_hour1=onhour1;
on_min1=onmin1;
on_sec1=onsec1;
on_Time1=(on_hour1*10000 + on_min1*100 + on_sec1);
off_hour1=offhour1;
off_min1=offmin1;
off_sec1=offsec1;
off_Time1=(off_hour1*10000 + off_min1*100 + off_sec1);
The final result are the 3 variables with we will work : Time, on_Time1 and off_Time1
Now the relay function. Here we compare "Time" with "on_Time1" and "off_Time1" to turn on or off the relay. We have 3 main "if" statements:
1)if(onhour1 == offhour1 && onmin1==offmin1 && onsec1==offsec1){
digitalWrite(Relay, LOW); }
This statement is an enable/disable function. We use the byte values, because we don't need any conversion here. If all values are the same the relay is off. If you change , even a second, the timer will work.
2)if(on_Time1 < off_Time1){
if(Time >= on_Time1 && Time < off_Time1){ //Start
digitalWrite(Relay, HIGH);
}
else if(Time >= off_Time1) {
digitalWrite(Relay, LOW);
}
else{
digitalWrite(Relay, LOW);
}
}
3)if (on_Time1 > off_Time1){
if(Time >= on_Time1 && Time <= 235959){ //Start
digitalWrite(Relay, HIGH);
}
else if(Time < off_Time1 ){
digitalWrite(Relay, HIGH);
}
else if(Time >= off_Time1 && Time < on_Time1){
digitalWrite(Relay, LOW); } }
These 2 functions cover the 2 possible settings: "on time" lower than "off time" and "on time" higher than "off time".Inside each one you can find 3 statements more to control the relay at any moment.The functions can be easily understand with a graphic demo. Watch the pictures!
With the buttons interface we can change the values (on/off) and store our new ones.This is the structure to store the values. As i have said, we store the byte values on a single address. where:
(address, byte value)
EEPROM.write(0, onhour1);
EEPROM.write(1, onmin1);
EEPROM.write(2, onsec1);
EEPROM.write(3, offhour1);
EEPROM.write(4, offmin1);
EEPROM.write(5, offsec1);
Step 3: 1 Timer for Everyday
This timer is the base for the next ones. Mount the circuit following the schematic, remember RTC and LCD share the same pins (analog 4 SDA ; analog 5 SCL).
Upload the code, remember to add the libraries RTClib and LiquidCrystal_I2C.
You have 3 buttons to move the 3 main pages with the up/down buttons and select button to enter and move the submenus.
The first page shows you a message and the current time.
The second page is the on/off interface, here you can change the setpoints. Press the select button to enter to submenu, an arrow will be placed in front of each item, press up or down to set the on hour, minute, second and off hour, minute, second. Press the select button to move beetwen items (forward only) The final item is the "back" char, if you press up, it will exit the submenu and now you can move the main pages. If you press down, the arrow will be placed in front of the first item.
The third page is to save your settings. Just press the select buton and all your data will be stored on the eeprom. A message "SAVED!" will be displayed and automatically redirect to the main page.
This timer will work everyday and in case of power failure or disconnection will recover the data from the eeprom to start again.
With the relay you can control your devices. The relay is activated with a high signal (5V).
Warning! Be careful with the maximum load of the relay!
Step 4: 1 Timer, Selectable Day
This timer is for those who want to control the day where the timer is activated. For this, we'll use the RTC's function "now.dayOfTheWeek()" and it values can be 1 to 7 ; Monday to Sunday. To assign the day of the week to each number, we use this(global variables):
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
To display it on the LCD (main page):
lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
We need new variables to know if the day is enebled/disabled.So:
//------Days of the week
boolean Sun1;
boolean Mon1;
boolean Tue1;
boolean Wed1;
boolean Thu1;
boolean Fri1;
boolean Sat1;
We use boolean values (1 or 0) and as the other variables, we take the values from the eeprom.Boolean can be stored in 1 address. The last address used was 5 (offsec1), so we continue with:
void setup.....
Sun1=EEPROM.read(6);
Mon1=EEPROM.read(7);
Tue1=EEPROM.read(8);
Wed1=EEPROM.read(9);
Thu1=EEPROM.read(10);
Fri1=EEPROM.read(11);
Sat1=EEPROM.read(12);
Remember, your first value will be 0 (eeprom clear). So 0 is for disable and 1 for enable day.
In order to control the relay, we need to check the current day and check if the timer is enabled/disabled for that day.
Another switch function is used, where every "case" will be the value of "now.dayOfTheWeek()" (1 to 7)
//----Relay Function per day----//
switch(now.dayOfTheWeek()){ //now.dayOfTheWeek values 1 to 7, monday to sunday
case 1: //If monday
if(Mon1==1){
First_Timer();
}
else{
digitalWrite(Relay1, LOW);
}
break;
case 2: //If tuesday
if(Tue1==1){
First_Timer();
}
else{
digitalWrite(Relay1, LOW);
} break;
case 3: .......and so on...
For example: If today is monday (now.dayOfTheWeek() =1), we enter to the first case. if the boolean value Mon1==1 (day enabled), we call a custom function "First_Timer()", the same relay function from the previous timer, now working as a custom function, so we don't need to write it on every case. If we put a 0 the relay function will be LOW (day disabled). So we use one case per day and skip the others.
Now we need to add another screen to the interface to change the settings.
The main page shows you the current day and time.
The second page the on/off setings.
Here we introduce the new page where you can select the day to activate the relay and it works the same as the others: the arrow indicates the item, if you press the up button you will put a 1 on that day and it will be enabled. If you press down, you will put a 0 and the day will be disabled.
The fourth page save the settings, on/off time and day enabled/disabled. The structure to save:
EEPROM.write(0, onhour1);
EEPROM.write(1, onmin1);
EEPROM.write(2, onsec1);
EEPROM.write(3, offhour1);
EEPROM.write(4, offmin1);
EEPROM.write(5, offsec1);
EEPROM.write(6, Sun1);
EEPROM.write(7, Mon1);
EEPROM.write(8, Tue1);
EEPROM.write(9, Wed1);
EEPROM.write(10, Thu1);
EEPROM.write(11, Fri1);
EEPROM.write(12, Sat1);
Step 5: 4 Timers 1 Relay for Everyday
Another request from the users. This timer is able to control 4 event at day with a single output. No much to say about this because we only add more variables for the timer 2, 3, and 4, also the interface to move the settings. We continue reading and writting from the eeprom, from the last address used.
Note: Be careful to don't overlap the timers, because any of it can turn on or off the relay.
So, here you have 3 timers with a nice interface. For the "simple" version, you just need to change the values within "///////////".Default values are 0.
on/offhour1, 2,3,4 = 0-23
on/offmin1, 2,3,4 =0-59
on/offsec1, 2,3,4 =0-59
Day enabled/disabled =1 for enable 0 for disable.
"Simple" timers doesn't need eeprom save because you have already stored the values. This useful too, if you want to study the timer's code.
As you can see, more timers can be added, following the logic,and you can use the "selectable day" function on it.
If you are a beginner, this project it's easy to make and run, but if you want to go deep into the code, that's another story. This is not rocket science, but you need some knowledge to face the codes. That's why i've separeted the codes for better understanding. i'm just saying this because i get a lot of question from users about how to modify codes and i can't do that for you, I can always help you, of course.I hope you understand.