RTC DS1307 - Am I writing/reading to/from this device?

I don't believe I am accessing the RTC DS1307 but rather addressing the UNO and reading its "own clock".
I say this because I can "setTime" (in setup) and display the time correctly for hours, BUT, if I reset the UNO the time resorts back to my original "setTime" value.

I chose DS1302RTC.h because I believe that I can manipulate time elements individually.

I don't think the RTC has made any contribution to my sketch!

I have included relevant code segments:

/*
 * These are snippets from my (LONG) sketch, I have only included the relevant RTC sections.
 */
#include <Wire.h>                     
#include <Time.h>
#include <DS1307RTC.h>

// ----------------------------------------------------------------------------
void setup(void) {
  delay(500);

// Manual RTC set
// uncomment to setTime & RTC.set(now()  for first time download - hrs and mins only! 
// format is: setTime(hour(),minute(),second(),day(),month(), year());
  setTime(8,17,1,1,1, 1);            // only interested in HH MM
  RTC.set(now());                    // sending the onboard time to the RTC
// !!! this updates my TFTLCD display correctly with 08:17

if (time_t timeNow = now())
  { tft.println("                RTC success!");}
  else
   {tft.setTextColor(RED); 
    tft.println("                RTC failed!");}
// !!! never fails?

// ----------------------------------------------------------------------------
void loop(void) 
 {  
   CheckButtons();                           // check time adjust buttons every 500mS
        
   if (LoopTick > 0)                         // test 1 minute timer
    {LoopTick --;}
   if (LoopTick == 0)
   { TFTupdate();                            // update display every minute
     LoopTick = 120;
   }
    delay(500);                              // 120 x 500mS = 1 minute
  }
// !!! No apparent problem

// ----------------------------------------------------------------------------
 // Update display every minute
 void TFTupdate()
 {   
    time_t timeNow = now(); 
    
    tft.fillScreen(BLACK);
    tft.setCursor(0, 50);
    tft.setFont(&FreeSansBold18pt7b);
    tft.setTextSize(2);
    tft.print("   ") ;
    if (hour(timeNow) < 10)
      {tft.print(" ");}                        // leading space for hours
    tft.print(hour(timeNow), DEC);
    tft.print(":") ;    
    if (minute(timeNow) < 10)
      {tft.print("0");}                         // leading 0 for minutes
    tft.print(minute(timeNow), DEC); 
 }
// !!! Display updates correctly

// ----------------------------------------------------------------------------
   void CheckButtons()
  {
    time_t timeNow = now();
    uint8_t NewHr = hour(timeNow);
    uint8_t NewMn = minute(timeNow);
    
    if (digitalRead(But_Hrs) == LOW)              // read Hour adj
      { NewHr ++;
        setTime(NewHr, minute(), 1, 1, 1, 1);
        RTC.set(now());
        LoopTick = 1;                             // 0,5 secs to restore display
      }
    if (digitalRead(But_Mins) == LOW)             // read Min adj   
      { NewMn ++;
        setTime(hour(), NewMn, 1, 1, 1, 1);
        RTC.set(now());
        LoopTick = 1;                              // 0,5 secs to restore display
      }           
  }
// !!! Display updates correctly

I have searched far and wide and often find examples which can't even compile!
e.g. DS1302RTC.h/example/setTime.ino fails on 'tmElements_t' does not name a type.

Some examples switch between Time.h and TimeLib.h for one reason or the other.

My wife has threatened to trade me in if I lose any more hair! If you recognize my problem, please assist.

You might be using old or mismatched versions of the DS1307RTC and Time libraries, see the note about newer versions on the Arduino Playground .

I followed the links there, then on to GitHub for the libraries and can confirm that the SetTime example compiles for an Uno.

  setTime(8, 17, 1, 1, 1, 1);        // only interested in HH MM
  RTC.set(now());                    // sending the onboard time to the RTC

Every time you execute this line of code you set the time to the same value.

Run the program then comment out these 2 lines then compile and upload the program again.

I don't believe I am accessing the RTC DS1307 but rather addressing the UNO and reading its "own clock".

Correct. You are only reading the time with time library commands, and never directly access the rtc memory.

You can use setSyncProvider(RTC.get) to link the time library internal clock with the RTC. See the time library example "TimeRTC".

Alternatively, you can directly read the RTC time using the syntax of the DS1307 library. See the DS1307 library example "Read Test".

Here is the code I use to read the date and time from the RTC.
The only library it uses is the Wire library which is already included with the Arduino software.

This should print the date and time to the serial monitor. Remember to select the correct baud rate.
Note that I number the weekdays starting from 1 for Monday. Some people prefer to use 1 for Sunday.

#include <Wire.h>

byte ss=0, mi=0, hh=0, wd=6, dd=1, mo=1, yy=0;
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
 
  // clear /EOSC bit
  // Sometimes necessary to ensure that the clock
  // keeps running on just battery power. Once set,
  // it shouldn't need to be reset but it's a good
  // idea to make sure.
//  Wire.beginTransmission(0x68); // address DS3231
//  Wire.write(0x0E); // select register
//  Wire.write(0b00011100); // write register bitmap, bit 7 is /EOSC
//  Wire.endTransmission();
}
 
