I'm Confused DS1307 & LCD

I just received a DS1307 break-out board from Sparkfun and decided to try it out. So I downloaded Sjunnesson’s library from the playground. I hooked everything up and ran the example code. That worked fine.

I then decided to send the output to an LCD instead of the serial port. So I mounted up a 16x2 LCD. To test my hook up, I loaded up the LCD “Hello World” example and ran it. It functioned fine.

So then I sort of collided the two sketches like this:

#include <LiquidCrystal.h>
#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int Hr=0;
int Mn=0;
int Sc=0;
int DD=0;
int MM=0;
int YY=0;

void setup() {
  lcd.begin(16, 2);
}

void loop() {

  Hr=RTC.get(DS1307_HR,true);
  Mn=RTC.get(DS1307_MIN,false);
  Sc=RTC.get(DS1307_SEC,false);
  DD=RTC.get(DS1307_DATE,false);
  MM=RTC.get(DS1307_MTH,false);
  YY=RTC.get(DS1307_YR,false);

  lcd.clear();
  lcd.print(MM); 
  lcd.setCursor(2, 0);
  lcd.print("-");
  lcd.setCursor(3, 0);
  lcd.print(DD);
  lcd.setCursor(5, 0);
  lcd.print("-");
  lcd.setCursor(7, 0);
  lcd.print(YY);

  lcd.setCursor(0, 1);
  lcd.print(Hr); 
  lcd.setCursor(2, 1);
  lcd.print(":");
  lcd.setCursor(3, 1);
  lcd.print(Mn);
  lcd.setCursor(5, 1);
  lcd.print(":");
  lcd.setCursor(6, 1);
  lcd.print(Sc);

  delay(1000);

}

When I run that, I get odd results. Either the “:” and “-” characters do not show up and the time does not update or nothing shows at all. So I altered the code to this:

#include <LiquidCrystal.h>
#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int Hr=0;
int Mn=0;
int Sc=0;
int DD=0;
int MM=0;
int YY=0;

void setup() {
  lcd.begin(16, 2);
}

void loop() {

  Hr=RTC.get(DS1307_HR,true);
  Mn=RTC.get(DS1307_MIN,false);
  Sc=RTC.get(DS1307_SEC,false);
  DD=RTC.get(DS1307_DATE,false);
  MM=RTC.get(DS1307_MTH,false);
  YY=RTC.get(DS1307_YR,false);

  lcd.clear();
  lcd.print("Time:");
//  lcd.print(MM); 
//  lcd.setCursor(2, 0);
//  lcd.print("-");
//  lcd.setCursor(3, 0);
//  lcd.print(DD);
//  lcd.setCursor(5, 0);
//  lcd.print("-");
//  lcd.setCursor(7, 0);
//  lcd.print(YY);

  lcd.setCursor(0, 1);
  lcd.print(Hr); 
  lcd.setCursor(2, 1);
  lcd.print(":");
  lcd.setCursor(3, 1);
  lcd.print(Mn);
  lcd.setCursor(5, 1);
  lcd.print(":");
  lcd.setCursor(6, 1);
  lcd.print(Sc);

  delay(1000);

}

… and it functions as one would anticipate (after cycling the power). The word “Time” shows up on the first line of the LCD and the time that updates every second on the second line. What the heck am I missing?

Does it work any better if you explicitly convert the numbers to strings before calling lcd.print?

char buffer[6];
sprintf(buffer, "%d", Hr);
lcd.print(buffer);

I'll try that once I get home.

Well I tried it. It didn’t work. A bar of blocks was displayed on the first line of the LCD and nothing else. After trying it, I couldn’t get anything to display from the real time clock. Even using the code that worked before. The LCD “Hello World” app however still works. Now I’m really confused. The DS1307 example code also still works.

Any other suggestions?

No one has any other ideas?

It would benefit anyone trying to help you if you post the "new" code you say you used without success

Right, sorry:

#include <LiquidCrystal.h>
#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>

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

int Hr=0;
int Mn=0;
int Sc=0;
int DD=0;
int MM=0;
int YY=0;
char buffer[6];

void setup() {
  lcd.begin(16, 2);
}

