How To Make A Digital Clock Using Arduino
How To Make A Digital Clock Using Arduino
Arduino
Implementation of digital clock using Arduino, MAX7219 dot matrix display, DS1302 RTC real time
clock, DHT11 humidity and temperature sensor and alarm active buzzer
Digital_Clock_Code_Files
In this article we will learn how to make a digital clock using Arduino nano with below features:
Prerequisites:
Implementation
We will design our circuit based on below diagram. Momentary switches use 220ohm resistors and DHT sensor
uses 10K ohm resistor.
Two momentary switches are "back" and "select". On press back clock can display day, temperature, humidity
etc. Select button works as menu which supports momentary press and long press. Momentary press is used to
display menu items and long press is used to get into menu item also to save and exit.
If you want to change time, click on select button(button-2 in video) keep clicking until you see option "Time".
Once time is displayed press and hold same button, you will be able to get into time setting mode. Click
back(Button-1 in video) to change between hours and minutes, press select button to change time and again log
press to save and exit.
Full video of making this clock:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "Font_Data.h"
#include <virtuabotixRTC.h>
#include "DHT.h"
#include <EEPROM.h>
//Display
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define DISPLAY_CLK_PIN 13
#define DISPLAY_DATA_PIN 11
#define DISPLAY_CS_PIN 10
//RTC
#define RTC_CLK_PIN 2
#define RTC_DATA_PIN 3
#define RTC_RST_PIN 4
//DHT
#define DHT_PIN 6
#define DHTTYPE DHT11
//OTHER PINS
#define BTN_BACK_PIN 8
#define BTN_SELECT_PIN 7
#define ALARM_PIN 5
char Buffer[7];
int SELECT = 0;
int SUBSELECT = 0;
int BACK = 0;
int OPTION = 0;
int RING = 0;
int ALARMHOUR = 6;
int ALARMMINUTE = 30;
int ALARMON = 0;
int ALARMOFFONBUTTONPRESS = 0;
int ROMALARMHOURADD = 0;
int ROMALARMMINUTEADD = 2;
int ROMALARMONADD = 4;
void setup(void)
{
P.begin();
dht.begin();
Serial.begin(9600);
P.setFont(newFont);
P.setIntensity(1);
pinMode(ALARM_PIN, OUTPUT);
pinMode(BTN_BACK_PIN, INPUT);
pinMode(BTN_SELECT_PIN, INPUT);
ALARMHOUR=EEPROM.read(ROMALARMHOURADD);
ALARMMINUTE=EEPROM.read(ROMALARMMINUTEADD);
ALARMON=EEPROM.read(ROMALARMONADD);
if(ALARMHOUR > 23) ALARMHOUR = 6;
if(ALARMMINUTE > 59) ALARMHOUR = 30;
if(ALARMON > 1) ALARMON = 0;
}
void loop(void)
{
int alarmMinDiff = (myRTC.hours*60 + myRTC.minutes) - (ALARMHOUR*60 + ALARMMINUTE);
//Ring if time is alarm time, alarm is on, user did not press any button and user is not inside menu
if(alarmMinDiff == 0 && ALARMON == 1 && ALARMOFFONBUTTONPRESS == 0 && SELECT == 0)
{
ringAlarm();
}
else
{
digitalWrite(ALARM_PIN, LOW);
}
if(alarmMinDiff != 0)
{
ALARMOFFONBUTTONPRESS = 0;
}
int longPress = 0;
if(digitalRead(BTN_BACK_PIN)==HIGH)
{
if(tryStopAlarm(alarmMinDiff) == 0)
clickedBack();
}
while(digitalRead(BTN_SELECT_PIN)==HIGH)
{
longPress += 100;
delay(100);
if(longPress > 1500 || digitalRead(BTN_SELECT_PIN)==LOW)
break;
continue;
}
if(longPress > 0)
{
if(tryStopAlarm(alarmMinDiff) == 0)
{
if(SELECT > 0 && longPress > 1500)
{
clickedLongSelect();
}
else if(longPress > 0)
{
clickedSelect();
}
}
}
P.displayAnimate();
while(digitalRead(BTN_BACK_PIN)==HIGH)
delay(100);
while(digitalRead(BTN_SELECT_PIN)==HIGH)
delay(100);
delay(100);
}
void ringAlarm()
{
if(RING == 0)
{
digitalWrite(ALARM_PIN, HIGH);
RING = 1;
}
else
{
digitalWrite(ALARM_PIN, LOW);
RING = 0;
}
}
void clickedSelect()
{
SELECT++;
if(SUBSELECT == 0)
{
switch(SELECT)
{
case 1:
{
P.displayText("Time", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
break;
}
case 2:
{
P.displayText("Date", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
//P.displayText("Set Date", PA_LEFT, 60, 0, PA_SCROLL_LEFT, PA_NO_EFFECT);
break;
}
case 3:
{
P.displayText("Day", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
break;
}
case 4:
{
P.displayText("Alarm", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
break;
}
case 5:
{
P.displayClear();
P.displayText("ON/OFF - Alarm", PA_LEFT, 60, 0, PA_SCROLL_LEFT, PA_NO_EFFECT);
break;
}
default:
{
SELECT = 0;
}
}
}
else
{
switch(SUBSELECT)
{
case 1:
{
if(OPTION == 0) OPTION++; else OPTION=0;
displayOptionTime();
break;
}
case 2:
{
if(OPTION < 2) OPTION++; else OPTION=0;
displayOptionDate();
break;
}
case 3:
{
displayOptionDay();
break;
}
case 4:
{
if(OPTION == 0) OPTION++; else OPTION=0;
displayOptionAlarm();
break;
}
case 5:
{
displayOptionOnOffAlarm();
break;
}
default:
{
SELECT = 0;
}
}
}
}
void clickedLongSelect()
{
if(SELECT > 0 && SUBSELECT > 0)
{
reset();
displayTime();
}
if(SELECT > 0)
{
SUBSELECT = SELECT;
switch(SELECT)
{
case 1:
{
displayOptionTime();
break;
}
case 2:
{
displayOptionDate();
break;
}
case 3:
{
displayOptionDay();
break;
}
case 4:
{
displayOptionAlarm();
break;
}
case 5:
{
displayOptionOnOffAlarm();
break;
}
}
}
}
//---------------------------------Update Date Time--------------------------------------//
void updateTime()
{
if(OPTION == 0)
{
int hours = myRTC.hours < 23 ? myRTC.hours + 1 : 0;
myRTC.setDS1302Time(00, myRTC.minutes, hours, myRTC.dayofweek, myRTC.dayofmonth, myRTC.month,
myRTC.year);
}
else
{
int minutes = myRTC.minutes < 59 ? myRTC.minutes + 1 : 0;
myRTC.setDS1302Time(00, minutes, myRTC.hours, myRTC.dayofweek, myRTC.dayofmonth, myRTC.month,
myRTC.year);
}
myRTC.updateTime();
displayOptionTime();
}
void updateDate()
{
if(OPTION == 0)
{
int dayofmonth = myRTC.dayofmonth < 31 ? myRTC.dayofmonth + 1 : 1;
myRTC.setDS1302Time(00, myRTC.minutes, myRTC.hours, myRTC.dayofweek, dayofmonth, myRTC.month,
myRTC.year);
}
else if(OPTION == 1)
{
int month = myRTC.month < 12 ? myRTC.month + 1 : 1;
myRTC.setDS1302Time(00, myRTC.minutes, myRTC.hours, myRTC.dayofweek, myRTC.dayofmonth, month,
myRTC.year);
}
else if (OPTION == 2)
{
int year = myRTC.year < 2050 ? myRTC.year + 1 : 2020;
myRTC.setDS1302Time(00, myRTC.minutes, myRTC.hours, myRTC.dayofweek, myRTC.dayofmonth,
myRTC.month, year);
}
myRTC.updateTime();
displayOptionDate();
}
void updateDay()
{
int dayofweek = myRTC.dayofweek < 7 ? myRTC.dayofweek + 1 : 1;
myRTC.setDS1302Time(00, myRTC.minutes, myRTC.hours, dayofweek, myRTC.dayofmonth, myRTC.month,
myRTC.year);
myRTC.updateTime();
displayOptionDay();
}
void updateAlarm()
{
if(OPTION == 0)
{
ALARMHOUR = ALARMHOUR < 23 ? ALARMHOUR + 1 : 0;
EEPROM.write(ROMALARMHOURADD, ALARMHOUR);
}
else
{
ALARMMINUTE = ALARMMINUTE < 59 ? ALARMMINUTE + 1 : 0;
EEPROM.write(ROMALARMMINUTEADD, ALARMMINUTE);
}
displayOptionAlarm();
}
void updateOnOffAlarm()
{
if(ALARMON == 0) ALARMON++; else ALARMON = 0;
EEPROM.write(ROMALARMONADD, ALARMON);
displayOptionOnOffAlarm();
}
//---------------------------------Display methods--------------------------------------//
void displayTime()
{
myRTC.updateTime();
int hours = myRTC.hours > 12 ? myRTC.hours - 12 : myRTC.hours == 0 ? 12 : myRTC.hours;
sprintf(Buffer,"%02d : %02d",hours,myRTC.minutes);
P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
void displayTemparature()
{
int tempC = dht.readTemperature();
sprintf(Buffer,"%02d ºC", tempC);
P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
void displayHumidity()
{
int humi = dht.readHumidity();
sprintf(Buffer,"%02d %%", humi);
P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
void displayDay()
{
myRTC.updateTime();
char* dayPtr = getDay(myRTC.dayofweek);
P.displayText(dayPtr, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
void displayDate()
{
myRTC.updateTime();
char* monthPtr = getMonth(myRTC.month);
sprintf(Buffer,"%s %02d", monthPtr, myRTC.dayofmonth);
P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
void displayOptionTime()
{
if(OPTION == 0)
sprintf(Buffer,">%02d:%02d",myRTC.hours,myRTC.minutes);
else
sprintf(Buffer,"%02d:>%02d",myRTC.hours,myRTC.minutes);
void displayOptionDate()
{
if(OPTION == 0)
sprintf(Buffer,"D>%02d",myRTC.dayofmonth);
else if(OPTION == 1)
sprintf(Buffer,"M>%02d",myRTC.month);
else
sprintf(Buffer,"Y>%02d",myRTC.year);
void reset()
{
SELECT = 0;
BACK = 0;
SUBSELECT = 0;
OPTION = 0;
}
Font_Data.h file also to be added to Arduino code:
Like 1 Person
Last modified on 10 October 2020
Nikhil Joshi
Ceo &
Founder at Dotnetlovers
Atricles: 140
Questions: 12
Given Best Solutions: 12 *
Reference:
Music Credits: https://www.bensound.com
Comments:
Weka Man
Hi great clock, just breadboarded it and might make it an actual for my workshop but with a 16x64 matrix. Not much of a coder
and have been trying to make it change back to time after a minute on the other options and scroll through time, date, temp and
humidity as an option. Also would like 24 hour time. Any ideas on how to change my code to suit?
Nikhil Joshi
Thanks Weka, Could not get you question 1 but for changing it to 24hours clock you change where I'm displaying time:
void displayTime()
{
myRTC.updateTime();
int hours = myRTC.hours > 12 ? myRTC.hours - 12 : myRTC.hours == 0 ? 12 : myRTC.hours;
sprintf(Buffer,"%02d : %02d",hours,myRTC.minutes);
P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
void displayTime()
{
myRTC.updateTime();
sprintf(Buffer,"%02d : %02d",myRTC.hours,myRTC.minutes);
P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
}
Weka Man
Thanks. Only had to change the code there. Looks like Ill have to get a nano to shrink the form factor as my pro minis' havent
got enough power to handle the matrix, temp sensor, RTC and buzzer at once