void loop()
{
  // ask RTC for the time
  // send request to receive data starting at register 0
  Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
  Wire.write((byte)0); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7); // request seven bytes (ss, mi, hh, wd, dd, mo, yy)
  // check for a reply from the RTC, and use it if we can
  if (Wire.available() >= 7) {
    // if we're here, we got a reply and it is long enough
    // so now we read the time
    ss = bcd2bin(Wire.read()); // get seconds
    mi = bcd2bin(Wire.read()); // get minutes
    hh = bcd2bin(Wire.read()); // get hours
    wd = bcd2bin(Wire.read());
    dd = bcd2bin(Wire.read());
    mo = bcd2bin(Wire.read());
    yy = bcd2bin(Wire.read());
    // show that we successfully got the time
    Serial.print("Got the time: ");
    printTime();
  }
  else {
    // if we're here, that means we were unable to read the time
    Serial.println("Unable to read time from RTC");
  }
  delay(500);
}

byte bcd2bin(byte x) {
  // converts from binary-coded decimal to a "regular" binary number
  return ((((x >> 4) & 0xF) * 10) + (x & 0xF)) ;
}

void printTime() {
  // just like it says on the tin
  Serial.print ("\'");
  if (yy<10) Serial.print("0"); Serial.print(yy,DEC); Serial.print("-");
  if (mo<10) Serial.print("0"); Serial.print(mo,DEC); Serial.print("-");
  if (dd<10) Serial.print("0"); Serial.print(dd,DEC); Serial.print("(");
  switch (wd) {
    case 1: Serial.print("Mon"); break;
    case 2: Serial.print("Tue"); break;
    case 3: Serial.print("Wed"); break;
    case 4: Serial.print("Thu"); break;
    case 5: Serial.print("Fri"); break;
    case 6: Serial.print("Sat"); break;
    case 7: Serial.print("Sun"); break;
    default: Serial.print("Bad");  
  }
  Serial.print(") ");
  if (hh<10) Serial.print("0"); Serial.print(hh,DEC); Serial.print(":");
  if (mi<10) Serial.print("0"); Serial.print(mi,DEC); Serial.print(":");
  if (ss<10) Serial.print("0"); Serial.print(ss,DEC); Serial.println("");
}

Gentlemen, thank you for your assistance.

I started with one suggestion "SyncProvider(RTC.get)" and I get my first error:
(relevant lines)

#include <Wire.h>                     // I2C
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
.
.
In void setup:
SyncProvider(RTC.get);
.
.
exit status 1
'SyncProvider' was not declared in this scope

I will explore this option for a while and will probably end up by byte bashing DS1307 registers.
I, being an ASM dinosaur, this is home ground for me!

I wish you guys would refer to the RTC IC as the RTC. The Arduino board IS NOT a Real Time Clock, it is, at best, an inaccurate emulation of a clock. My board "clock" has lost 3 minutes in 9 hours.

rayva:
I wish you guys would refer to the RTC IC as the RTC. The Arduino board IS NOT a Real Time Clock

Where did anyone refer to the Arduino itself as an RTC?

Pretty sure everyone knows that.

I started with one suggestion "SyncProvider(RTC.get)" and I get my first error:

You can use setSyncProvider(RTC.get) to link the time library internal clock with the RTC. See the time library example "TimeRTC".You can use setSyncProvider(RTC.get) to link the time library internal clock with the RTC. See the time library example "TimeRTC".

Only in your mind is SyncProvider(RTC.get) the same as setSyncProvider(RTC.get).

You were directed to library example code for reference. Instead of looking at that, you invented new syntax. People on this forum want to help you, but you must put in the basis work yourself.

Everywhere! Refer to all RTC classes and you may see where my confusion arises from.

rayva:
Everywhere! Refer to all RTC classes and you may see where my confusion arises from.

I would be interested in links to some examples.

Try this example:

setTime(19,22,0,14,9,2017);
RTC.set(now()); // sending the onboard time to the RTC.

Doesn't go any where near the IC. Note "RTC.set" is not, it is "board.set"

Dear Cattledog,

My apologies, my cut and paste did not include "set". Your suggestion works.

I will now figure out how to write to the RTC using SyncProvider. I haven't found a method yet but I will keep on trying.

Thank you for your help.

RTC.set(now());                    // sending the onboard time to the RTC.
Doesn't go any where near the IC. Note "RTC.set" is not, it is "board.set"

I can assure you that RTC.set(time_t t) is a DS1307.h command addressing the RTC chip. It t the takes the "unix" time stamp as an input, and that value is returned by the now() command which is part of the time library. It requires the wire library Wire.h to write to the chip.

Please provide an example which compiles and runs which demonstrates that RTC.set(now()) doesn't go anywhere near the IC.

The DS1307 library files and time library files are on your computer. It is always best to refer to them if there is confusion. File path in windows is

C:\Users\YOU\Documents\Arduino\libraries\DS1307RTC\DS1307RTC.cpp
C:\Users\YOU\Documents\Arduino\libraries\DS1307RTC\DS1307RTC.h

"Please provide an example which compiles and runs which demonstrates that RTC.set(now()) doesn't go anywhere near the IC."

#include <TimeLib.h> 
#include <Wire.h> 
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

void setup()  {

// First time upload, then comment next 2 lines out for subsequent uploads

  //setTime(10, 54, 0, 15, 9,2017);
  //RTC.set(now());             // manually send time to the RTC.
   
  Serial.begin(9600);
  Serial.print("Reboot  ");
  
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  
  if(timeStatus()!= timeSet)
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has fetched the system time");   
}