void loop() {

  Hr=RTC.get(DS1307_HR,true);
  Mn=RTC.get(DS1307_MIN,false);
  Sc=RTC.get(DS1307_SEC,false);
  DD=RTC.get(DS1307_DATE,false);
  MM=RTC.get(DS1307_MTH,false);
  YY=RTC.get(DS1307_YR,false);

  lcd.clear();

  sprintf(buffer, "%d", Sc);
  lcd.print(buffer);  

  delay(1000);

}

Some things to check, as I look at your code:

  • (Without having looked at the DS1307 library) Do you need any initialization calls to use the RTC.get() functions? I don't see anything in your setup () function.
  • Have you tried, in your loop () function, using Serial.println calls along with lcd.print in order to verify that you are getting good data and converting them to strings properly?
  • (Again without looking at libraries) Why do you have WProgram.h and Wire.h included in your program? Does DS1307 need them?
  • The fact that you say the LCD and RTC tests work independently of each other makes me suspect interference between them.
  • The boolean parameter passed to RTC.get seems to be for a refresh option. Why do you have some true and some false?

Hopefully, these questions might lead someplace useful in your investigation.

.andy

I am suspecting some kind of interference between the libraries as well. The behavior is just too random and unpredictable and I'm too green to find it.

  • (Without having looked at the DS1307 library) Do you need any initialization calls to use the RTC.get() functions? I don't see anything in your setup () function.

There was none in the DS1307 example code.

  • Have you tried, in your loop () function, using Serial.println calls along with lcd.print in order to verify that you are getting good data and converting them to strings properly?

The example code uses serial.Print to send out the data gleaned from the DS1307. I hadn't tried sending it both to the LCD & serial simultaneously.

  • (Again without looking at libraries) Why do you have WProgram.h and Wire.h included in your program? Does DS1307 need them?

I presume that it does because they were in the DS1307 example code.

  • The fact that you say the LCD and RTC tests work independently of each other makes me suspect interference between them.

My thoughts exactly, but where and how?

  • The boolean parameter passed to RTC.get seems to be for a refresh option. Why do you have some true and some false?

Because you don't want to update the data you're reading prior to reading all of it. Imagine reading the time directly at 59 minutes, 59.9999 seconds. You get the proper hour, but suddenly the minute value reads "00" because you've updated and it rolled and you're data is now erroneously an hour old.

More questions:

How is the RTC chip getting initialized? By that I mean, are you sure that it has valid time data in it and the battery powering it is good?

Are you getting the actual time from your computer and then loading that into the RTC ?

There are some RTC.set() functions in the library that you can use to load values into the clock chip, and there are RTC.start() and RTC.stop() calls to control it. The example I saw did use these.

Your latest test program only attempts to show the seconds; I assume that was just to test?

I don't know how the libraries might interact with each other and I don't know exactly which ones you have downloaded and are using, etc.

If I were trying to debug this, I would reduce it to the simplest case I could formulate, and try to get that working, then add in more stuff.

A simple case might be to push known values into the RTC (stop, set, set, set...) without starting it, and then verify you can get those values back and see them via serial and lcd output. Then put the values in and start the clock (stop, set, set, set... start) and see that you are getting updates. Do this without the sprintf buffer first.

Then once you know you are getting good data, add in the sprintf formatting and continue the verification.

I think you have too many floating unknowns right now and you need to reduce the problem to narrower test cases.

If I had one of those modules, I would happily play with it, as I plan to develop an RTC app soon myself.

.andy

Two things to propose:

  • try outputing a constant integer, instead of the seconds.
  • try updating the LCD more slowly. put a delay_microsecodns in the loop, delay for half a second and output something.

OK, I’ve taken your advice. I altered the code to this:

#include <LiquidCrystal.h>
#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>

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

int Hr=0;
int Mn=0;
int Sc=0;
int DD=0;
int MM=0;
int YY=0;
char buffer[6];

void setup() {
  lcd.begin(16, 2);
}

