Digital Clock using PIC Microcontroller Interrupt Circuit diagram

Figure 1: Digital Clock using Timer 1

A Real Time clock (Digital Clock) can be made easily by using Timer 1 of a PIC Microcontroller.
The Timer1 module exists in most of the series of PIC, this module can be used to easily implement a real-time clock. Instead of an external real-time clock device like a DS1307, an inexpensive 32.768 kHz watch crystal and two 33 pF capacitors are used to complete the circuit.
In this application, Timer1 is clocked by an external crystal (32.768 kHz) connected across RC0 (T1OSO) and 
RC1 (T1OSI).

Timer TMR1 module is a 16-bit timer/counter, which means that it consists of two registers (TMR1L and TMR1H). 
It can count up 65.535 pulses in a single cycle before the counting starts from zero.
These registers can be read or written to at any moment. 
In case an overflow occurs, an interrupt is generated if enabled.

Circuit Diagram

As shown on the circuit diagram above on figure 1, an external 32.768 kHz watch crystal and two 33 pF capacitors are connected to Timer1 on PORTC, RC0 (T1OSO) and RC1 (T1OSI). 
The PIC uses an internal oscillator and the MCLR is disabled. If an external oscillator is needed, it can be connected to pins 9 (OSC1) and 10 (OSC2) and if the MCLR is needed to reset the PIC, it can be connected to positive supply via a 10K resisitor.
Time and Date are read from a Personal Computer (PC) via a serial connection. A MAX232 IC is used to convert the voltage logics from the PIC to RS232 standard and vice versa. To learn more on serial connection, please refer to the article: PIC Microcontroller Communication: The RS232. 
When power is switched on, a message will be sent to the PC to set the date and the time. 

A 16 x 2 lines LCD display is connected to PORT B. refer to the Interfacing LCD Display with PIC microcontroller article to learn more. 
LED D1 flashes each second as the clock is running.

MPLAB XC8 Code

MPLAB XC8 compiler is used to write the code. 
The PIC18 Peripheral Library found inside the installation folder of CX8 compiler contains a full description of Real-Time Clock and Calendar (RTCC) function simulated using Timer1. 

Important:

If you are using XC8 v1.35, the Peripheral Libraries which include the LCD and other peripherals like ADC, SPI, I2C libraries are no longer included in the installation file as with previous versions. You can either write your own LCD library and use MPLAB code configurator to configure the other peripherals or the easiest is to download the Peripheral Libraries as a separate download and install them,. You can download them at microchip website under the MPLAB XC Compilers downloads tab. They are now called PIC18 Legacy Peripheral Libraries.

Download: PIC18 Legacy Peripheral Libraries 

You can access the PIC18F Peripheral Library Help Document found inside your compiler installation directory in: ..Program Files (x86)Microchipxc8v1.34docsMPLAB_XC8_Peripheral_Libraries.pdf (assuming you installed your compiler in the Program Files (x86) directory. v1.34 is the version of your compiler, it might be different if you are using a different compiler).
Search for the PIC you are going to use, click on: “CLICK HERE for the Peripheral Library Support Details for this Device”.

Open_RTCC(): Configures Timer1 to work as clock source for RTCC, enables Timer1 interrupts, and writes a value into TMR1H & TMR1L registers to get 1second interrupt.
update_RTCC(): checks for the TMR1 interrupt flag, refreshes TMR1H if interrupt has occurred and returns the state of TMR1IF 
Close_RTCC():

//
/*
 * File:   RTC_Interrupt.c
 * Author: Student Companion SA: www.studentcompanion.co.za
 * Real Time Clock Using Timer 0
 */
 
#include "RTC_Interrupt.h"
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
 
#define NUM(x,y) (10*(x - '0') + y - '0')
#define MSD(x) ((x / 10 + '0'))
#define LSD(x) ((x % 10) + '0')
 
void XLCD_init(void);             //Initialize LCD
void Init_USART(void);            //Initialize USART
void ReadClock(void);             //Initialize Read Clock
void DelayFor18TCY( void );
void DelayPORXLCD (void);
void DelayXLCD (void);
void User_Timer(void);
 
unsigned char Time[ ] = "12:00:00";  //Initialize Time to 12H00
unsigned char Date[ ] = "01/01/03";  //Initialize Date 1st January 2013
unsigned char Days[ ]={0,31,28,31,30,31,30,31,31,30,31,30,31};
unsigned char day,month,year,hour,minute,second,msec;
 
