0
\$\begingroup\$

I am integrating DS1307 in my project and using PIC32MX795F512L MCU. I have somehow managed to do I2C communication in it and getting the real time values. I am displaying the real time value in terminal using UART. So the time is updating automatically. But when I turned off the power to the device and turn it ON again, the DS1307 doesnt gave me the real time value instead it starts the time which I set in the code.

In the code I set, 14:27:12, so after turning it off and on again, the time started from 14:27:12 which I think should not happen. I have battery attached with DS1307.

So I thought to get a real time value, I might have to save the code somewhere else in the Micro Controller.

Need help regarding this.!

CODE:

int main(void)
{
 OpenUART1( UART_EN | UART_NO_PAR_8BIT | UART_1STOPBIT , UART_RX_ENABLE | UART_TX_ENABLE, (FPB/16/BAUDRATE)-1 );
 I2C2BRG = 0xA3; //I2C Baudrate
 I2CEnable(EEPROM_I2C_BUS, TRUE); //I2C module On
 if( !StartTransfer(FALSE) )
 {
 while(1);
 }
 TransmitOneByte(0xD0); //slave address
 TransmitOneByte(0x00); //register pointer pointing to first register 
 TransmitOneByte(0x00); //seconds value
 TransmitOneByte(0x56); //min value
 TransmitOneByte(0x12); //hr value
 StopTransfer(); //I2C Stop
 if(!Success)
 {
 while(1);
 }
 while(1)
 {
 RTC_read();
 **//sending time to UART**
 putsUART1("Time: ");
 putsUART1(value6);
 putsUART1(value5);
 putsUART1(":");
 putsUART1(value4);
 putsUART1(value3);
 putsUART1(":");
 putsUART1(value2);
 putsUART1(value1);
 putsUART1("\n");
 }
}
**///******** FUNCTION TO READ FROM I2C ****************//**
void RTC_read()
 {
 StartTransfer(FALSE); //I2C Start
 TransmitOneByte(0xD0); //I2C slave address
 TransmitOneByte(0x00);
 StopTransfer(); //I2C Stop
 IdleI2C2(); //i2C Stop
 StartTransfer(TRUE); //I2C Restart
 TransmitOneByte(0xD1); //Slave address to read
 **//Reading from I2C slave**
 if(I2CReceiverEnable(EEPROM_I2C_BUS, TRUE) == I2C_RECEIVE_OVERFLOW)
 {
 putsUART1("Error: I2C Receive Overflow1\n");
 }
 else
 {
 **//read sec**
 while(!I2CReceivedDataIsAvailable(EEPROM_I2C_BUS));
 Nop();
 sec = I2CGetByte(EEPROM_I2C_BUS); 
 AckI2C2();
 while (!I2CAcknowledgeHasCompleted(I2C2)); 
 **//read min**
 I2CReceiverEnable(EEPROM_I2C_BUS, TRUE);
 while(!I2CReceivedDataIsAvailable(EEPROM_I2C_BUS)); 
 Nop();
 min = I2CGetByte(EEPROM_I2C_BUS); 
 AckI2C2();
 while (!I2CAcknowledgeHasCompleted(I2C2)); 
 **//read hr**
 I2CReceiverEnable(EEPROM_I2C_BUS, TRUE);
 while(!I2CReceivedDataIsAvailable(EEPROM_I2C_BUS)); 
 Nop();
 hr = I2CGetByte(EEPROM_I2C_BUS); 
 NotAckI2C2();
 while (!I2CAcknowledgeHasCompleted(I2C2)); 
 }
 StopTransfer(); //I2C Stop
 if(!Success)
 {
 while(1);
 }
 **//converting sec to ASCII**
 x1 = sec & 0x0F;
 p1 = x1 | 0x30;
 y = sec & 0xF0;
 y = y >> 4;
 p2 = y | 0x30;
 sprintf(value1,"%c",p1);
 sprintf(value2,"%c",p2);
 **///converting min to ASCII**
 x2 = min & 0x0F;
 p3 = x2 | 0x30;
 y2 = min & 0xF0;
 y2 = y2 >> 4;
 p4 = y2 | 0x30;
 sprintf(value3,"%c",p3);
 sprintf(value4,"%c",p4);
 **////converting hr to ASCII**
 x3 = hr & 0x0F;
 p5 = x3 | 0x30;
 y3 = hr & 0xF0;
 y3 = y3 >> 4;
 p6 = y3 | 0x30;
 sprintf(value5,"%c",p5);
 sprintf(value6,"%c",p6);
}