void loop() {

  Hr=1;
  Mn=2;
  Sc+=1;
  DD=3;
  MM=4;
  YY=2009;

  lcd.clear();
  lcd.print(MM);
  lcd.setCursor(2, 0);
  lcd.print("-");
  lcd.setCursor(3, 0);
  lcd.print(DD);
  lcd.setCursor(5, 0);
  lcd.print("-");
  lcd.setCursor(7, 0);
  lcd.print(YY);

  lcd.setCursor(0, 1);
  lcd.print(Hr);
  lcd.setCursor(2, 1);
  lcd.print(":");
  lcd.setCursor(3, 1);
  lcd.print(Mn);
  lcd.setCursor(5, 1);
  lcd.print(":");
  lcd.setCursor(6, 1);
  lcd.print(Sc);

  delay(1000);

}

It does not work. If however I comment out the “#include <DS1307.h>” line, it functions as one would anticipate. That pretty much localizes it. Does anyone have an idea how to fix it?

How did you connect the LCD and the RTC? Can you post a schematic or at least a simple drawing? It might be a lines signal problem.

Ok, I’ve been playing some more with the code. I followed the other DS1307 link on the playground and adapted the code I found there. The following functions just fine:

#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

// Global Variables
int second, minute, hour, dayOfWeek, dayOfMonth, month, year;

void setup() {
  Wire.begin();
  Serial.begin(57600);
}

void loop() {

    getDateDs1307();
  
    Serial.print(month);
    Serial.print("/");
    Serial.print(dayOfMonth);
    Serial.print("/");
    Serial.print(year);
    Serial.println();

    Serial.print(hour);
    Serial.print(":");
    Serial.print(minute);
    Serial.print(":");
    Serial.print(second);
    Serial.println();

    delay(500);
}

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

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

// Gets the date and time from the ds1307 and prints result
void getDateDs1307()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x00);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(Wire.receive() & 0x7f);
  minute     = bcdToDec(Wire.receive());
  hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(Wire.receive());
  dayOfMonth = bcdToDec(Wire.receive());
  month      = bcdToDec(Wire.receive());
  year       = bcdToDec(Wire.receive());

}

However as soon as I add the LCD library and declare an instance, things head south.

#include "Wire.h"
#include <LiquidCrystal.h>
#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

// Global Variables
int second, minute, hour, dayOfWeek, dayOfMonth, month, year;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  Wire.begin();
  lcd.begin(16, 2);
}

void loop() {
    getDateDs1307();

    lcd.clear();
    lcd.print(month);
    lcd.setCursor(2,0);
    lcd.print("/");
    lcd.setCursor(3,0);
    lcd.print(dayOfMonth);
    lcd.setCursor(5,0);
    lcd.print("/");
    lcd.setCursor(6,0);
    lcd.print(year);

    lcd.setCursor(0, 1);
    lcd.print(hour);
    lcd.setCursor(2,1);
    lcd.print(":");
    lcd.setCursor(3,1);
    lcd.print(minute);
    lcd.setCursor(5,1);
    lcd.print(":");
    lcd.setCursor(6,1);
    lcd.print(second);

    delay(500);
}

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

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

// Gets the date and time from the ds1307 and prints result
void getDateDs1307()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x00);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(Wire.receive() & 0x7f);
  minute     = bcdToDec(Wire.receive());
  hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(Wire.receive());
  dayOfMonth = bcdToDec(Wire.receive());
  month      = bcdToDec(Wire.receive());
  year       = bcdToDec(Wire.receive());
}

If I leave the Serial.print statements in the code and comment out everything BUT the instantiation of the LCD instance (“LiquidCrystal lcd(12, 11, 5, 4, 3, 2);”) then the code ceases to function.

Here is the schematic you’ve asked for:

OK, now you've shuffled some things around and you can repeat the same tests.
Does the LCD driver work by itself (as in the previous occasion). If so - does adding the DS1307 driver make things worse?
Because now you show the opposite behavior than before - the clock working, and adding the LCD "sends things south".
The connections seem OK to me.
I would check if the drivers in their initialization parts make some strange assumptions and initialize other ports and pins than the ones they need. Also if some strange and long delays are used.

Yes the LCD works by itself (Tested by running the "Hello World" LCD Example while the DS1307 hardware was still hooked up). It seems as though Wire.h and LiquidCrystal.h have some contention that doesn't allow them to play nicely together. You'd think it wouldn't be uncommon to use them together.

