0

I ran into this while trying to make a battery monitor and wondered where I went wrong. Using RTClib available in the Arduino IDE or from adafruit github, I ran into problems when trying to call now within a while loop inside of loop. Here is a simple example:

#include "RTClib.h"

#define ledPIN 13

RTC_PCF8523 rtc;

void setup() {
  // put your setup code here, to run once:
  pinMode(ledPIN, OUTPUT);
  digitalWrite(ledPIN, LOW);
  Serial.begin(9600);
  while(!Serial) {/* wait for Serial */}
  rtc.begin();
  rtc.start();
  digitalWrite(ledPIN, HIGH);
 }

void loop() {
  // put your main code here, to run repeatedly:
  char fmt[] = "YYYY/MM/DD-hh:mm:ss\n";
  while (millis() < 60000){
    Serial.println((rtc.now()).toString(fmt));
    delay(5000); 
  }
  Serial.println("Finished");
  digitalWrite(ledPIN, LOW);
  while(1) { /* do nothing forever */ }
}

The output of this little test will be the same time repeated every 5ish seconds. If it matters I am using a Feather M0 with the FeatherLogger that has an RTC on it. Changing this loop function to this:

void loop() {
  // put your main code here, to run repeatedly:
  char fmt[] = "YYYY/MM/DD-hh:mm:ss\n";
  if (millis() < 60000){
    Serial.println((rtc.now()).toString(fmt));
    delay(5000); 
  } else {
    Serial.println("Finished");
    digitalWrite(ledPIN, LOW);
    while(1) { /* do nothing forever */ }
  }
} 

shows that now does in fact update the time every 5ish seconds. I looked at the code for now and it appears to do very basic i2c commands to get the time and report it back. The only thing I can think of is that the compiler created a (not so) temporary DateTime object for me within the while loop and the RTC library does not provide a convenient constructor or operator to overwrite the existing object.

I tested my theory with this

void loop() {
  // put your main code here, to run repeatedly:
  char fmt[] = "YYYY/MM/DD-hh:mm:ss\n";
  while (millis() < 60000){
    DateTime t1 = rtc.now();
    Serial.println(t1.toString(fmt));
    delay(5000); 
  }
  Serial.println("Finished");
  digitalWrite(ledPIN, LOW);
  while(1) { /* do nothing forever */ }
}  

But again, the time did not change so clearly I don't understand what's happening here. Why doesn't the rtc now function work as intended within a while loop inside the loop function?

3
  • if (! rtc.begin()) { Serial.println("Couldn't find RTC"); Serial.flush(); abort(); } can you add this part to your code to check whether it is giving any error or not
    – Maaz Sk
    Feb 22, 2021 at 4:20
  • You have also not added the date and time in your code. Before going forward can you check whether the example code is working or not
    – Maaz Sk
    Feb 22, 2021 at 4:29
  • Try changing your loop to while (millis() < 60000){ volatile DateTime time = rtc.now(); Serial.println(time.toString(fmt)); delay(5000); } If this works, your theory about a wrong compiler optimization is correct.
    – PMF
    Feb 22, 2021 at 7:15

1 Answer 1

3

See the documentation of DateTime::toString():

The buffer parameter should be initialized by the caller with a string specifying the requested format. This format string may contain any of the following specifiers: [...] The specifiers within buffer will be overwritten with the appropriate values from the DateTime. Any characters not belonging to one of the above specifiers are left as-is.

The important thing to realize is that the buffer parameter is used both as input (for the format description) and as output (for the formatted date and time). You initialize it with a format description ("YYYY/MM/DD-hh:mm:ss\n"). Then, after the first call to toString(), the same buffer contains the formatted date and time. It does not contain the format description anymore. On the second call to toString(), as per the rule “Any characters not belonging to one of the above specifiers are left as-is”, the buffer is not modified.

Solution: Put the buffer initialization within the same while loop as the call to toString().

1
  • As usual, reading the documentation would have saved the OP a lot of time... ;-) +1 Feb 22, 2021 at 10:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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