DS1307 RTC help :)

Hey guys!

I have my LCD clock and sensor temperature working fine.

However, I don't know how the DS1307 RTC really works, so I have a couples questions:

1 - If I increase the day by one, does the weekday also increases by one?

2 - Does this RTC knows when a month has 28/29/30/31 days?

3 - Does the RTC knows when the year is leap (bissextile).

4 - Finally, if all the above are true, do I need to add anything else on my code so it works like a real calendar/clock?

Regarding the manual setup up of the clock... How can I do it? I am thinking in 2 pushbuttons but how do I code it?

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include <LiquidCrystal.h>
#include "RTClib.h"

RTC_DS1307 RTC;

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

byte graus[8] = {
  0b01110,
  0b10001,
  0b10001,
  0b01110,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

int pin=0; // analog pin
long int temp=0, Vin=0, k=0;
long double samples[20];
long double min = (-424.0/6.25);


void setup () 
{
  Serial.begin(57600);
  Wire.begin();
  RTC.begin();
  lcd.begin(16, 2);   
  lcd.createChar(0, graus);
  analogReference(INTERNAL);

  if (! RTC.isrunning()) 
  {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }  
  
}


void loop () {
  DateTime now = RTC.now();
  lcd.home();    

  if (now.hour() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.hour(), DEC); 
    lcd.print(':');
  }
  else
  {
    lcd.print(now.hour(), DEC); 
    lcd.print(':');
  }

  if (now.minute() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.minute(), DEC); 
    lcd.print(':');
  }
  else
  {
    lcd.print(now.minute(), DEC); 
    lcd.print(':');
  }

  if (now.second() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.second(), DEC);
  }  
  else {
    lcd.print(now.second(), DEC);
  }


  lcd.setCursor(0,1);

  if (now.day() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.day(), DEC); 
    lcd.print('/');
  }
  else
  {
    lcd.print(now.day(), DEC); 
    lcd.print('/');
  }

  if (now.month() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.month(), DEC); 
    lcd.print('/');
  }
  else
  {
    lcd.print(now.month(), DEC); 
    lcd.print('/');
  }

  lcd.print(now.year(), DEC); 

  lcd.setCursor(12, 1);
  if (now.dayOfWeek() == 0)
    lcd.print("Sun");

  if (now.dayOfWeek() == 1)
    lcd.print("Mon");  

  if (now.dayOfWeek() == 2)
    lcd.print("Tue"); 

  if (now.dayOfWeek() == 3)
    lcd.print("Wed"); 

  if (now.dayOfWeek() == 4)
    lcd.print("Thu"); 

  if (now.dayOfWeek() == 5)
    lcd.print("Fri"); 

  if (now.dayOfWeek() == 6)
    lcd.print("Sat"); 


  for(k=0 ; k<=19 ; k++)
  {
    samples[k] = (analogRead(pin)*(1100/1088));
    Vin = Vin + samples[k];
    delay(2);
  }

  temp = (Vin/20 /1024.0 * 1088.0 / 6.25) + min;

  if (temp >=0 & temp <=9)
  {
    lcd.setCursor(11, 0);
    lcd.print("  "); 
    lcd.print(temp, DEC);    
  }

  if (temp >=10 & temp <=99)
  {
    lcd.setCursor(11, 0);
    lcd.print(" "); 
    lcd.print(temp, DEC);
  }

  if (temp >=100 & temp <=150)
  {
    lcd.setCursor(11, 0); 
    lcd.print(temp, DEC);
  }

  if (temp >=-9 & temp <=-1)
  {
    lcd.setCursor(11, 0);
    lcd.print(" "); 
    lcd.print(temp, DEC);
  }

  if (temp >=-99 & temp <=-10)
  {
    lcd.setCursor(11, 0);
    lcd.print(temp, DEC);
  }

  lcd.setCursor(14, 0);
  lcd.write((uint8_t)0);
  lcd.print("C");

 
  Vin=0;
  temp = 0;
  k=0;

  delay(200); 
  
}

The datasheet for the DS1307 is here - Mixed-signal and digital signal processing ICs | Analog Devices

