# RTC_DS1307 + PIC18F458 displaying time and date as zeroes

I am trying to get the RTCDS1307 + PIC hardware to work in order to display the appropriate data and time. But the problem is that, its displaying the time and date as 00:00:00 and 00/00/2000 as shown in the snap below.

I presume that the RTC registers aren't be set properly or there is no data tx and rx happening at all when it comes to the hardware.I cross checked the code/bit rate calculations and everything seems to be fine. I don't understand how come it isn't working. Is there anything wrong with the I2C initialization or my approach?. Any help regarding this would be appreciated.Here is the code:

#include<P18F458.h>
#include<xc.h>
#include<htc.h>
#include"LCD.h"

#define _XTAL_FREQ 20000000

unsigned char sec,min,hour,date,month,year;
unsigned char data[7] = {0x45,0x59,0x71,0x04,0x05,0x10,0x06};
int i;

void I2C_idle()
{
while((SSPCON2 & 0x1F)|(SSPSTATbits.R_W));
}
void I2C_start()
{
I2C_idle();
SSPCON2bits.SEN = 1; //Set start enable bit
while(SSPCON2bits.SEN); //Wait until cleared by hardware
}

void I2C_stop()
{
SSPCON2bits.PEN = 1; //Set stop enable bit
while(SSPCON2bits.PEN); //Wait until cleared by hardware
I2C_idle();
}

void I2C_restart()
{
SSPCON2bits.RSEN = 1; //Initiates Repeated Start Condition on SDA   and SCL pins
while(SSPCON2bits.RSEN==1); //Wait until cleared by hardware
I2C_idle();
}

{
I2C_start();
I2C_idle();
I2C_idle();
SSPBUF = addr; //Write the location
I2C_idle();
SSPBUF = data; //Write the data
I2C_idle();
I2C_stop(); //Enable stop bit
I2C_idle();
}
void I2C_Init()
{
TRISCbits.TRISC3 = 1; // SCL direction input
TRISCbits.TRISC4 = 1; //SDA direction input
SSPCON1bits.SSPM3 = 1; //SSPM0:SSPM3 = 0001 (Master Mode
SSPCON1bits.SSPM2 = 0;
SSPCON1bits.SSPM1 = 0;
SSPCON1bits.SSPM0 = 0;
SSPSTATbits.SMP = 1;
SSPADD = 0x31; /*For Fosc 20MHz, Required Bit Rate = 100 KHz
SSPADD = ((20MHz/4)/100 KHz - 1)= 0x31*/
PIR1bits.SSPIF = 0;
SSPCON2 = 0;
SSPCON1bits.SSPEN = 1;
RTC_Write(0,0x00);
}

{
unsigned char x;
I2C_start(); //Enable repeated start condition
I2C_idle();
I2C_idle();
I2C_restart();
I2C_restart();
SSPCON2bits.RCEN = 1; //Enable to recieve data
I2C_idle();
SSPCON2bits.ACKDT = 1; //Acknowledge the operation (Send NACK)
SSPCON2bits.ACKEN = 1; //Acknowledge sequence on SCL and SDA pins
I2C_stop();
x = SSPBUF; //store the recieved value in a var
return(x);

}
unsigned char BCD2Upperch(unsigned char bcd)
{
unsigned char temp;
temp = bcd >> 4;
temp = temp | 0x30;
return (temp);

}

unsigned char BCD2Lowerch(unsigned char bcd)
{
unsigned char temp;
temp = bcd & 0x0F;
temp = temp | 0x30;
return (temp);
}

void main()
{
TRISCbits.TRISC0 = 0;
TRISCbits.TRISC1 = 0;
TRISCbits.TRISC2 = 0;
TRISD = 0;
char16x2LCDInit();
__delay_ms(20);
I2C_Init();
for(i=0 ; i<7 ; i++)
RTC_Write(data[i],i);
__delay_ms(20);

while(1)
{

arraydisp("Time: ",0x80);
Write_Data(BCD2Upperch(hour));
Write_Data(BCD2Lowerch(hour));
Write_Data(':');
Write_Data(BCD2Upperch(min));
Write_Data(BCD2Lowerch(min));
Write_Data(':');
Write_Data(BCD2Upperch(sec));
Write_Data(BCD2Lowerch(sec));
arraydisp("Date: ",0xC0);
Write_Data(BCD2Upperch(date));
Write_Data(BCD2Lowerch(date));
Write_Data('/');
Write_Data(BCD2Upperch(month));
Write_Data(BCD2Lowerch(month));
Write_Data('/');
LCDWriteInt(20,2);
Write_Data(BCD2Upperch(year));
Write_Data(BCD2Lowerch(year));

}


Best Regards ~VD

• Have you any way to write text to the host PC? If you have, write the RTC values to the host PC, inside the while (1) {...} loop. How does the correct time get set on the RTC? Also try blinking a led or part of the display each time round the while (1) {...} loop to ensure it is not blocked on something. Have you a simpler program which proves that the RTC code, and RTC, is working, something without the extra complexity of the LCD? – gbulmer Dec 27 '15 at 16:33
• Yes. I can write to PC using UART. I will first check if my slave is even responding with an acknowledgement. We set the time and date on the RTC before entering the while loop. – PsychedGuy Dec 28 '15 at 1:18

The I2C_restart only belongs at the point where you change from write mode (sending the register address) to read mode (reading data).

• you should check the ACK bit after you send the RTC read/write address (and wait for I2C_Idle) right at the beginning of your RTC_read/RTC_write functions. You can't wait until after the I2C transaction is complete before checking ACK.
• If the RTC fails to ACK, you should end the I2C transaction (by sending an I2C_stop) and then possibly trying again and/or displaying an error message. Once you have this working, an ACK fail most likely indicates a hardware fault of some kind ...

• You mean, I need to call the I2C_restart function only during the I2C_Read operation?. I also need to 1st check if my slave is even responding with an acknowledgement after sending a byte to it. – PsychedGuy Dec 28 '15 at 14:22
• The 2nd I2C_restart in your RTC_read is correct. The 1st one should be an I2C_start, not an I2C_restart. An I2C transaction always starts with a _start, never a _restart. – brhans Dec 28 '15 at 14:25
• Thank you for your time and detailed answer. I will do as suggested and get back soon! – PsychedGuy Dec 28 '15 at 15:20

You are swapping i2c addr and data while passing them to RTC_Write(). Just check RTC_Write() function and code after I2C_Init() you will understand.

// for(i=0;i<7;i++)
RTC_Write(0,0x45); // when i=0

In RTC_Write function()