EDIT

Following are the functions used in code:

StartTransfer(BOOL restart):-

//Description:This routine starts (or restarts) a transfer to/from the EEPROM, waiting (in a blocking loop) until the start (or re-start) condition has completed.
 //Parameters:restart - If FALSE, send a "Start" condition
 // - If TRUE, send a "Restart" condition
 //Returns: TRUE - If successful
 // FALSE - If a collision occured during Start signaling
BOOL StartTransfer( BOOL restart )
{
I2C_STATUS status;
// Send the Start (or Restart) signal
if(restart)
{
 I2CRepeatStart(EEPROM_I2C_BUS);
}
else
{
 // Wait for the bus to be idle, then start the transfer
 while( !I2CBusIsIdle(EEPROM_I2C_BUS) );
 if(I2CStart(EEPROM_I2C_BUS) != I2C_SUCCESS)
 {
 DBPRINTF("Error: Bus collision during transfer Start\n");
 return FALSE;
 }
}
// Wait for the signal to complete
do
{
 status = I2CGetStatus(EEPROM_I2C_BUS);
} while ( !(status & I2C_START) );
return TRUE;
}

BOOL TransmitOneByte( UINT8 data ):-

 //Description:This transmits one byte to the EEPROM, and reports errors for any bus collisions.
//Returns:TRUE - Data was sent successfully
 FALSE - A bus collision occured
BOOL TransmitOneByte( UINT8 data )
{
// Wait for the transmitter to be ready
while(!I2CTransmitterIsReady(EEPROM_I2C_BUS));
// Transmit the byte
if(I2CSendByte(EEPROM_I2C_BUS, data) == I2C_MASTER_BUS_COLLISION)
{
 DBPRINTF("Error: I2C Master Bus Collision\n");
 return FALSE;
}
// Wait for the transmission to finish
while(!I2CTransmissionHasCompleted(EEPROM_I2C_BUS));
return TRUE;
}

void StopTransfer( void ):-

 //Description:This routine Stops a transfer to/from the EEPROM, waiting (in //a blocking loop) until the Stop condition has completed.
void StopTransfer( void )
{
I2C_STATUS status;
// Send the Stop signal
I2CStop(EEPROM_I2C_BUS);
// Wait for the signal to complete
do
{
 status = I2CGetStatus(EEPROM_I2C_BUS);
} while ( !(status & I2C_STOP) );
}
asked Dec 8, 2015 at 8:30
\$\endgroup\$
8
  • \$\begingroup\$ You should try to reduce the program to something simple, and paste the code into your question. It sounds like your program is always setting the time value, no matter what. If you post code, someone might be abe to help. How does your program detect that the DS1307 is running when the MCU is turned off, and the program restarted from the beginning, and hence, how does the program avoid updating the DS1307? \$\endgroup\$ Commented Dec 8, 2015 at 8:53
  • \$\begingroup\$ @gbulmer I have editd my question with code. Thanks! \$\endgroup\$ Commented Dec 8, 2015 at 9:01
  • \$\begingroup\$ That code looks like it just sets the same time every time on boot, just comment it out and see what happens. \$\endgroup\$ Commented Dec 8, 2015 at 9:05
  • 1
    \$\begingroup\$ @user007 Everytime the uC starts; it is sending out values to DS1307. TransmitOneByte(0x00); //seconds value TransmitOneByte(0x56); //min value TransmitOneByte(0x12); //hr value Because the main function will execute one time when it starts and then enters the while loop. You might want to put these three lines somewhere in a function and call this function when you press a switch or something. Only then you could avoid updating DS1307 every time you start the uC \$\endgroup\$ Commented Dec 8, 2015 at 9:06
  • 1
    \$\begingroup\$ @ammar.cma lets say If I put those three lines in a function and call the function at pressing the switch, so when I'll press the switch all the three lines will execute so that will not be a real time . \$\endgroup\$ Commented Dec 8, 2015 at 16:49