Basically, the answer to your questions is yes.

Real-Time Clock (RTC) Counts Seconds, Minutes, Hours, Date of the Month, Month, Day of the week, and Year with Leap-Year Compensation Valid Up to 2100

KenshinPT:
1 - If I increase the day by one, does the weekday also increases by one?

2 - Does this RTC knows when a month has 28/29/30/31 days?

3 - Does the RTC knows when the year is leap (bissextile).

4 - Finally, if all the above are true, do I need to add anything else on my code so it works like a real calendar/clock?

Regarding the manual setup up of the clock... How can I do it? I am thinking in 2 pushbuttons but how do I code it?

1-Yes, 2-Yes, 3-Yes. 4-Depends on how you want it to work. Turns out that setting the time may be the tougher part, IMHO! I might start with more than two buttons. It's worth it to first write down and maybe draw some pictures of how the buttons would work. Consider, both the time and the date (including the year) need to be set. If it's an alarm clock, another button or two may be needed.

Thank you so much for your help!! :slight_smile:

Regarding the manual set-up, I think I know how to do it... but the problem is that I don't know which variable I should increment?

I tried:

if (button is pressed)
{
debounce();
now.day++;
}

But this wont work... I think the problem relies on the variable to change: seconds, minutes, days...

Thanks you so much for your help

Happy new year 2012 of coding :stuck_out_tongue:

After each button press, you'll need to construct a DateTime value, then call RTC.adjust().

dxw00d:
After each button press, you'll need to construct a DateTime value, then call RTC.adjust().

Great! I got it and it's working. Thanks :slight_smile:

Now, I have two more questions - sorry :slight_smile:

1 a)- When I do this: ABCD%1000 the result is always CD, right? I am asking this because I don't won't to display 4 digits of the year. I just want the last 2 digits.

1 b) However, when the year is 2100, the result is 100, right? Is there any efficient way to solve this problem? That is, when year is 2100, the result should be 00.

2 - When I set up manually the date I can have like 62 minutes or 75 seconds or 25 hours... I thought the RCT was smarter. Does this mean that I have do code something to roll over when the hour digit reachs 23 and rolls to 00.

When I do this: ABCD%1000 the result is always CD, right?

Wrong. The result is always BCD. If you change 1000 to 100, the result will be CD.

However, when the year is 2100, the result, 100, right? Is there any efficient way to solve this problem? That is, when year is 2100, the result should be 00.

Sure. See above.

Does this mean that I have do code something to roll over when the hour digit reachs 23 and rolls to 00.

The answer to that seems pretty obvious, doesn't it?

PaulS:

When I do this: ABCD%1000 the result is always CD, right?

Wrong. The result is always BCD. If you change 1000 to 100, the result will be CD.

However, when the year is 2100, the result, 100, right? Is there any efficient way to solve this problem? That is, when year is 2100, the result should be 00.

Sure. See above.

Does this mean that I have do code something to roll over when the hour digit reachs 23 and rolls to 00.

The answer to that seems pretty obvious, doesn't it?

Thanks! :slight_smile:

Step by step I am getting the clock/calendar working smoothly :slight_smile:

However, I found something that must be solved:

When I try to set any of the clock/date parameters the clock freezes... that is, if I press the pushbuttom to set the year for 5 seconds, after releasing it, the clock has stopped for 5 seconds :fearful:

 if (digitalRead(buttonPin) == 1)
  {
    {
      RTC.adjust(DateTime(now.year()+1,now.month(),now.day(),now.hour(),now.minute(),now.second()));
    }
  }

}

After solving this problem I'll add a debounce for the pushbuttom :grin:

After solving this problem I'll add a debounce for the pushbuttom

No, you've got the steps in the wrong order. Stop the button from bouncing, and you may not have the other problem.

Post all of your code, too. It's impossible to tell what you are doing wrong with just that snippet.

PaulS:

After solving this problem I'll add a debounce for the pushbuttom

No, you've got the steps in the wrong order. Stop the button from bouncing, and you may not have the other problem.

Post all of your code, too. It's impossible to tell what you are doing wrong with just that snippet.