I for sure did something like that in my first Arduino attempts. I had ds1307, character LCD, a temperature sensor and a buzzer in one big mess of wires and soldered components. It worked though and I did not have those problems. But it was back at the times of Arduino 011, and AFAIK some of the libraries changed a bit.
I will try to dig out the DS1307 library and send it to you, so you can check it. The LCD library is more mainstream and I hope it it not the cause.
What happens if you only have wire.h included and the LCD routines?

It's fine with that as long as you don't actually use anything from it. I think that might be because the compiler optimizes out dead-end code.

Hello G_Man,

I got the parallel LCD yesterday and had same problems as you´re describing, regarding using it with DS1307 chip/library.

I really dont know what I did but got it to work right now.
Sounded absolutely random to me like if it just starts working. Anyway, i had same problem and read in some portuguese forum another guy with same issue so i think we must sort things out, really.

Please test the RTC + LCD with this code:

#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>
#include <LiquidCrystal.h>
 

 int hourT;
int minuteT;
int secondT;
int dayT;
int monthT;
int yearT;
char hourS[5];
char minuteS[5];
char secondS[5];
char dayS[5];
char monthS[5];
char yearS[5];
char alldate[60];
char allhour[60];
char te[4] ;

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


void setup()
{
 // Wire.begin();
  Serial.begin(9600);
  lcd.begin(16, 2);

 RTC.stop();
  RTC.set(DS1307_SEC,1);        //set the seconds
  RTC.set(DS1307_MIN,23);     //set the minutes
  RTC.set(DS1307_HR,12);       //set the hours
  RTC.set(DS1307_DOW,4);       //set the day of the week
  RTC.set(DS1307_DATE,5);       //set the date
  RTC.set(DS1307_MTH,3);        //set the month
  RTC.set(DS1307_YR,9);         //set the year
  RTC.start(); 

  
}


void loop() { 
 
strcpy(allhour, "");
  strcpy(alldate, ""); 
  
hourT = (RTC.get(DS1307_HR,true)) ;
minuteT = (RTC.get(DS1307_MIN,false)) ;
secondT = (RTC.get(DS1307_SEC,false));
dayT = (RTC.get(DS1307_DATE,false));
monthT = (RTC.get(DS1307_MTH,false));
yearT = (RTC.get(DS1307_YR,false));
itoa(hourT, hourS, 10);
itoa(minuteT, minuteS, 10);
itoa(secondT, secondS, 10);
itoa(dayT, dayS, 10);
itoa(monthT, monthS, 10);
itoa(yearT, yearS, 10);
if (strlen(hourS) < 2) { char te[4] = "0" ; strcat(te, hourS);  strcpy (hourS, te); }
if (strlen(minuteS) < 2) { char te[4] = "0" ; strcat(te, minuteS);  strcpy (minuteS, te); }
if (strlen(secondS) < 2) { char te[4] = "0" ; strcat(te, secondS);  strcpy (secondS, te); }
if (strlen(dayS) < 2) { char te[4] = "0" ; strcat(te, dayS);  strcpy (dayS, te); }
if (strlen(monthS) < 2) { char te[4] = "0" ; strcat(te, monthS);  strcpy (monthS, te); } 
 
strcat(allhour, hourS) ; strcat(allhour, ":"); strcat(allhour, minuteS); strcat(allhour, ":"); strcat(allhour, secondS);
strcat(alldate, dayS) ; strcat(alldate, "/"); strcat(alldate, monthS); strcat(alldate, "/"); strcat(alldate, yearS);
 
lcd.setCursor(0, 0);
lcd.print(alldate);
lcd.setCursor(0, 1);
lcd.print(allhour);

}

Maybe the order you invoke the libraries at the beginning of the code makes the difference?

Well, im excited to know if it will work for you with this code because i need an reliable setup and like to discover what it´s causing the issue. I hope it´s not just random.

Good luck,

Rodrigo

----EDITED-----

Another actually working example with the LCD, DS1307 and 24c256 on the bus. It show time and date recording photoresistor values in the EEPROM.

#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>
#define EEPROM_ADDR 0x50
#include <LiquidCrystal.h>


 int hourT;
int minuteT;
int secondT;
int dayT;
int monthT;
int yearT;
char hourS[5];
char minuteS[5];
char secondS[5];
char dayS[5];
char monthS[5];
char yearS[5];
char alldate[60];
char allhour[60];
char te[4] ;
long previousMillis = 0;
long interval = 1000;
long interval2 = 120000 ;
long previousMillis2 = 0;
int kk = 0;
int lightPin = 1;  

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


