Interfacing of RTC DS1307 with PIC18F4550

Interfacing RTC DS1307 with PIC18F4550

Real time clocks(RTC) are chips which store and keep track of time. Because of it’s precise functioning, RTCs are are incorporated in personal computers, consumer electronic and embedded devices.This chapter particularly deals with details of interfacing RTC DS1307 with PIC18F4550.

RTC

A real time clock has registers which store the system description or setup values including the current time values stored by the real time clock. User can write into these registers for configuring the RTC. They are widely used in embedded systems which uses controllers without a built-in RTC module. It can count leap years and knows how many days are there in a month. RTCs can be usually configured in both 12 hr and 24 hr mode. The day register is incremented at midnight.

Keeping track of time can be done by other methods including timers, but RTC has many advantages. RTC is independent of main system, which frees up the resources. This will be very advantageous in embedded systems with very limited resources. RTCs operate from separate power supplies, usually from batteries, so it operates even in a power failure situations. They are made to be low power devices and a single battery will be enough for operation of years. They are accurate as compared to manual methods including timers. Most RTCs have external oscillators which make them accurate.

The processor communicates with an externally interfaced RTC through serial communication protocols. DS1307 RTC is interfaced with the microcontroller using I2C interface. I2C is a serial communication protocol developed by Philips and is commonly used in embedded systems because of its features which make it simple.

Since DS1307 communicates with the microcontroller using I2C protocol it is necessary to understand the protocol in brief.

I2C

I2C is a two-wire synchronous serial communication protocol. SDA line is used for transferring data and SCK is used for transferring clock information. Every device connected to an I2C bus has a unique address. I2C communication protocol involves communication between a slave and a master. The device which initiates the communication and which provides the clock is referred to as a master device. The devices which receive the clock signal and receive/transmit data according to the clock signal is termed as a slave device. Each device on the bus is accessed using its slave address.

Let’s have a look on the communication process in an I2C bus. First the MCU will issue a START condition. The devices connected to the bus will listen to the START condition and will stay ready to begin the communication process. Then MCU will send the address of the device with which it needs to communicate. Master indicates the action to be performed with the device whether to read or write along with the address. All devices connected to the bus will receive the address and will compare it with its own address. If the addresses match with each other, the device will send back an ACKNOWLEDGEMENT signal to the master device. If they don’t match they will simply wait for the bus to be released with a STOP condition.

Once the MCU sends the address and corresponding device acknowledges, the MCU can start transmitting or receiving data. When the data transmission or reception is complete, the MCU will stop communicating by sending a STOP condition. STOP condition indicates that the bus is released and it can be used by any other master (if any) connected to the I2C bus.

After a master generate a start condition I2C bus will solely belong to it. The bus will be freed only if the master generate a STOP condition. Any other master connected to the bus can access the bus after a STOP is identified on the bus. If the master device which uses the bus needs to communicate with a different slave it should generate a RESTART. Instead if it tries to stop current communication and then start again it may lose access to the bus. RESTART is nothing but a start signal without a stop in the bus.

There is detailed tutorial on PIC18F4550 I2C module implementation: I2C Module In PIC18F4550

RTC Interfacing: Firmware

DS1307 has internal registers addressing from 00h to 3Fh. The time keeping registers of RTC are located in the address locations 00h to 07h. The registers from 08h to 3Fh are RAM registers.

rtc-interfacing-firmware

The above table shows the different registers and its addresses. The time and calendar are set or initialised by writing to the appropriate registers.The contents of the calendar and time registers are in the BCD format, so all the data should be written in BCD format. The seven bit slave address for the DS1307 RTC is 1101000. Therefore 0xD0 is transmitted to access the RTC in write mode and 0xD1 is transmitted to access the slave in read mode. The least significant bit will describe the operation to be performed whether to write into the RTC or to read from RTC.

Procedure for writing time and date

  • Initiate a START condition.
  • Transmit the RTC address 0xD0 with LSB 0 for write mode.
  • Transmit the address of the register to write(for example 0x00 for write to second register). This transfer sets the register pointer inside the DS1307 RTC
  • Transmit the seconds value in BCD format. Following the procedure of writing to the seconds register, the pointer in the RTC will automatically increment. The next data will be written in the 0x01 location which is minute register.
  • Transmit until year register is written.
  • Terminate the communication with a STOP condition.