Hey, thanks for the help.

The code is here:

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include <LiquidCrystal.h>
#include "RTClib.h"

RTC_DS1307 RTC;

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

byte graus[8] = {
  0b01110,
  0b10001,
  0b10001,
  0b01110,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

int pin=0; // analog pin
long int temp=0, Vin=0, k=0;
long double samples[20];
long double min = (-424.0/6.25);

const int buttonPin = 10;     // the number of the pushbutton pin

void setup () 
{
  Serial.begin(57600);
  Wire.begin();
  RTC.begin();
  lcd.begin(16, 2);   
  lcd.createChar(0, graus);
  analogReference(INTERNAL);

  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);  

  if (! RTC.isrunning()) 
  {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }  

}

void loop () {
  DateTime now = RTC.now();
  lcd.home();    

//Print time on LCD
  if (now.hour() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.hour(), DEC); 
    lcd.print(':');
  }
  else
  {
    lcd.print(now.hour(), DEC); 
    lcd.print(':');
  }

  if (now.minute() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.minute(), DEC); 
    lcd.print(':');
  }
  else
  {
    lcd.print(now.minute(), DEC); 
    lcd.print(':');
  }

  if (now.second() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.second(), DEC);
  }  
  else {
    lcd.print(now.second(), DEC);
  }


//Print date on LCD
  lcd.setCursor(0,1);

  if (now.day() < 10)
  {
    lcd.print('0'); 
    lcd.print(now.day(), DEC); 
    lcd.print('/');
  }
  else
  {
    lcd.print(now.day(), DEC); 
    lcd.print('/');
  }


  switch(now.month())
  {
    case 1:lcd.print("Jan/"); break;     
    case 2:lcd.print("Feb/"); break;
    case 3:lcd.print("Mar/"); break;
    case 4:lcd.print("Apr/"); break;
    case 5:lcd.print("May/"); break;
    case 6:lcd.print("Jun/"); break;
    case 7:lcd.print("Jul/"); break;
    case 8:lcd.print("Aug/"); break;     
    case 9:lcd.print("Sep/"); break;
    case 10:lcd.print("Oct/"); break;
    case 11:lcd.print("Nov/"); break;
    case 12:lcd.print("Dec/"); break;
    default:lcd.print("Err/");
  }

  lcd.print(now.year(), DEC); 
 
//Print weekday on LCD
  lcd.setCursor(13, 1);
  switch(now.dayOfWeek())
  {
    case 0:lcd.print("Sun"); break;     
    case 1:lcd.print("Mon"); break;
    case 2:lcd.print("Tue"); break;
    case 3:lcd.print("Wed"); break;
    case 4:lcd.print("Thu"); break;
    case 5:lcd.print("Fri"); break;
    case 6:lcd.print("Sat"); break;
    default:lcd.print("Err");
  }

  for(k=0 ; k<=19 ; k++)
  {
    samples[k] = (analogRead(pin)*(1100/1088));
    Vin = Vin + samples[k];
    delay(2);
  }

  temp = (Vin/20 /1024.0 * 1088.0 / 6.25) + min;

  if (temp >=0 & temp <=9)
  {
    lcd.setCursor(11, 0);
    lcd.print("  "); 
    lcd.print(temp, DEC);    
  }

  if (temp >=10 & temp <=99)
  {
    lcd.setCursor(11, 0);
    lcd.print(" "); 
    lcd.print(temp, DEC);
  }

  if (temp >=100 & temp <=150)
  {
    lcd.setCursor(11, 0); 
    lcd.print(temp, DEC);
  }

  if (temp >=-9 & temp <=-1)
  {
    lcd.setCursor(11, 0);
    lcd.print(" "); 
    lcd.print(temp, DEC);
  }

  if (temp >=-99 & temp <=-10)
  {
    lcd.setCursor(11, 0);
    lcd.print(temp, DEC);
  }

  lcd.setCursor(14, 0);
  lcd.write((uint8_t)0);
  lcd.print("C");

  Vin=0;
  temp = 0;
  k=0;

  delay(250); 

  if (digitalRead(buttonPin) == 1)
  {
    {
      RTC.adjust(DateTime(now.year(),now.month()+1,now.day(),now.hour(),now.minute(),now.second()));
    }
  }

}
    samples[k] = (analogRead(pin)*(1100/1088));

