The PIC 18F2620 has a built-in I2C (Inter-Integrated Circuit) bus. I2C is a 2-wire synchronous serial bus.

Some devices, such as sensors, communicate with microcontrollers on this 2-wire serial bus. Multiple devices, even different types of devices, can be attached to the same 2-wire I2C bus without causing collisions or errors.
Each device contains a unique address allowing multiple devices attached to the same I2C bus.
In this example, we will use the DS1307 real-time clock (RTC) that communicates over I2C to set (write) the time and date and also read from it. Before continuing, be sure to read through the I2C tutorial.

The DS1307 is a low power serial real time clock/calender from Maxim Integrated with full binary coded decimal (BCD) clock/calendar plus 56 bytes of Non Volatile Static Random Access Memory.

Data and Address are transferred serially through a bidirectional I2C bus. The RTC provides year, month, date, hour, minute and second information. The end date of months is automatically adjusted for months fewer than 31 days including leap year compensation up to year 2100. It can operate either in 24-hour format or 12-hour format with AM/PM indicator.
DS1307 comes with built-in power sensing circuit which senses power failures and automatically switches to back up supply. Timekeeping operation continues while the part operates from the backup supply.
The DS1307 RTC uses an external 32.768kHz Crystal Oscillator and it does not requires any external resistors or capacitors to operate.

The DS1307 operates as a slave device on the I2C bus. Access is obtained by implementing a START condition and providing a device identification code followed by a register address. Subsequent registers can be accessed sequentially until a STOP condition is executed.

I2C Bus Connection

As shown on the circuit diagram above, connect the PIC SCK pin (pin 14 of the 18F2620) to the DS1307 SCL (pin 6) and connect the PIC SDA pin (pin 15) to the DS1307 SDA (pin 5).
Connect two pull up resistors one from the serial clock line and the other from the serial data line to positive power supply.
The higher value of pull up resistor is limited by the rise time and the lower vale of pull up resistor is limited by the drive strength (IOL max) of the SDA and SCL drivers. If the pull up resistor is very low , the bus line might not work.
Connect an external 32768 crystal to pins 1 and 2 of the DS1307.
A 3V backup battery can also be connected to pin VBAT (pin 3) of the DS1307, if this is not required, this pin can be grounded.
On our circuit, we are using internal oscillator and the MCLR is disabled. If an external oscillator is needed, it can be connected to pins 9 and 10 and if the MCLR is needed, it can be connected to positive supply via a 10K resisitor.

MPLAB XC8 provides built-in libraries for I2C devices. DS1307 works as a slave device on I2C bus.
Register access can be obtained by implementing a START and followed by device identification address. Then each registers can be accessed sequentially by using its address until a STOP condition is executed.
Device Address of the DS1307 is 0x68 = 1101000 (page 12 of datasheet).
More details can be found from the DS1307 Datasheet.

Configure I2C with PIC18F Peripheral Library

The first thing to do is to configure the I2C port on the PIC. According to the PIC18F Peripheral Library Help Document found inside your compiler installation directory in: ..Program Files (x86)Microchip\ xc8\ v1.34\ docs\ MPLAB_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” For a 18F2620 family, the I²C functions are from page 1152 in the pdf ).

The OpenI2C is the function to call.
If the PIC microcontroller has more than one I2C lines, specify which one you are opening (OpenI2C, OpenI2C1…))
The first thing to understand here is the difference between MASTER and SLAVE. Since the PIC will control all the devices, the PIC should be set as MASTER. Since bus speed isn’t a concern, slew control can be turned off using SLEW_OFF parameter:
SLEW_OFF Slew rate disabled for 100 kHz mode (standard mode).
SLEW_ON Slew rate enabled for 400 kHz mode (fast mode)
The second thing is to understand what the SSPADD register (SSP Address) does inside the PIC.
SSPADD register holds the slave device address when the SSP is configured in I2C Slave mode. When the SSP is configured in Master mode, the lower seven bits of SSPADD act as the Baud Rate Generator reload value.
It can be used to specify what baud rate (speed) communications will occur based on the crystal used.
For our example, we will are using internal oscillator at a frequency of 8MHz and baud rate of 100KHz, SSPADD = 19 as the DS1307 operates in the standard mode (100kHz) only.
From the Using the PICmicro MSSP Module for I2C Communications document on page 3, the formula to calculate SSPADD is:

Where FoSC is the oscillator frequency and Bit Rate is the speed of communication (100KHz, 400KHz…)

For more values, check the PIC18F2620 Datasheet

At this stage the initialization of the I2C is complete and communication can now start.

There are 2 functions commonly used with this device: set values in memory and get values from memory.
We will go through both functions using examples. The digital values in this device are stored using 4-bit binary-coded decimal (BCD). A conversion from BCD to Binary and Binary to BCD will be needed to properly display and save the values using a PIC.

Writing and Reading from a slave can be summarized as follow:

Master Writes to a Slave

  1. Send a START bit (logic zero)
  2. Send the I²C address of the SLAVE with the R/W bit low (even address)
  3. Send the device register you want to write to 
  4. Send the data byte 
  5. Send the STOP sequence. 

Master Reads from a Slave 

  1. Send a START
  2. Send I²C address of the SLAVE with the R/W bit low (even address)
  3. Send device register you want to read from
  4. Send a START sequence again (a repeated start)
  5. Send I²C address of the SLAVE with the R/W bit high (odd address)
  6. Read data byte from SLAVE
  7. Send the STOP sequence.

Set RTC Values

First thing is to program the IC with the correct values for the calendar and the clocks. In our example, we will set the minutes. Once this set, all other registers (hour, day…) can be set using the same procedures.
The timing and sequence of the I2C communication is as follow: We begin with the StartI2C() command.

This is what we have been doing:

1. First thing we do is begin the communication by using StartI2C().
2. IdleI2C(): This function checks the state of the I2C peripheral and waits for the bus to become available. The I2C peripheral must be in an Idle state before an I2C operation can be initiated or a write collision will be generated.
3. WriteI2C(): This is the function to access the register.
Since many devices can be attached to this bus, this address ‘awakens’ the correct device. The next data sequences will only be ‘looked at’ by this device on the bus. The address of any device on the I2C bus is usually (but not always) made up of 2 parts. First part is a set of internal address bits. The second part is made up of hardwired address bits using the pins of the IC. However, the DS1307 has its entire address in internal to the chip.
According to page 12 of datasheet), the 7-bit address is ‘1101000’. So where’s the 8th bit? After every address byte sent by the PIC using I2C, the 8th bit determines if the next byte is written or read by the PIC: 0 to write and 1 to read.  The least significant bit (8th bit) is 0, so the full 8-bit data to write will be 0xD0.
4. WriteI2C(0x01): According to the Table 2 above, each register has a hex value address associated with it. Notice that the MINUTES register is 01h (or 0x01). Therefore, to access the register, the PIC writes 0x01.
5. WriteI2C( 0b00010010 ): According to the Table 2 again, The MINUTES register is composed of 2 parts:
The lower nibble (bit 0 through bit 3) and the upper nibble (bit 4 through bit 6). Both nibbles are used together to represent double-digit numbers. For example, the number “13” is composed of a ‘1’ and a ‘3’. Each digit is stored in a separate nibble. The ‘1’ is stored as a BCD number in the upper nibble while the ‘3’ is stored as a BCD number in the lower nibble.
For example, to store the number “13”, the MINUTES register should be set to ‘001 0011’ in binary.
The ‘001’ is BCD for ‘1’ and 0011 is BCD for ‘3’. Since there are no double-digit minutes higher than 59, only 7 bits are needed to represent any double-digit from 00 to 59.
6. StopI2C(): After everything, we can close the I2C bus.

We have written the binary number 0010011 into the MINUTES register, we can repeat the same procedure or write a function that we can call to set the hour, day, month and so on. Now, the RTC will keep track of the minutes and after 59min:59sec, the RTC will increment the HOURS register and roll-over to 00min:00secs.

Let us now learn how to read from the registers.

Get RTC Value 

The next step is to get data from the RTC into PIC memory. Assuming I2C has been previously configured, all the correct files have been included, and the RTC has values stored, we can begin. In the following example, we are going to get the value for day of the week. We can start by declaring a char variable to store the 8-bit value (which holds the BCD number).

The I2C read routine needs to be added. Therefore, we begin as usual using the StartI2C() command and address the chip using WriteI2C().

The rest of the registers can also be read in the same way to display the hour, minute, seconds and so on.

What is important to note here again, the data read is 8-bit BCD value, it has to be converted to binary, decimal or hexadecimal as required before being used by the microcontroller.