void main(void)
{
   OSCCON=0x76;          //Configure internal oscillator
   TRISAbits.TRISA0 = 1;  // RA0 is input
   XLCD_init();
 
   putrsXLCD("  Set Time and ");
   SetDDRamAddr(0x40);             //Second line on LCD
   putrsXLCD("Date with PC...");
   
   ReadClock();               //Read date and time from PC
 
   WriteCmdXLCD(0x01); //Clear Screen
   putrsXLCD("Time: ");
   SetDDRamAddr(0x40);             //Second line on LCD
   putrsXLCD("Date: ");
 
   Open_RTCC();  // Configures Timer1 to work as clock source for RTCC and enables Timer1 interrupts.
 
 //Look for leap year and adjust for February
   int result;
   result = 10*(Date[6] - '0') + Date[7] - '0';
   result = result % 4;
   if(result == 0)
    Days[2] = 29;
   else
    Days[2] = 28;
 
      do{
        //Display Date and Time
      SetDDRamAddr(0x07);
      putrsXLCD(Time);            // Display Time
      SetDDRamAddr(0x47);         //Move LCD cursor on the second line
      putrsXLCD(Date);            // Display Date
   
   while(update_RTCC()) ;        //wait for timer interruption after one milli second completion
        User_Timer();            //Update Timer count
                  
}while(1);
        Close_RTCC();              //*** Close SW_RTCC***
 
}
// This function updates the clock fields.
 
void User_Timer(void)
{
    
    day = NUM(Date[0], Date[1]);
    month=NUM(Date[3], Date[4]);
    year = NUM(Date[6], Date[7]);
    hour = NUM(Time[0], Time[1]);
    minute = NUM(Time[3],Time[4]);
    second = NUM(Time[6], Time[7]);
      msec++;
    if(msec>=100)
    {
      second++;  msec=0;
      LATCbits.LATC3= ~LATCbits.LATC3;     //Flash LED every second
       if(second==60)
        {
             minute++; second=0;
           if(minute==60)
           {
              hour++; minute=0;
             if(hour==24)
             {
               day++; hour=0;
               if (day == Days[month]+1)
               {
                   month++; day=1;
                   if (month==13)
                   {
                       year++;
                       month=1;
                   }
               }
              }
             }
            }
    }
Time[6] = MSD(second);
Time[7] = LSD(second);
Time[3] = MSD(minute);
Time[4] = LSD(minute);
Time[0]  = MSD(hour);
Time[1] = LSD(hour);
Date[6]  = MSD(year);
Date[7]  = LSD(year);
Date[3]  = MSD(month);
Date[4]  = LSD(month);
Date[0]  = MSD(day);
Date[1]  = LSD(day);  
}
 
// This function is used to read the real-time date and time from the PC
// keyboard and then load, store, and update the date and time in software
 
void ReadClock(void)
{
char set, setLen;
Init_USART();
 
// Read the date and time from the keyboard until the Enter key is pressed
while(BusyUSART());
putrsUSART("Please Enter Date in this format (01/01/03): ");
 
set = 0;
setLen = 0;
while(set != 0x0D)
{
while(!DataRdyUSART());
set = getcUSART( );
putcUSART(set);
Date[setLen] = set;
setLen++;
}
// Terminate the Filename with a NULL character
setLen--;
Date[setLen] = '';
//
// send a message
//
putrsUSART("nrDate set. Set the time now in this format (12:00:00): ");
 
set = 0;
setLen = 0;
while(set != 0x0D)
{
while(!DataRdyUSART());
set = getcUSART( );
putcUSART(set);
Time[setLen] = set;
setLen++;
}
// Terminate the Filename with a NULL character
setLen--;
Time[setLen] = '';
//
// send a message
//
putrsUSART("nrTime set. Thank you. nr");
}
void Init_USART(void )       // This function initializes the USART
                             //baud rate to 9600,high speed, asynchronous mode
                             //and 8 data bits.
{
OpenUSART(USART_TX_INT_OFF &
         USART_RX_INT_OFF &
         USART_ASYNCH_MODE &
         USART_EIGHT_BIT &
         USART_CONT_RX &
         USART_BRGH_HIGH,
         52);
}
 
void XLCD_init(void){                //Initialize LCD display
    OpenXLCD(FOUR_BIT&LINES_5X7);
    while(BusyXLCD());
    WriteCmdXLCD(0x06); // move cursor right, don?t shift display
    WriteCmdXLCD(0x0C); //turn display on without cursor
    putrsXLCD("Digital Clock");
    SetDDRamAddr(0x44);
    putrsXLCD("Starting...");
     for(int c=0;c<=20;c++)__delay_ms(50);
    WriteCmdXLCD(0x01); //Clear Screen
    WriteCmdXLCD(0x02); //Go Home
}
void DelayFor18TCY( void ){
Delay10TCYx(20);  //18 cycles delay
}
//*****************************************
void DelayPORXLCD (void){
Delay1KTCYx(15); // Delay of 15ms
return;
}//End DelayPORXLCD
//*****************************************
void DelayXLCD (void){
Delay1KTCYx(5); // Delay of 5ms
return;
}

You can download the full project files (MPLAB XC8 source code and Proteus Schematic design) below here. All the files are zipped, you will need to unzip them (Download a free version of the Winzip utility to unzip files). 

Download RTC_Interrupt C Main

Download RTC_Interrupt H File

Download RTC_Interrupt Hex

Download RTC_Interrupt Proteus