1100/1088 = 1. Is this necessary? 1100.0/1088.0 (= 1.011) might be.

Why are you storing an array of doubles, when the array is never used again? Why are you storing ints in a double array?

Putting the code to show the time and date in a function would greatly shorten loop(), to make it easier to follow.

  delay(250); 

  if (digitalRead(buttonPin) == 1)
  {
    {
      RTC.adjust(DateTime(now.year(),now.month()+1,now.day(),now.hour(),now.minute(),now.second()));
    }
  }

Every 1/4 of a second (plus the time it takes to do all the other stuff in loop), you see if it is necessary to update the month, and, if it is, set the time 1/4 of a second (plus) late. Why? now was a snapshot of the time at the start of loop(). You should get the current time again, just before adjusting it.

PaulS:

    samples[k] = (analogRead(pin)*(1100/1088));

1100/1088 = 1. Is this necessary? 1100.0/1088.0 (= 1.011) might be.

It's a correction factor for the thermometer. My Vref is 1088mV and not 1100mV. Is this the right thing to do?

PaulS:
Why are you storing an array of doubles, when the array is never used again? Why are you storing ints in a double array?

It was once used but then I changed the code and I forgot to change de declaration of "samples" variable. So, you're right :slight_smile:

PaulS:
Putting the code to show the time and date in a function would greatly shorten loop(), to make it easier to follow.

I'll do that for sure. This is in version Beta 0.1 :stuck_out_tongue:

PaulS:

  delay(250); 

if (digitalRead(buttonPin) == 1)
  {
    {
      RTC.adjust(DateTime(now.year(),now.month()+1,now.day(),now.hour(),now.minute(),now.second()));
    }
  }



Every 1/4 of a second (plus the time it takes to do all the other stuff in loop), you see if it is necessary to update the month, and, if it is, set the time 1/4 of a second (plus) late. Why? now was a snapshot of the time at the start of loop(). You should get the current time again, just before adjusting it.

Got it :slight_smile: Thanks for the tip

It's a correction factor for the thermometer. My Vref is 1088mV and not 1100mV. Is this the right thing to do?

A correction factor of (1100/1088 =) 1 seems useless. A correction factor of 1100.0/1088.0 (= 1.011) might be.

PaulS:

It's a correction factor for the thermometer. My Vref is 1088mV and not 1100mV. Is this the right thing to do?

A correction factor of (1100/1088 =) 1 seems useless. A correction factor of 1100.0/1088.0 (= 1.011) might be.

:fearful: Thanks! I totally forgot the floating point!!!

Is this particular to arduino IDE? I believe, and hope:), that when I do 1100/1088 in others C IDE/compilers the result is 1.011029411... or not?

for example:

(...)
double var;

var=1100/1088;

printf(%f, var);
(...)

What do I get on my screen? :roll_eyes:

1100 and 1088 are integer constants, as defined by the language spec, so 1100/1088 is an integer calculation. A standards compliant c compiler should give the result of 1.

On my mac...

davidwood$ cat test.c 
#include <stdio.h>

int main()
{
  double var;

  var=1100/1088;

  printf("%f\n", var);
}
davidwood$ cc test.c 
davidwood$ ./a.out 
1.000000
davidwood$ cc -v
Using built-in specs.
Target: i686-apple-darwin11
Configured with: /private/var/tmp/llvmgcc42/llvmgcc42-2336.1~1/src/configure --disable-checking --enable-werror --prefix=/Developer/usr/llvm-gcc-4.2 --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-prefix=llvm- --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin11 --enable-llvm=/private/var/tmp/llvmgcc42/llvmgcc42-2336.1~1/dst-llvmCore/Developer/usr/local --program-prefix=i686-apple-darwin11- --host=x86_64-apple-darwin11 --target=i686-apple-darwin11 --with-gxx-include-dir=/usr/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)