Displaying RTC (DS1307) date and time on LCD

Hi,

I've copied and modified a code from this link: [RTC] [SOLVED] How to set date and time permanent - #17 by pito - Programming Questions - Arduino Forum
The code was by ppcjunkie, which is to set time and date.
hence, i would like to display the date and time running on the LCD.
I've tried different ways of code (I'm bad at coding) but still couldn't get the values display on the LCD, it just shows zero and some weird patch on the screen. Here's the code

/* Downloaded from http://projectsfromtech.blogspot.com/
*Connect SCL, SDA, Vcc, and GND
*Set date in function below.
*Upload and enjoy!
*/


//Arduino 1.0+ Only
#include <LiquidCrystal.h>
#include "Wire.h"

#define DS1307_ADDRESS 0x68
byte zero = 0x00; //workaround for issue #527
int month;
int monthDay;
int year;
int minute;
int hour;
int second;

LiquidCrystal lcd(12,11,9,4,3,5);

void setup(){
  lcd.begin(16,2);
  Wire.begin();
  
  Serial.begin(9600);
  setDateTime(); //MUST CONFIGURE IN FUNCTION
}

void loop(){
  {
  printDate();
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(month);
  lcd.print("/");
  lcd.print(monthDay);
  lcd.print("/");
  lcd.print(year);
  lcd.setCursor(0,1);
  lcd.print(hour);
  lcd.print(":");
  lcd.print(minute);
  lcd.print(":");
  lcd.println(second);
  

  }
  delay(1000);
}


void setDateTime(){

  byte second =      0; //0-59
  byte minute =      29; //0-59
  byte hour =        15; //0-23
  byte weekDay =     4; //1-7
  byte monthDay =    10; //1-31
  byte month =       7; //1-12
  byte year  =       14; //0-99

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.write(zero); //start 

  Wire.endTransmission();

}

byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  //print the date EG   3/1/11 23:59:59
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);

}

Plus, every time i upload the sketch, the time would keep override, will this wear out the RTC? If yes, then what should i do?

All helps and suggestions will be greatly appreciated.
Thanks a lot! :slight_smile:

Plus, every time i upload the sketch, the time would keep override, will this wear out the RTC?

No. But, since you have an RTC, why do you need to keep changing the time? Comment out that line.

I've tried different ways of code (I'm bad at coding) but still couldn't get the values display on the LCD, it just shows zero and some weird patch on the screen.

Is the problem with getting the data onto the LCD, or with getting the data? In other words, what does your serial output look like?

Why do you have global variables named hour, minute, second, etc. AND local variables in the stupidly-named printDate() function?
Stop that shit NOW!

Given your statement and comment:

  Wire.write(zero); //stop Oscillator

you need to download and read the DS1307 data sheet, especially Table 2, Timekeeper Registers, on page 8. The registers are read via an internal pointer that automatically advances each time you do a read operation. If you attempt to read past the last register, it automatically resets itself to the first register. The statement above has nothing to do with an oscillator. It simply resets the register pointer to the first (i.e., seconds) register.

Most DS1307 modules provide an onboard battery to maintain the time after power is removed from the host. I would get rid of the

setDateTime(); //MUST CONFIGURE IN FUNCTION

in setup() and replace it with a call to the PC to read the PC's system clock and then move those values into the DS1307. That way, a reset always picks off the current time without having to edit the numbers in the source file. Once you're happy with the code, you could even comment out the PC call.

Hi,

This is my first time using arduino, I'm only given 3 months to continue and complete the project that was left my 3 previous students. I've tried my best to understand arduino's code and my programming is rather weak. Anything funny or wrong, please understand.

Is the problem with getting the data onto the LCD, or with getting the data?

Yes, getting the data onto the LCD.

Why do you have global variables named hour, minute, second, etc.

Because the code couldn't compile-error saying those hour,minutes, etc were not declared, and i don't know what to do so i just tried putting it as global variables to make it compile.

AND local variables in the stupidly-named printDate() function?

I don't know, it was already in the code when i got it from ppcjunkie @ [RTC] [SOLVED] How to set date and time permanent - #17 by pito - Programming Questions - Arduino Forum

in setup() and replace it with a call to the PC to read the PC's system clock and then move those values into the DS1307. That way, a reset always picks off the current time without having to edit the numbers in the source file. Once you're happy with the code, you could even comment out the PC call.

Is there anyplace that i could get a reference code for PC call?

Thanks for the replies and helpful suggestions :slight_smile:

Give this a try, and then figure out what it does.

/*****
  This program initializes the RTC module to the time and date on the host PC. If the user wishes to use some other date
  and time, they can hard code the values in the SetStartingClockValues() function.
  
  Feb. 5, 2014
  Dr. Purdum, W8TEE
	 
*/
#include <Wire.h>            //I2C header file
#include <LiquidCrystal.h>
#include <RTClib.h>

