Pantech.AI

How to Interface Real Time Clock RTC DS1307 interfacing with PIC18F4550

Introduction

A Real-Time Clock (RTC) is a device used for timekeeping and calendar tracking, essential for applications that require logging the time and date of specific events.

RTCs are particularly useful in data logging applications and are widely integrated into devices such as computers, laptops, and mobile phones. They are powered by external batteries, enabling them to maintain accurate time and date records even during power outages.

RTCs have several registers dedicated to tracking the current time and date. To use an RTC, you must first set it with the correct date and time. Once initialized, these registers can be read at any time to retrieve the current time and date.

The DS1307 is a commonly used RTC that operates via the I2C protocol.

For details on implementing I2C communication with the PIC18F4550, refer to the “PIC18F4550 I2C” section in the PIC Inside series. For further information on the DS1307 RTC module, see the “Real-Time Clock RTC DS1307 Module” in the sensors and modules section.

DS1307 RTC Module

Connection Diagram of RTC DS1307 With PIC18F4550

RTC DS1307 Interfacing with PIC18F4550

Programming steps for RTC DS1307

When using an RTC for the first time, the initial step is to set the clock and calendar values. After this, the RTC will continuously update these values automatically.

Step 1: Setting the Clock and Calendar on the RTC DS1307

To set the clock and calendar on the DS1307 RTC, follow these steps:

  1. Identify the RTC Device Address: The DS1307 has a fixed I2C device address of 0xD0 (as specified in the datasheet). This address is used for communication between the microcontroller and the RTC.
  2. Initialize I2C Communication: Set up I2C communication in the PIC18F4550 microcontroller.
  3. Start I2C Communication: Begin I2C communication with the RTC by sending its address (0xD0).
  4. Send Register Address: First, send the register address of the Seconds register (0x00), then transmit the value of seconds you wish to set.
  5. Write Remaining Time and Date Values: As the RTC’s address auto-increments, continue to send the values for minutes, hours, day, date, month, and year in that order. These values will be written to their respective registers in the DS1307.
  6. Stop I2C Communication: Once all the time and date values have been written, end the I2C communication.

After completing this step, the DS1307 will start keeping track of time and updating the clock and calendar automatically.

void RTC_Clock_Write(char sec, char min, char hour, char AM_PM)					/* function for clock */
{
    hour = (hour | AM_PM);     /* whether it is AM or PM */
	I2C_Start(device_id_write);/* start I2C comm. with device slave address*/	
	I2C_Write(0);			   /* write 0 location for sec value */
	I2C_Write(sec);			   /* write second value on 00 location */
	I2C_Write(min);			   /* write min value on 01 location */
	I2C_Write(hour);		   /* write hour value on 02 location */
	I2C_Stop();				   /* stop I2C communication */
}

void RTC_Calendar_Write(char day, char date, char month, char year)	/* function for calendar */
{
	I2C_Start(device_id_write);/* start I2C comm. with device slave address */
	I2C_Write(3);			   /* write on 3 location for day value */
	I2C_Write(day);			   /* write day value on 03 location */
	I2C_Write(date);		   /* write date value on 04 location */
	I2C_Write(month);		   /* write month value on 05 location */
	I2C_Write(year);		   /* write year value on 06 location */
	I2C_Stop();
}

Step2: Reading Time and Date value from RTC DS1307

Step 2: Reading Data from the RTC DS1307

To read the time and date data (seconds, minutes, hours, etc.) from the DS1307 RTC, follow these steps:

  1. Start I2C Communication: Begin I2C communication with the RTC by sending the device’s write address (0xD0).
  2. Write Register Address: Send the register address from which you want to start reading data. For example, to read the seconds, write the address 0x00 (the Seconds register).
  3. Repeated Start and Switch to Read Mode: After setting the register address, issue a repeated start condition and switch the device to the read mode by sending the read address (0xD1).
  4. Read Data with Acknowledgment: Start reading data from the RTC. The first byte (seconds) will be received with acknowledgment. Continue reading the following bytes for minutes, hours, day, date, month, and year.
  5. Read Last Byte with Negative Acknowledgment: When you reach the last byte (year), read it with a negative acknowledgment to indicate that this is the final piece of data.
  6. Auto-Incrementing Register Address: As you read the data, the register address will auto-increment with each byte, so there is no need to manually specify the address for each new piece of data.

