Description
A Real Time Clock (RTC) is basically just like a watch – it runs on a battery and keeps time for you even when there is a power outage. Using an RTC, you can keep track of long timelines, even if you reprogram your microcontroller or disconnect it from USB or a power plug.
The microcontroller on an Arduino board has a built-in timekeeper called millis() that counts the milliseconds since the Arduino was last powered. An Arduino doesn’t know that it’s ‘Tuesday’ or ‘March 8th’, all it can tell is ‘It’s been 14,000 milliseconds since I was last turned on’.
To keep accurate track of time, even if the Arduino is powered down, we can use a separate clock module.
DS1307 is a Real Time Clock (RTC) module. It consists of a time keeping chip using a frequency oscillator circuit, crystal and 3V lithium metal coin cell battery. Often this chip is placed on a board together with a small I2C EEPROM memory chip (24LC08B) and (often) a thermometer chip ( DS18B20) for you to use. The board is named “TinyRTC”.
There is also a DS3231 High Precision Real-Time Clock Module. There are two main differences between the ICs on the real-time clock modules, which is the accuracy of the time-keeping. The DS1307 used in the first module works very well, however the external temperature can affect the frequency of the oscillator circuit which drives the DS1307’s internal counter. This will usually result with the clock being off by around five or so minutes per month. The DS3231 is more accurate, as it has an internal oscillator which isn’t affected by external factors – and thus is accurate down to a few minutes per year at the most. The DS3231 uses the same I2C protocol and can be used in place of a DS1307 chip without a need to make changes to your code.
The RTC is an I2C device, which means it uses a 2 wire bus to communicate. The I2C bus consists of signal clock (SCL) and signal data (SDA) lines to communicate. The bus is unidirectional, meaning only one chip can speak at the same time. The I2C protocol allows chips to send and receive information. In this case, the I2C wires are used to set the time and retrieve it. On the Arduino UNO, these pins are wired to the Analog 4 and 5 pins.
BAT | Battery voltage | To monitor the battery voltage, or not connected |
GND | Ground | Ground |
VCC | 5V supply | Power the module and charge the battery |
SDA | I2C data | I2C data for the RTC |
SCL | I2C clock | I2C clock for the RTC |
DS | DS18B20 Temp. Sensor output | One wire inteface |
SQ | Square wave output | Normally not used |
Note: The CR2032 button battery is rechargeable and is trickle charged using Vcc.
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include <Wire.h> #include <RTClib.h> RTC_DS1307 RTC; void setup () { Serial.begin(57600); Wire.begin(); RTC.begin(); // Enable the next line of code ONCE to program the current time into the DS1307 RTC chip: //RTC.adjust(DateTime(__DATE__, __TIME__)); } void loop () { DateTime now = RTC.now(); Serial.print(now.year(), DEC); Serial.print('/'); Serial.print(now.month(), DEC); Serial.print('/'); Serial.print(now.day(), DEC); Serial.print(' '); Serial.print(now.hour(), DEC); Serial.print(':'); Serial.print(now.minute(), DEC); Serial.print(':'); Serial.print(now.second(), DEC); Serial.println(); delay(3000); }
You can use pushbuttons and an I2C connected 2×16 LCD character display to display the time and set the current date/time:
/* :Project:Clock_Set_Date_Time :Author: Tiziano Bianchettin :Date: 13/01/2017 :Revision: 1 :License: Public Domain thanks to: http://arduinoenonsolo.blogspot.it/2012/12/orologio-con-arduino-e-il-ds1307.html http://www.mauroalfieri.it/ http://www.danielealberti.it/ http://www.maffucci.it/ My electronics laboratory professor "Perito Carli" */ //************libraries**************// #include <Wire.h> #include <RTClib.h> #include <LiquidCrystal_I2C.h> //************************************// LiquidCrystal_I2C lcd(0x3F,16,2); // Display I2C 16 x 2 RTC_DS1307 RTC; //************Button*****************// int P1=6; // Button SET MENU' int P2=7; // Button + int P3=8; // Button - //************Variables**************// int hourupg; int minupg; int yearupg; int monthupg; int dayupg; int menu =0; void setup() { lcd.begin(); lcd.backlight(); lcd.clear(); pinMode(P1,INPUT); pinMode(P2,INPUT); pinMode(P3,INPUT); Serial.begin(9600); Wire.begin(); RTC.begin(); if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // Set the date and time at compile time RTC.adjust(DateTime(__DATE__, __TIME__)); } // RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time // The default display shows the date and time int menu=0; } void loop() { // check if you press the SET button and increase the menu index if(digitalRead(P1)) { menu=menu+1; } // in which subroutine should we go? if (menu==0) { DisplayDateTime(); // void DisplayDateTime } if (menu==1) { DisplaySetHour(); } if (menu==2) { DisplaySetMinute(); } if (menu==3) { DisplaySetYear(); } if (menu==4) { DisplaySetMonth(); } if (menu==5) { DisplaySetDay(); } if (menu==6) { StoreAgg(); delay(500); menu=0; } delay(100); } void DisplayDateTime () { // We show the current date and time DateTime now = RTC.now(); lcd.setCursor(0, 1); lcd.print("Hour:"); if (now.hour()<=9) { lcd.print("0"); } lcd.print(now.hour(), DEC); hourupg=now.hour(); lcd.print(":"); if (now.minute()<=9) { lcd.print("0"); } lcd.print(now.minute(), DEC); minupg=now.minute(); lcd.print(":"); if (now.second()<=9) { lcd.print("0"); } lcd.print(now.second(), DEC); lcd.setCursor(0, 0); lcd.print("Date: "); if (now.day()<=9) { lcd.print("0"); } lcd.print(now.day(), DEC); dayupg=now.day(); lcd.print("/"); if (now.month()<=9) { lcd.print("0"); } lcd.print(now.month(), DEC); monthupg=now.month(); lcd.print("/"); lcd.print(now.year(), DEC); yearupg=now.year(); } void DisplaySetHour() { // time setting lcd.clear(); DateTime now = RTC.now(); if(digitalRead(P2)==HIGH) { if(hourupg==23) { hourupg=0; } else { hourupg=hourupg+1; } } if(digitalRead(P3)==HIGH) { if(hourupg==0) { hourupg=23; } else { hourupg=hourupg-1; } } lcd.setCursor(0,0); lcd.print("Set time:"); lcd.setCursor(0,1); lcd.print(hourupg,DEC); delay(200); } void DisplaySetMinute() { // Setting the minutes lcd.clear(); if(digitalRead(P2)==HIGH) { if (minupg==59) { minupg=0; } else { minupg=minupg+1; } } if(digitalRead(P3)==HIGH) { if (minupg==0) { minupg=59; } else { minupg=minupg-1; } } lcd.setCursor(0,0); lcd.print("Set Minutes:"); lcd.setCursor(0,1); lcd.print(minupg,DEC); delay(200); } void DisplaySetYear() { // setting the year lcd.clear(); if(digitalRead(P2)==HIGH) { yearupg=yearupg+1; } if(digitalRead(P3)==HIGH) { yearupg=yearupg-1; } lcd.setCursor(0,0); lcd.print("Set Year:"); lcd.setCursor(0,1); lcd.print(yearupg,DEC); delay(200); } void DisplaySetMonth() { // Setting the month lcd.clear(); if(digitalRead(P2)==HIGH) { if (monthupg==12) { monthupg=1; } else { monthupg=monthupg+1; } } if(digitalRead(P3)==HIGH) { if (monthupg==1) { monthupg=12; } else { monthupg=monthupg-1; } } lcd.setCursor(0,0); lcd.print("Set Month:"); lcd.setCursor(0,1); lcd.print(monthupg,DEC); delay(200); } void DisplaySetDay() { // Setting the day lcd.clear(); if(digitalRead(P2)==HIGH) { if (dayupg==31) { dayupg=1; } else { dayupg=dayupg+1; } } if(digitalRead(P3)==HIGH) { if (dayupg==1) { dayupg=31; } else { dayupg=dayupg-1; } } lcd.setCursor(0,0); lcd.print("Set Day:"); lcd.setCursor(0,1); lcd.print(dayupg,DEC); delay(200); } void StoreAgg() { // Variable saving lcd.clear(); lcd.setCursor(0,0); lcd.print("SAVING IN"); lcd.setCursor(0,1); lcd.print("PROGRESS"); RTC.adjust(DateTime(yearupg,monthupg,dayupg,hourupg,minupg,0)); delay(200); }