2 Answers 2

2
\$\begingroup\$

You only have to set time once and then just read it.

So next time don't include the setting time function in your code because earlier you have set time. The registers of DS1307 will contain the updated time and you will have to read it.

Lets say, you have below functions:

RTC_init : to initialise I2C channel
RTC_setTime : to set time
RTC_readTime : to read time

Then at first include all the three functions in your code. Something like below:

main()
{
 RTC_init();
 RTC_setTime();
 while(1)
 {
 RTC_readTime();
 }
}

and then second time, comment out the function RTC_setTime() and again program your device. Like below

main()
{
 RTC_init();
 //RTC_setTime();
 while(1)
 {
 RTC_readTime();
 }
}

Now if you didn't give power to your device, the battery will help DS1307 to hold the updated values of time & date to their registers and it will keep on doing this.

answered Dec 9, 2015 at 9:43
\$\endgroup\$
1
  • \$\begingroup\$ If you make one program for the device you're program is useless. That's why i suggested putting a switch to set TIME and then continuously read it. But given that OP has no display or I/O. This would work. \$\endgroup\$ Commented Dec 9, 2015 at 10:32
4
\$\begingroup\$

At a quick glance, it looks like the only way that the code WILL NOT update the DS1307, is if StartTransfer(FALSE) detects that the DS1307 has already been initialised.

Does it do that? (To understand the program, we'd need to see the code, and an explanation of how it works. )

Otherwise, the code looks like it always tries to set the same old time into the DS1307.

Copy the program, and change it so that it does not set the time in the DS1307, and run it again.

Think of the problem as two different (use) cases:

  1. Set the DS1307 time
  2. Use the DS1307 time

for simplicity, write two programs, one which only sets the time, and the other solves the problem (the other case).

Edit:
You say the application doesn't have a user interface, and will normally store data onto an SD Card.

So the options are:

  1. Add an extra button (or even just a pin which can safely be shorted to ground) which will be used to trigger the program to set the timer. It might use a variant of methods 2 or 3, below

  2. Write the time into a file with a specific name on the SD card using a PC (of some kind). Depending on your SD Card library, you might even get the data and time from the time stamp of the file. If the file exists when the system is RESET, the system should read the date and time information, set the DS1307, and then delete the file to avoid accidentally reseting the clock again.

  3. Use your 'debug' terminal, connected over UART, to set the DS1307 clock. Write a bit of code to detect if the terminal is connected (I assume normally it isn't), and if the terminal is connected, read the time information.

There is also the option to keep the 'clock set program' separate, and run it when the system is ready to install, and replace it with the production code. (Not as tidy)

answered Dec 8, 2015 at 9:15
\$\endgroup\$
4
  • \$\begingroup\$ Thanks for your answer. By reading your answer, it looks like I need to put a condition like if(time already set) then just {read time} else {set & read time}. If I make two programs: (set time) & (read time). Then where do I save (set time) program so that it run once only. All the programs will be saved in MCU, so at power ON, I think both program will run. I am confused. Please help.| \$\endgroup\$ Commented Dec 8, 2015 at 16:55
  • \$\begingroup\$ Think it through. Your digital watch doesn't have the time set at manufacturing time, it's set by the user with some buttons. Your program should be similar: don't program a fixed time, instead have some means of inputting it once the program is running. \$\endgroup\$ Commented Dec 8, 2015 at 17:05
  • \$\begingroup\$ @user007 - If you have some kind of display or user-interface, I would try build the program to work the way pjc50 explains. If you have no user-interface to offer a sensible way to set the time, then I think your program has to assume the DS1307 is correctly keeping time, and then you are reduced to writing a separate program who's only purpose is to set the time; you will write that and run it once. This isn't as pretty as a program which can set the time for itself. You'll need to explain what interface components (display, buttons, LEDs, USB, ...) the full system has to give more help. \$\endgroup\$ Commented Dec 9, 2015 at 2:48
  • \$\begingroup\$ I don't have any UI or display in my project. I have few inputs and outputs and I want to save their activity in a SD Card with RTC (time at which the input/output were high or low ),just like a log. Though I have not integrated SD card but I just want to set time once which I'll do in code \$\endgroup\$ Commented Dec 9, 2015 at 4:49

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.