#define RTCI2CADDRESS 0x68   // 7 bit device address (without last bit - look at the datasheet)

#define SECONDS          0      // These are offsets into the DS1307 internal registers
#define MINUTES          1
#define HOURS            2
#define DAY              3      // This is a day-of-the-week index register
#define DATE             4
#define MONTH            5
#define YEAR             6
#define MILLENIA         2000


LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // For LCD display from Chapter 3
RTC_Millis rtc;
DateTime currentDateTime;

byte result;
byte timeBuffer[8];
byte flagBit = 0;

void setup()
{
  Wire.begin();                           // Initiate the Wire library and join the I2C 
                                          // bus as a master
  lcd.begin(16, 2);                       // set up the LCD's number of columns and rows 

  Serial.begin(9600); // Initiate serial communication
  rtc.begin(DateTime(__DATE__, __TIME__));
  currentDateTime = rtc.now();
  SetStartingClockValues();
  Serial.println("Clock initialized");

}

void loop()
{ 
   // Nothing to do here... 
}


/*****
  This function reads the system clock of the host PC and translates those time and date values
  for use by the RTC. This involves reading the date and time values from the PC via the now()
  method from the RTClib library and copying those values into the timeBuffer[] array. Because
  the DS1307 wants its data in BCD format, the timeBuffer[] data are converted to BCD format. The 
  RTClib library is available from: https://github.com/adafruit/RTClib.
  
  Parameter list:
    void
    
  Return value:
    void
    
  CAUTION: This function assumes that the DateTime variable named currentDateTime exists prior 
  to the function call.
*****/
void SetStartingClockValues()
{  
  timeBuffer[MONTH]    = currentDateTime.month();             // Month (1-12)
  timeBuffer[DATE]     = currentDateTime.day();               // Day (1-31)
  timeBuffer[YEAR]     = currentDateTime.year() - MILLENIA;   // Year (need as 0-99, no centuries)
  timeBuffer[DAY]      = currentDateTime.dayOfWeek();         // Day of week (1-7)
  timeBuffer[HOURS]    = currentDateTime.hour();              // Hour (0-23)
  timeBuffer[MINUTES]  = currentDateTime.minute();            // Minutes (0-59)
  timeBuffer[SECONDS]  = currentDateTime.second();            // Seconds (0-59)

  Wire.beginTransmission(RTCI2CADDRESS);        // Select RTC on the I2C bus
  Wire.write(0);                                // Reset internal register pointer                     
  Wire.write(DecToBcd(timeBuffer[SECONDS]));    // Second
  Wire.write(DecToBcd(timeBuffer[MINUTES]));    // Minute
  Wire.write(DecToBcd(timeBuffer[HOURS]));      // Hour
  Wire.write(DecToBcd(timeBuffer[DAY]));        // Weekday
  Wire.write(DecToBcd(timeBuffer[DATE]));       // Day
  Wire.write(DecToBcd(timeBuffer[MONTH]));      // Month (with century bit = 0)
  Wire.write(DecToBcd(timeBuffer[YEAR]));       // Year
  Wire.write(0);                        
  result = Wire.endTransmission();
  if (result) 
    Serial.print("RTC Write error occurred");
}
/*****
  This function converts the byte-length decimal value to a Binary Coded Decimal value. 
 
  Parameter list:
    byte value        A number expressed as a decimal value
    
  Return value:
    byte              The decimal value expressed as a BCD number
    
*****/
byte DecToBcd(byte value){
  return (value / 10 * 16 + value % 10);
}

Just to add another perspective, I use this library which is linked from the Playground. I use it to display the time on OLED display. It might be worth a look.

There's a sketch in the library examples to set the time (it uses the time the sketch was compiled), and another to read it. Dead simple to use.

Because the code couldn't compile-error saying those hour,minutes, etc were not declared, and i don't know what to do so i just tried putting it as global variables to make it compile.

As PaulS stated you need to fix that.

I am assuming that you have the display working properly and can print the "Hello World" sketch in the Liquid Crystal library example. If not, you need to get the lcd running properly and a good trouble shooting procedure is here LCD WH1602B2-TMI-ET# Winstar Display Co. - #2 by floresta - Displays - Arduino Forum

I think that if you eliminate the global declaration of hours, minutes, seconds, etc, and then place the lcd print out statements within the printDate() function the code should work.

There are many things with the display and rtc sections of the code that could be improved after you get it all working. You've had some suggestions on the RTC side, and on the lcd side would suggest that not update the display continually in the loop with the use delay (1000) but rather study the "blink without delay" and use that approach to updating the timer rather than using delay().

It is also better practice to control the display with proper formatting and the printing of leading zeros rather than calling lcd.clear() every time through the loop. Do a forum or google search on printing leading zeros with a display and keeping the displayed data the same length on the display.

Hi all,

Really thanks for all of your help. I've changed to another code and able to fix my problem. Really thanks for the suggestions and explanation on my problem. Thanks again!

Rach