void loop()
{
   digitalClockDisplay(); 
   delay(60000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print("    ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

[b]Serial monitor:[/b]
Time set on first upload using:
setTime(10, 54, 0, 15, 9,2017);
RTC.set(now());                    // manually send time to the RTC.

[b]Extracts from Serial monitor log:[/b]

Reboot  RTC has fetched the system time
10:54:00    15 9 2017
10:55:00    15 9 2017
.
.
.
11:37:01    15 9 2017
11:38:01    15 9 2017


-------------------------------------------------
(Power reset, Upload shetch to start serial monitor. Lines below commented out 
 to to prevent a repeat of setTime
  //setTime(10, 54, 0, 15, 9,2017);
  //RTC.set(now());             // manually send time to the RTC

Reboot  RTC has fetched the system time
10:54:16    15 9 2017
10:55:16    15 9 2017
.
.
.
11:20:17    15 9 2017
11:21:17    15 9 2017


-------------------------------------------------
(Reset UNO)

Reboot  RTC has fetched the system time 
11:22:55    15 9 2017
11:23:55    15 9 2017
.
.
.
11:50:56    15 9 2017
11:51:56    15 9 2017

Please note that the removal of power will set the "clock" back to my original setTime

@rayva:

If you're still having trouble, you might want to try doing what I describe here:
http://forum.arduino.cc/index.php?topic=53422.msg2031756#msg2031756

It won't help you with the RTC libraries, but then again, those libraries are just a means to an end, and there is more than one means to that end.

I don't believe that your rtc is running under battery power. When I upload the sketch you provided and then comment out the two lines, my rtc will return the updated time with both a reset and a power removal. The fact that you return updated time with a reset and not a power removal indicates a battery problem.

Do you have a battery installed?Is the + facing out? Do you have a fresh battery to try? Are you using an rtc module? Can you provide a link. If you are using the chip in a circuit you have built, please provide a schematic.

Can also confirm that 3.3v is actually getting to the vbat pin of the ic. There can be defective battery holders and connections.

Here is a link to the ds1307 data sheet which will show the vbat pin
http://datasheets.maximintegrated.com/en/ds/DS1307.pdf

If there is actually voltage at the chip pin then its possible there is a defect with the chip or the oscillator.

@odometer
Thank you! :slight_smile: Your approach is direct and results are as expected. I am now reading the RTC IC registers and not some other "library" values. This works with board reset and with board power disconnection.

I still maintain that the "RTC" library functions are not actually doing what they implicate. The engineers should test these functions by disconnecting power and restarting.

I have extrapolated on your code to suit DS1307 where I have placed a test and initialization function in "setup" to start a raw RTC. Only secs, mins, hours included.

// Tribute to ODOMETER 
//http://forum.arduino.cc/index.php?topic=53422.msg2031756#msg2031756

#include "Wire.h"

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(500);

  CheckRTC();               // Initialise DS1307 RTC if neccesary
  
}

//------------------------------------------------------------------------------

void loop()
{
// send request to receive data starting at register 0
  Wire.beginTransmission(0x68);        // 0x68 is DS3231 device address
  Wire.write((byte)0);                     // start at register 0
  Wire.endTransmission();
  
  Wire.requestFrom(0x68, 3); // request 3 bytes (ss, mi, hr, wd, dd, mo, yy)
 
  while(Wire.available())
  { 
    byte ss = Wire.read();            // get seconds
    byte mi = Wire.read();            // get minutes
    byte hh = Wire.read();            // get hours

    if (hh<0x10) Serial.print("0"); Serial.print(hh,HEX); Serial.print(":");
    if (mi<0x10) Serial.print("0"); Serial.print(mi,HEX); Serial.print(":");
    if (ss<0x10) Serial.print("0"); Serial.print(ss,HEX); Serial.println("");    
  }
  delay(2000);
}

//------------------------------------------------------------------------------
// Check to see if RTC is running
void CheckRTC() {
  // enable RTC DS1307  ?  
  Wire.beginTransmission(0x68);      // address D1307
  Wire.write((byte)0);                   // select register 0
  Wire.endTransmission();   
  Wire.requestFrom(0x68, 1);
  byte RDr0 = Wire.read();            // read register 0 
  Wire.endTransmission(); 
  
  //RDr0 == RDr0 && 0x80;            // Mask b7
  if ( RDr0 & 0x80 )                      // test CH 
     { initRTC(); }                        // if hi, initialise RTC
  else {}
  }
   
// Set DS1307 RTC only if not initialised
  void initRTC()
  {
  delay(50);
  Wire.beginTransmission(0x68);     // address D1307
  Wire.write(0x00);                      // select register 0
  Wire.write(0x00);                      // clear CH OSC b7
  Wire.endTransmission();
  delay(50);
   
// enable 1Hz SqWave  
  Wire.beginTransmission(0x68);     // address D1307
  Wire.write(0x07);                      // select control register
  Wire.write(0x10);                      // set SQWE
  Wire.endTransmission();
  delay(500);
    
// set arbitrary time for initial start  
  Wire.beginTransmission(0x68);     // address DS3231
  Wire.write(0x00);                 // select register
  Wire.write(0x00);                 // seconds (BCD)
  Wire.write(0x00);                 // minutes (BCD)
  Wire.write(0x12);                 // hours (BCD)  
  Wire.endTransmission();
 }
//------------------------------------------------------------------------------
//EOF

Thank you for your invaluable assistance.

@ cattledog

I have been using DS1307 devices for at least 15 Years and have professionally produced many reliable products using this device. I am very familiar with the data sheets and battery polarities/voltages.

Using assembler, I have no problem with byte manipulation of registers and always achieve reliable results and performance, no matter what the power conditions may be.

However, I have a problem when using some library files, which in my opinion, appear to interfere with the true operation of the RTC. I have now resorted to byte manipulation (without RTC or time libraries) and I am, so far, achieving satisfactory results.

I thank you for your interest and input.