DS1307 is an i2c based serial real time clock (RTC). It is a very low power device with full BCD clock/calendar keep tracks of seconds, minutes, hours, date of month, month, day of month and year with leap year compensation which is valid upto year 2100.

Here are the list of features available in this small RTC chip:

  • 56 byte of NVRAM for data storage (need battery backup)
  • I2C Interface
  • Programmable Square wave output (1Hz, 4kHz, 8kHz, 32kHz)
  • Low power

The time keeping function of DS1307 provides data and time information with automatic adjustment of months with less than 31 days including leap year. The clock can be programmed to operate either in 12-hour or 24-hour format.

RTC and RAM Address Map

DS1307 has total 64 bytes of memory area which is divided into two segments:

  1. RTC Register Area
  2. General Purpose RAM
0x00 Seconds
0x01 Minutes
0x02 Hours
0x03 Day
0x04 Date
0x05 Month
0x06 Year
0x07 Control
0x08
0x3F
RAM
56 x 8

DS1307 Timekeeper Registers

All the registers of DS1307 stores value as BCD, i.e. if clock is at 49 seconds then register 0x00 will show 0x49 as binary coded decimal value of 49. This makes it easy for programmer to read and display number on LCD or serial terminal. So if you want to use register values of RTC then first convert the value from BCD to decimal and then use it.

Image below shows timekeeper register map for DS1307 RTC. Ds1307-timekeeper-regsiter.png

Register 0x07 is control register for square wave output pin. RS0 and RS1 bit selects the output frequency as per table below:

RS0 RS1 SQW Output Frequency
0 0 1 Hz
0 1 4.096 kHz
1 0 8.192 kHz
1 1 32.768 kHz

You can also use SQW/Out pin as GPO pin, when SQW function of DS1307 is not used. Bit 7 controls the output level of the pin. If OUT bit is 1 then OUT pin is high and when 0 OUT pin will be low.

Basic interfacing circuit

DS1307 requires very less number of components to operate. One of the mandatory component is the crystal oscillator of 32.768kHz. The battery backup is optional as you can connect power source to Vbatt pin. But It is good to have battery connected. When running on battery it only consumes 500 nA of current just for the operation of clock and to maintain content of NV RAM. Your can use a coin cell type battery as backup source for DS1307.

Following image shows typical connection diagram for DS1307 RTC.

Ds1307-basic-circuit.png

R1 and R2 are pullups on I2C line which goes to microprocessor pins. Y2 is 32kHz oscillator BT1 is 3V coin cell battery

Pin SQW/OUT is shown unconnected as its not used but you can connect it the way you want. This pin can provide programmable square wave output at 1Hz, 4kHz, 8kHz or 32kHz. This pin can be used where you want a slow frequency input to timer of a microprocessor.

Programming 8051 for DS1307

DS1307 uses I2C Protocol and act as a slave device and I2C Master can read/write register of RTC. To communicate with the slave device, master need the slave address of device connected on bus. DS1307 has fixed slave address which makes it impossible to connect two RTC devices on same bus, don't worry occurrence of such a scenario is close to zero.

Slave Address

7-Bit format: 0b1101000 = 0x68
Slave address for I2C Write: 0b11010000 = 0xD0
Slave address for I2C Read: 0b11010001 = 0xD1

Assembly Code Sample

Follow example is based on the I2C Implementation on 8051, so subroutine calls will have same name as mentioned in that tutorial.

;*****************************************
; This sample will read DS1307 timekeeper
; registers and store them in memory
;*****************************************
	;Start Condition
	acall startc
	;Send DS1307 Slave Address
	;with write flag, for dummy write call
	mov a,#0D0H
	acall send
	;You can check if DS1307 has acked or not
	;by reading carry flag
	;if carry flag is 1 it means its a NAK
	;if 0 its ACK
	
	;Set start address where we want to read from
	mov a,#00H
	acall send
	
	;You can send a repeated start condition
	;or send stop + start depending your
	;i2c controller support Rstart or not
	acall rstart
	;Send DS1307 slave address again but
	;this time with a read bit set
	mov a,#0D1H
	acall send

	;Setting memory area to store data in
	;microcontroller RAM
	mov r0,#30H
	;load Number of bytes to read
	mov r1,#8
read:
	;Read one byte
	acall recv
	;Store in RAM
	mov @r0, a
	;Move to next address
	inc r0
	;Check if its our last byte?
	cjne r1,#1,sendack
	;Send NAK to DS1307 indicating end of transfer
	;as this was our last byte to read
	acall nak
	sjmp next
sendack:
	;Send ACK if its not last byte
	acall ack
next:
	;Decrement counter for loop
	djnz r1, read
	
	;Send a stop condition after reading is done
	acall stop

C Language Sample Code

I am considering same scenario as in assembly sample, DS1307 connected to 8051 microcontroller. Here is a sample code for reading DS1307 registers in C

I2CStart();		/* start condition */
I2CSend(0xD0);	/* Slave address + Write */
I2CSend(0x00);	/* Starting address of RTC */
I2CRestart();	/* Repeated start condition */
I2CSend(0xD1);	/* Slave address + Read */
/* Read 8 registers from RTC */
for (i = 0; i < 8; i++) {
	/* Read and store in array */
	/* This is much simpler than in Assembly :) */
	a[i] = I2CRead();

	/* check for last byte */
	if(i == 7)
		I2CNak();	/* NAK if last byte */
	else
		I2CAck();	/* ACK for all read bytes */
}
/* Reading finished send stop condition */
I2CStop();

Programming PIC for DS1307

Following code example uses the C code provided in I2C Implementation on PIC written for PIC16F877A microcontroller MSSP module.

void main()
{
	/* Buffer where we will read/write our data */
	unsigned char I2CData[] = {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x00};
	unsigned char i;
	/* Initialize I2C Port */
	I2CInit();
	/* Send Start condition */
	I2CStart();
	/* Send DS1307 slave address with write operation */
	I2CSend(0xD0);
	/* Send subaddress 0x00, we are writing to this location */
	I2CSend(0x00);

	/* Loop to write 8 bytes */
	for (i = 0; i < 8; i++) {
		/* send I2C data one by one */
		I2CSend(I2CInitval[i]);
	}

	/* Send a stop condition - as transfer finishes */
	I2CStop();

	/* We will now read data from DS1307 */
	/* Reading for a memory based device always starts with a dummy write */
	/* Send a start condition */
	I2CStart();
	/* Send slave address with write */
	I2CSend(0xD0);
	/* Send address for dummy write operation */
	/* this address is actually where we are going to read from */
	I2CSend(0x00);

	/* Send a repeated start, after a dummy write to start reading */
	I2CRestart();
	/* send slave address with read bit set */
	I2CSend(0xD1);
	/* Loop to read 8 bytes from I2C slave */
	for (i = 8; i > 0; i--) {
		/* read a byte */
		I2CData[i] = I2CRead();
		/* ACK if its not the last byte to read */
		/* if its the last byte then send a NAK */
		if (i - 1)
			I2CAck();
		else
			I2CNak();
	}
	/* Send stop */
	I2CStop();
	/* end of program */
	while(1);
}

See Also

There are other RTC chips available from Maxim (DS13xx series) which are similar to DS1307. You can check the register description of RTC and you can try working on them.

Read more articles on I2C based devices

Help & Queries

If you have any queries, doubts or feedback on this tutorial please share in our discussion forum.

Powered by MediaWiki
This page was last modified on 6 March 2015, at 18:51.
ArrayContent is available under Creative Commons Attribution Non-Commercial Share Alike unless otherwise noted.