void setup()
{
 // Wire.begin();
  Serial.begin(9600);
  lcd.begin(16, 2);

 

  
}


void loop() {
if ((millis() - previousMillis > interval)) {
    // save the last time you blinked the LED 
    previousMillis = millis(); 
strcpy(allhour, "");
  strcpy(alldate, "");
  
hourT = (RTC.get(DS1307_HR,true)) ;
minuteT = (RTC.get(DS1307_MIN,false)) ;
secondT = (RTC.get(DS1307_SEC,false));
dayT = (RTC.get(DS1307_DATE,false));
monthT = (RTC.get(DS1307_MTH,false));
yearT = (RTC.get(DS1307_YR,false));
itoa(hourT, hourS, 10);
itoa(minuteT, minuteS, 10);
itoa(secondT, secondS, 10);
itoa(dayT, dayS, 10);
itoa(monthT, monthS, 10);
itoa(yearT, yearS, 10);
if (strlen(hourS) < 2) { char te[4] = "0" ; strcat(te, hourS);  strcpy (hourS, te); }
if (strlen(minuteS) < 2) { char te[4] = "0" ; strcat(te, minuteS);  strcpy (minuteS, te); }
if (strlen(secondS) < 2) { char te[4] = "0" ; strcat(te, secondS);  strcpy (secondS, te); }
if (strlen(dayS) < 2) { char te[4] = "0" ; strcat(te, dayS);  strcpy (dayS, te); }
if (strlen(monthS) < 2) { char te[4] = "0" ; strcat(te, monthS);  strcpy (monthS, te); }

strcat(allhour, hourS) ; strcat(allhour, ":"); strcat(allhour, minuteS); strcat(allhour, ":"); strcat(allhour, secondS);
strcat(alldate, dayS) ; strcat(alldate, "/"); strcat(alldate, monthS); strcat(alldate, "/"); strcat(alldate, yearS);

lcd.setCursor(0, 0);
lcd.print(alldate);
lcd.setCursor(0, 1);
lcd.print(allhour);
}

if ((millis() - previousMillis2 > interval2)) {
    
    previousMillis2 = millis();

i2c_eeprom_write_byte(EEPROM_ADDR,kk,analogRead(lightPin));
Serial.println(analogRead(lightPin));

kk++;
lcd.setCursor(0, 0);
lcd.print("RECORDED==== "); lcd.print(kk);
lcd.setCursor(0, 1);
lcd.print("RECORDED==== "); lcd.print(kk);
delay(10000);
}

}



//////////////////// EEPROM /////////////////
 void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
 int rdata = data;
 Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddress >> 8));    // Address High Byte
 Wire.send((int)(eeaddress & 0xFF));  // Address Low Byte
 Wire.send(rdata);
 Wire.endTransmission();
}

/// NOT USED IN loop() //////
// Address is a page address, 6-bit (63). More and end will wrap around
// But data can be maximum of 28 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
 Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddresspage >> 8)); // Address High Byte
 Wire.send((int)(eeaddresspage & 0xFF)); // Address Low Byte
 byte c;
 for ( c = 0; c < length; c++)
   Wire.send(data[c]);
 Wire.endTransmission();
 delay(10);                           // need some delay
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
 byte rdata = 0xFF;
 Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddress >> 8));    // Address High Byte
 Wire.send((int)(eeaddress & 0xFF));  // Address Low Byte
 Wire.endTransmission();
 Wire.requestFrom(deviceaddress,1);
 if (Wire.available()) rdata = Wire.receive();
 return rdata;
}

/// NOT USED IN loop() //////
// should not read more than 28 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
 Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddress >> 8));    // Address High Byte
 Wire.send((int)(eeaddress & 0xFF));  // Address Low Byte
 Wire.endTransmission();
 Wire.requestFrom(deviceaddress,length);
 //int c = 0;
 for ( int c = 0; c < length; c++ )
   if (Wire.available()) buffer[c] = Wire.receive();
}
////////////////////// EEPROM /////////////////

Sorry, no joy. The code you posted does not work. It produces a row of grey blocks on the first line of the LCD.