0

I am missing something fundamental using RTClib.
When I use the rtc.adjust function to change the time in the RTC, I cannot get the updated time from the RTC, just increments a fixed time. I have searched for examples for what I need, and the same few samples of code keep getting quoted.

I want my code to set the RTC at compile to the system time, which it does, then in the Loop I want to increment the hour. In reality I will use a button for this, but for now I am just trying to understand how DateTime now = rtc.now and rtc.adjust work. How to write to the RTC, how to read it back. I am missing something regarding these variables.

Two version of my code. One with output showing the clock working, and one where the output is static, just increments the hour.

This one works:

#include <RTClib.h>
#include <Wire.h>
int ArduinoHour;
int ArduinoMin;
int ArduinoSec;
RTC_DS1307 rtc;

void setup()
{
  Serial.begin(250000);
  Wire.begin();  //sets up the I2C
  rtc.begin();   //initializes the I2C to the RTC

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
  }
    if (rtc.isrunning()) {
    Serial.println("RTC IS running!");
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
}
void loop()
{
  DateTime now = rtc.now(); // pings RTC and loads time info into the now variable.

  ArduinoHour = now.hour();
  ArduinoMin = now.minute();
  ArduinoSec = now.second();

  Serial.print("AT TOP");
  Serial.println();
  Serial.print("RTC Time");
  Serial.println();
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
  Serial.println();
  delay(1000);

  Serial.print("Arduino Time");
  Serial.println();
  Serial.print(ArduinoHour, DEC);
  Serial.print(':');
  Serial.print(ArduinoMin, DEC);
  Serial.print(':');
  Serial.print(ArduinoSec, DEC);
  Serial.println();
  Serial.println();
  delay(1000);

  //RTC increments when these are commented out. Does not when active
  //ArduinoHour = ArduinoHour +1;
  //rtc.adjust(DateTime(now.year(),now.month(),now.day(),ArduinoHour,ArduinoMin,ArduinoSec));

}

Here is the output. Looks fine:

RTC IS running!
AT TOP
RTC Time
11:38:3

Arduino Time
11:38:3

AT TOP
RTC Time
11:38:5

Arduino Time
11:38:5

AT TOP
RTC Time
11:38:7

Arduino Time
11:38:7

AT TOP
RTC Time
11:38:9

Arduino Time
11:38:9 

This one does not Work: Now I try to simply increment variable ArduinoHour and then write it to the RTC using rtc.adjust. The only change are the two lines at the bottom are uncommented.

#include <RTClib.h>    //https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/understanding-the-code
#include <Wire.h>

int ArduinoHour;
int ArduinoMin;
int ArduinoSec;

RTC_DS1307 rtc;

void setup()
{
  Serial.begin(250000);
  Wire.begin();  //sets up the I2C
  rtc.begin();   //initializes the I2C to the RTC

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
  }
    if (rtc.isrunning()) {
    Serial.println("RTC IS running!");
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
}

void loop()
{
  DateTime now = rtc.now(); // pings RTC and loads time info into the now variable.

  ArduinoHour = now.hour();
  ArduinoMin = now.minute();
  ArduinoSec = now.second();

  Serial.print("AT TOP");
  Serial.println();
  Serial.print("RTC Time");
  Serial.println();
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
  Serial.println();
  delay(1000);

  Serial.print("Arduino Time");
  Serial.println();
  Serial.print(ArduinoHour, DEC);
  Serial.print(':');
  Serial.print(ArduinoMin, DEC);
  Serial.print(':');
  Serial.print(ArduinoSec, DEC);
  Serial.println();
  Serial.println();
  delay(1000);

  //RTC increments when these are commented out
  ArduinoHour = ArduinoHour +1;
  rtc.adjust(DateTime(now.year(),now.month(),now.day(),ArduinoHour,ArduinoMin,ArduinoSec));

}

Here is the output, RTC time is not changing. I know I am doing something basically wrong with how I am updating the variables writing/reading from the RTC. Can't figure it out.

RTC IS running!
AT TOP
RTC Time
11:41:54

Arduino Time
11:41:54

AT TOP
RTC Time
12:41:54

Arduino Time
12:41:54

AT TOP
RTC Time
13:41:54

Arduino Time
13:41:54

AT TOP
RTC Time
14:41:54

Arduino Time
14:41:54 
0

If by "RTC time is not changing" you mean minutes and seconds frozen at the same value, then this is entirely of your doing.

Your sketch spends 99% of the time between the initial rtc.now() request

 DateTime now = rtc.now(); // pings RTC and loads time info into the now variable.

and the final rtc.adjust() call

rtc.adjust(DateTime(now.year(),now.month(),now.day(),ArduinoHour,ArduinoMin,ArduinoSec));

This period is the period when your RTC is supposed to be "ticking", progressing forward.

But you actually store the original minutes and seconds values in ArduinoMin and ArduinoSec at the beginning of this period. And later, at the end of this period, you bash these values back into the clock. By doing this you forcefully erase whatever progress the clock made between these two lines. No wonder your minutes and second do not change.

This problem actually has no perfect solution. RTC_DS1307 class (and, I suspect, the underlying RTC hardware) provide no means to change just the hours value without disrupting minutes and seconds. When you call adjust(), you have to set everything, which means that you will always somehow "disrupt" the whole clock.

In your sketch you can minimize the adverse effects by re-requesting the minutes and seconds values right before doing adjust():

//RTC increments when these are commented out
ArduinoHour = ArduinoHour +1;
now = rtc.now(); 
rtc.adjust(DateTime(now.year(), now.month(), now.day(), ArduinoHour, now.minute(), now.second()));

Note, that I'm using your updated ArduinoHour values, but everything else comes from a just-refreshed now object.

This is still not perfect, since it still suffers from a race condition against a real-time clock, but it is better than what you had originally.

  • @ AnT - Thank you. That perfectly explains it. – RickH May 18 at 22:50
  • @AnT, there is a suggested edit, which moves ArduinoHour = ArduinoHour +1; after now = rtc.now();. should it be accepted? – Juraj May 22 at 14:07
  • @Juraj: I don't see why. The whole idea of the workaround is to place the second now = rtc.now(); call as close as possible to the rtc.adjust call - in order to minimize the time "lost" between these actions. Moving the ArduinoHour = ArduinoHour + 1; after now = rtc.now(); (for what reason?) goes against that idea. – AnT May 22 at 14:09
  • Sorry, it was my mistake. My edits has nothing useful, sorry again. – Alexander May 22 at 14:35
0

This is the content of ajust method:

void RTC_DS1307::adjust(const DateTime& dt) {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE((byte)0); // start at location 0
  Wire._I2C_WRITE(bin2bcd(dt.second()));
  Wire._I2C_WRITE(bin2bcd(dt.minute()));
  Wire._I2C_WRITE(bin2bcd(dt.hour()));
  Wire._I2C_WRITE(bin2bcd(0));
  Wire._I2C_WRITE(bin2bcd(dt.day()));
  Wire._I2C_WRITE(bin2bcd(dt.month()));
  Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  Wire.endTransmission();
}

You can write new Hour value directly to the clock without erasing other clock data:

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE((byte)2); // Hour location
  Wire._I2C_WRITE(bin2bcd(ArduinoHour));
  Wire.endTransmission();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.