ds1307-write-sequence
DS1307 write sequence

Procedure for reading the time and date

  • Initiate a START condition
  • Transmit RTC address with LSB 1 (0xD1) to access the RTC in read mode.
  • Now RTC will transmit data from its registers. It should be taken care that it will output data in the register whose address is currently stored in the pointer. If user needs to read a particular register, first the RTC should be accessed in write mode and the desired register address should be written to pointer. Now again RTC should be addressed in read mode after a RESTART or a STOP followed by a START.
  • Each receiving byte should be acknowledged by the master to receive the next byte.
  • After receiving the last byte master should send not-acknowledge(NACK) to the RTC.
  • Terminate communication with a STOP condition in the bus.
ds1307-read-sequence
DS1307 read sequence

Below is an example function for writing time values into DS1307 registers. All the time values should be in BCD format.

/* seconds,minutes,hour,day,date,month,year variables will hold the 
   time and date values in BCD format */ 

void RTC_write_time(char seconds,char minutes,char hour,char day,char date,char month, char year)
{
    I2C_Start();          /*start condition */
    
    I2C_Write(0xD0);     /* slave address with write mode */
    I2C_Write(0x00);     /* address of seconds register written to the pointer */ 
    
    I2C_Write(seconds);  /*time register values */
    I2C_Write(minutes);
    I2C_Write(hour);
    
    I2C_Write(day);      /*date registers */
    I2C_Write(date);
    I2C_Write(month);
    I2C_Write(year);
    
    I2C_Stop();          /*i2c stop condition */
}

/* convert the decimal values to BCD using below function */
char Dec2BCD (char val)
{
    char res;
    res = (val/10) << 4;
    res = res | (val % 10);
    return res;
}

Reading the current date and time from DS1307 registers,

void RTC_read_time()
{
    I2C_Start();          /*start condition */
    
    I2C_Write(0xD0);     /* slave address with write mode */
    I2C_Write(0x00);     /* address of seconds register written to the pointer */
    
    I2C_Restart();

    I2C_Write(0xD1);     /* slave address with read mode */
    
    seconds = I2C_Read(1);  /* Read the slave with ACK */
    minutes= I2C_Read(1);
    hour = I2C_Read(1);
    day = I2C_Read(1);
    date = I2C_Read(1);
    month = I2C_Read(1);
    year = I2C_Read(0);     /* Read the slave with not-ACK */
    
   /*Two things should be taken care of when reading the time
   the received values will be in **BCD format** and  after reading 
   the year register, a not-acknowledgement should be sent instead 
   of an acknowledgement */
   
    I2C_Stop();          /*i2c stop condition */
}

All the time register values are in binary code decimal (BCD) format, so you need to convert them into decimal/hex to start processing. Below is a sample BCD to decimal function.

/* Convert BCD to decimal */
void BCDtoDecimal (char val)
{
    char res;
    res = (val & 0x0F) + ((val & 0xF0)>>4)*10;
    return res;
}

Circuit Diagram – Interfacing RTC DS1307 with PIC18F4550

I2C protocol allows multiple slave devices and master devices communicate with each other and it is used for short distance communications. It uses two signal wires to communicate with each other, SDA or data line and SCL or clock line.

Interfacing RTC DS1307 with PIC18F4550
Interfacing RTC DS1307 with PIC18F4550

SDA and SCL lines are connected to the corresponding pins in the microcontroller. I2C bus drivers are open drain so that they can’t drive corresponding signals high. This avoids bus contention when more than two devices communicate with each other and each device is trying different logic level (e.g: one device pulling high and other pulling low), thus avoiding chance to damage drivers. The signal lines have pull-up resistors to restore the signal state high when no device is using the line.

DS1307 uses a 32.768 kHz quartz crystal as the oscillator. The pins X1 and X2 are used as the oscillator pins. There is a VBAT pin for connecting the battery. The battery will provide backup in the absence of power. A CR2032 battery will provide around 7 years power backup.