Summary of DS1307 Based Hand Clock with seven segment display using PIC16F877A
This article details a digital clock project using the PIC16F877A microcontroller and DS1307 real-time clock IC. The system displays time, date, month, and year on 4-digit common anode seven-segment displays. It features four buttons to navigate between time settings, date adjustments, and year views, with support for AM/PM conversion. The code handles I2C communication for data retrieval and storage, utilizing interrupts for multiplexing the display segments efficiently.
Parts used in the DS1307 Based Hand Clock:
- PIC16F877A Microcontroller
- DS1307 Real-Time Clock IC
- 4-Digit Seven Segment Display (Common Anode)
- Four Push Buttons
- I2C Communication Module
- AM/PM Indicator LEDs (PORT E pins)
DS1307 Based Hand Clock with seven segment display using PIC16F877A (Code)
//------Project by { ZAKI }--"facebook.com / Zaki Semel"----------//
//------Project { Clock Hand }---For Pic16f877a & 7 Segment 4, Anode-------//
//*****************************************************************************//
char second, minute, hour, day, date, month, year;
char second_d1, second_d2, minute_d1, minute_d2, hour_d1, hour_d2;
char date_d1, date_d2, month_d1, month_d2, year_d1, year_d2, year_d3, year_d4;
char convert, hold;
char seg[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; //Segment 0-9
//----Buttons-----------------------------//
#define Button1 PORTC.f0 //Show Date & Second, Date & Second ++
#define Button2 PORTC.f1 //Change Time & Date
#define Button3 PORTC.f2 //Show Time & No Save Time & Date
#define Button4 PORTC.f5 //Show Year
//----In Interrupt-----------------------------------//
#define GotoTime 0
#define GotoSecond 1
#define GotoDate 2
#define GotoYear 3
#define GotoClear 4
//----Hour 12 (AM-PM)---------------------//
#define AM PORTE.f0 //Hour12(AM)
#define PM PORTE.f1 //Hour12(PM)
//-----Display Time------------------//
void DisplayTime()
{
char x;
second_d1 = seg[second /10];
second_d2 = seg[second %10];
minute_d1 = seg[minute /10];
minute_d2 = seg[minute %10];
hour_d1 = seg[hour /10];
hour_d2 = seg[hour %10];
date_d1 = seg[date /10];
date_d2 = seg[date %10];
month_d1 = seg[month /10];
month_d2 = seg[month %10];
year_d1 = seg[year /10];
year_d2 = seg[year %10];
year_d3 = seg[year /10];
year_d4 = seg[year %10];
}
//----I2C Read for IC DS1307----------------//
void ReadI2C()
{
i2c1_start();
i2c1_wr(0xd0);
i2c1_wr(0);
i2c1_repeated_start();
i2c1_wr(0xd1);
second = i2c1_rd(1);
minute = i2c1_rd(1);
hour = i2c1_rd(1);
day = i2c1_rd(1);
date = i2c1_rd(1);
month = i2c1_rd(1);
year = i2c1_rd(0);
i2c1_stop();
}
//----Transform Time for IC DS1307------------------//
void TransformTime()
{
second =((second & 0xf0)>>4)* 10 +(second & 0x0f);
minute =((minute & 0xf0)>>4)* 10 +(minute & 0x0f);
hour =((hour & 0xf0)>>4)* 10 +(hour & 0x0f);
day =((day & 0xf0)>>4)* 10 +(day & 0x0f);
date =((date & 0xf0)>>4)* 10 +(date & 0x0f);
month =((month & 0xf0)>>4)* 10 +(month & 0x0f);
year =((year & 0xf0)>>4)* 10 +(year & 0x0f);
}
//----Start Time for IC DS1307------------------------------//
void StartTime(char second, char minute, char hour, char day, char date, char month, char year)
{
i2c1_start();
i2c1_wr(0xd0);
i2c1_wr(0);
i2c1_wr(second);
i2c1_wr(minute);
i2c1_wr(hour);
i2c1_wr(day);
i2c1_wr(date);
i2c1_wr(month);
i2c1_wr(year);
i2c1_wr(0x10); // 1Hz
i2c1_stop();
}
//----Save Time & Date for Change------------------//
void SaveTime()
{
i2c1_start();
i2c1_wr(0xd0);
i2c1_wr(0);
i2c1_wr(dec2bcd(second));
i2c1_wr(dec2bcd(minute));
i2c1_wr(dec2bcd(hour));
i2c1_wr(dec2bcd(day));
i2c1_wr(dec2bcd(date));
i2c1_wr(dec2bcd(month));
i2c1_wr(dec2bcd(year));
i2c1_stop();
}
//----Hour 12 (AM-PM)----------------------//
void Hour12_AM_PM()
{
if (hour < 0x12) { if (hour == 0) { hour = 0x12; AM = 1; } else AM = 1; } else if (hour == 0x12) { PM = 1; } else if (hour > 0x12 && hour < 0x20) { hour = hour - 0x12; PM = 1; } else if (hour == 0x20) { hour = 0x08; PM = 1; } else if (hour == 0x21) { hour = 0x09; PM = 1; } else if (hour == 0x22) { hour = 0x10; PM = 1; } else if (hour == 0x23) { hour = 0x11; PM = 1; } } //----Show Date & Second for Button1-------------------// void DateSecond(char set) { switch(set) { case 0: convert = GotoDate; break; //Goto Date in Interrupt case 1: convert = GotoSecond; break; //Goto Second in Interrupt } } //----Show Date & Second for Button1-------------------// void MenuDateSecond() { char set; set = 0; while(1) { ReadI2C(); Hour12_AM_PM(); TransformTime(); DisplayTime(); DateSecond(set); if (Button1 == 0){hold = 1;} if (Button1 == 1 && hold == 1) { hold = 0; set++; if (set > 1)
{
delay_ms(2);
convert = GotoTime; //Goto Time in Interrupt
break;
}
}
//-----------------------------//
if (set >= 1)
{
if (Button2 == 1) //---Second = 0
{
second = 0;
SaveTime(); //---Save Time
}
}
}
}
//*****************************************//
//----Change Time & Date for Button2----------------------//
void SetChangeTime(char set)
{
switch(set)
{
case 0:
hour_d1 = hour_d2 = 0xff; delay_us(500);
break;
case 1:
minute_d1 = minute_d2 = 0xff; delay_us(500);
break;
case 2:
date_d1 = date_d2 = 0xff; delay_us(500);
break;
case 3:
month_d1 = month_d2 = 0xff; delay_us(500);
break;
case 4:
year_d3 = year_d4 = 0xff; delay_us(500);
break;
}
}
//----Change Time & Date for Button2----------------------//
void ChangeTime(char set, char change)
{
switch(set)
{
case 0:
if (change == 0)
{
hour ++;
if (hour > 23) hour = 0;
}
break;
case 1:
if (change == 0)
{
minute ++;
if (minute > 59) minute = 0;
}
break;
case 2:
if (change == 0)
{
date ++;
if (date > 31) date = 1;
}
break;
case 3:
if (change == 0)
{
month ++;
if (month > 12) month = 1;
}
break;
case 4:
if (change == 0)
{
year ++;
if (year > 99) year = 0;
}
break;
}
}
//----Change Time & Date for Button2----------------------//
void MenuChangeTime()
{
char set;
set = 0;
while(1)
{
DisplayTime();
SetChangeTime(set);
if (Button2 == 0){hold = 1;}
if (Button2 == 1 && hold == 1)
{
hold = 0;
set ++;
if (set > 4) //Save Time
{
convert = GotoTime; //Goto Time in Interrupt
second = 0;
SaveTime();
break;
}
if (set > 1) convert = GotoDate; //Goto Interrupt
if (set > 3) convert = GotoYear; //Goto Interrupt
}
if (Button1 == 1) //Time & Date ++
{
SetChangeTime(set);
ChangeTime(set, 0); //Time & Date ++
}
if (Button3 == 1) //No Save, Goto Normal Time
{
convert = GotoTime; //Goto Time in Interrupt
break;
}
}
}
//----Clear Display-------------------------//
void ClearDisplay()
{
while(1)
{
convert = GotoClear; //Goto Clear in Interrupt
ReadI2C();
TransformTime();
portE = 0;
if (Button1 == 0 && Button2 == 0){hold = 1;}
if (Button1 == 1 && hold == 1) //Show Date & Second
{
hold = 0;
convert = GotoDate; //Goto Interrupt
MenuDateSecond(); //Goto MenuDateSecond();
break;
}
if (Button2 == 1 && hold == 1)
{
hold = 0;
convert = GotoTime; //Goto Time in Interrupt
MenuChangeTime();
break;
}
if (Button3 == 1)
{
convert = GotoTime; //Goto Time in Interrupt
break;
}
if (Button4 == 1)
{
convert = GotoYear; //Goto Year in Interrupt
break;
}
}
}
//----Interrupt-------------------------------//
void Interrupt()
{
if (convert == GotoSecond) //Show Second
{
portd = 1; portb = 0xff; delay_ms(1);
portd = 2; portb = 0xff; delay_ms(1);
portd = 4; portb = second_d1; delay_ms(1);
portd = 8; portb = second_d2; delay_ms(1);
}
if (convert == GotoTime) //Show Time(Hour & Minute)
{
portd = 1; portb = hour_d1; delay_ms(1);
portd = 2; portb = hour_d2 + 128; delay_ms(1);
portd = 4; portb = minute_d1; delay_ms(1);
portd = 8; portb = minute_d2; delay_ms(1);
}
if (convert == GotoDate) //Show Date(Date & Month)
{
portd = 1; portb = date_d1; delay_ms(1);
portd = 2; portb = date_d2 + 128; delay_ms(1);
portd = 4; portb = month_d1; delay_ms(1);
portd = 8; portb = month_d2; delay_ms(1);
}
if (convert == GotoYear) //Show Year
{
portd = 1; portb = 0xa4; delay_ms(1);
portd = 2; portb = 0xc0; delay_ms(1);
portd = 4; portb = year_d3; delay_ms(1);
portd = 8; portb = year_d4; delay_ms(1);
}
if (convert == GotoClear) //Clear Display
{
portd = 1; portb = 0xff; delay_ms(1);
portd = 2; portb = 0xff; delay_ms(1);
portd = 4; portb = 0xff; delay_ms(1);
portd = 8; portb = 0xff; delay_ms(1);
}
intcon = 0b10100000;
}
//*********** Main *******************************************//
void main()
{
trisB = 0; trisC = 0xff; trisD = 0; trisE = 0;
option_reg = 0b10000000; intcon = 0b10100000; //Registers
i2c1_init(100000); //Init I2C(IC DS1307)
StartTime(0x00, 0x00, 0x00, 0, 0x21, 0x03, 0x17); //Start Time
while(1)
{
ReadI2C();
Hour12_AM_PM();
TransformTime();
DisplayTime();
delay_ms(10);
ClearDisplay(); //Goto ClearDisplay()
}
}
DS1307 Based Hand Clock with seven segment display using PIC16F877A (Schematic Diagram)

- How is the time data retrieved from the clock chip?
The ReadI2C function initiates an I2C start condition, writes the register address, and reads sequential bytes for seconds, minutes, hours, day, date, month, and year. - What type of seven segment display is required?
The project requires a 4-digit common anode seven segment display as specified in the project comments. - Can the user adjust the date and time manually?
Yes, pressing Button2 enters the change mode where Button1 increments values for hour, minute, date, month, or year. - How does the system handle AM and PM indicators?
The Hour12_AM_PM function converts 24-hour format to 12-hour format and sets PORT E bits to indicate AM or PM status. - Which ports are configured for the input buttons?
Button1, Button2, Button3, and Button4 are defined as inputs connected to PORTC bits f0, f1, f2, and f5 respectively. - What happens when the save button is pressed during setting changes?
After incrementing all fields up to the year, the system calls SaveTime to write decimal-to-BCD converted values back to the DS1307 via I2C. - How is the display refreshed continuously?
The main loop calls ClearDisplay which triggers an interrupt routine that multiplexes the segments by rapidly switching port D lines and loading data to port B. - What is the role of the dec2bcd function in the code?
The dec2bcd function converts decimal values read from the user interface into Binary Coded Decimal format before saving them to the DS1307 chip.