This method allows you to retrieve the current time and date values from the RTC DS1307.

Program for Reading Date and Time using PIC18F4550

/*
 * PIC18F4550 interfacing with RTC DS1307
 * http://www.electronicwings.com
 */ 


#include <stdio.h>
#include "Configuration_Header_File.h"
#include "16x2_LCD_4bit_File.h"
#include <pic18f4550.h>
#include "I2C_Master_File.h"

#define device_id_write 0xD0
#define device_id_read 0xD1

int sec,min,hour;
int Day,Date,Month,Year;

void RTC_Read_Clock(char read_clock_address)
{
    I2C_Start(device_id_write);
    I2C_Write(read_clock_address);     /* address from where time needs to be read*/
    I2C_Repeated_Start(device_id_read);
    sec = I2C_Read(0);                 /*read data and send ack for continuous reading*/
    min = I2C_Read(0);                 /*read data and send ack for continuous reading*/
    hour= I2C_Read(1);                 /*read data and send nack for indicating stop reading*/
    
}

void RTC_Read_Calendar(char read_calendar_address)
{   
    I2C_Start(device_id_write);
    I2C_Write(read_calendar_address); /* address from where time needs to be read*/
    I2C_Repeated_Start(device_id_read);
    Day = I2C_Read(0);                /*read data and send ack for continuous reading*/
    Date = I2C_Read(0);               /*read data and send ack for continuous reading*/
    Month = I2C_Read(0);              /*read data and send ack for continuous reading*/
    Year = I2C_Read(1);               /*read data and send nack for indicating stop reading*/
    I2C_Stop();
}

void main()
{
    
    char secs[10],mins[10],hours[10];
    char date[10],month[10],year[10];
    char Clock_type = 0x06;
    char AM_PM = 0x05;
    char days[7] = {'S','M','T','W','t','F','s'};
    OSCCON=0x72;                    /*Use internal oscillator and 
                                     *set frequency to 8 MHz*/ 
    I2C_Init();                     /*initialize I2C protocol*/
    LCD_Init();                     /*initialize LCD16x2*/    
    LCD_Clear();
    MSdelay(10);
    while(1)
    { 
        RTC_Read_Clock(0);              /*gives second,minute and hour*/
        I2C_Stop();
        if(hour & (1<<Clock_type)){     /* check clock is 12hr or 24hr */
            
            if(hour & (1<<AM_PM)){      /* check AM or PM */
                LCD_String_xy(1,14,"PM");
            }
            else{
                LCD_String_xy(1,14,"AM");
            }
            
            hour = hour & (0x1f);
            sprintf(secs,"%x ",sec);   /*%x for reading BCD format from RTC DS1307*/
            sprintf(mins,"%x:",min);    
            sprintf(hours,"Tim:%x:",hour);  
            LCD_String_xy(0,0,hours);            
            LCD_String(mins);
            LCD_String(secs);
        }
        else{
            
            hour = hour & (0x3f);
            sprintf(secs,"%x ",sec);   /*%x for reading BCD format from RTC DS1307*/
            sprintf(mins,"%x:",min);    
            sprintf(hours,"Tim:%x:",hour);  
            LCD_String_xy(0,0,hours);            
            LCD_String(mins);
            LCD_String(secs); 
        }
        
        RTC_Read_Calendar(3);        /*gives day, date, month, year*/        
        I2C_Stop();
        sprintf(date,"Cal %x-",Date);
        sprintf(month,"%x-",Month);
        sprintf(year,"%x ",Year);
        LCD_String_xy(2,0,date);
        LCD_String(month);
        LCD_String(year);

    /* find day */
        switch(days[Day])
        {
            case 'S':
                        LCD_String("Sun");
                        break;
            case 'M':
                        LCD_String("Mon");
                        break;                
            case 'T':
                        LCD_String("Tue");
                        break;                
            case 'W':   
                        LCD_String("Wed");
                        break;                
            case 't':
                        LCD_String("Thu");
                        break;
            case 'F':
                        LCD_String("Fri");
                        break;                
            case 's':
                        LCD_String("Sat");
                        break;
            default: 
                        break;
                        
        }
        
    }    
}

Leave a Comment

Your email address will not be published. Required fields are marked *