RTC Gives wrong time after few days

I made a LED clock and I used it in my room. But after a few days (almost 15-30days) the RTC DS3231 dives the wrong time (slow than the current time). For fixing the time I need to upload the time resetting code.
Same behave it's doing continuously. And when it gives the wrong time, its time difference continually increases. For example: with the wrong time, if it currently gives 3 minutes difference (from the current time), after 1-2 hours it gives 7-8 minutes difference.

Please anyone can help me to find out, what the issue is?

No clock is perfect and it's going to be off after several days. But I think the DS3231 is supposed to be pretty good and I wouldn't expect it to be worse than a wristwatch. Did you buy yours from a reputable supplier?

But if it's off by several minutes after a couple of yours, that's a problem!

...I wonder if your code is actually reading the DS3231 "continuously" or if the Arduino is running on it's own.

P.S.
The datasheet says the accuracy is +/- 2ppm. And according to the Internet ... 1 million seconds is about 11.5 days so it shouldn't be more off by more than around 1 second in a week.

A regular quartz crystal typically has an accuracy of around 100ppm so watches and clocks are usually "tweaked" for better accuracy because that's not good enough for a watch.

Start by posting your code. Read the forum guidelines to see how to properly post code and some good information on making a good post.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

Bro! when it is off, can it repeatedly becomes off?. When it's giving the wrong output, from that time it's slower than the actual time (that's why the difference is increasing).
When I re-upload code, without any testing of ware it's run perfectly.

My code is here.

#include<Wire.h>
#include<DS3231.h>

DS3231 rtc(SDA, SCL);
Time t;

int milliSec=0;

int gnd=2, v5=3; //Register Power.
int dataPin=4,latchPin=5, clockPin=6;

int dGnds[]={7,8,9,10,11};//From Left to Right
int digits[]={
 //gfedcba
  B00111111,//0=63
  B00110000,//1=48
  B01101101,//2=109
  B01111001,//3=121
  B01110010,//4=114
  B01011011,//5=91
  B01011111,//6=95
  B00110001,//7=49
  B01111111,//8=127
  B01111011,//9=123
  B00000001 //:=For second
};

void setup() {
  rtc.begin();
  Serial.begin(9600);

  //setTime(); //For set time uncomment it, then recomment and upload again.

  pinMode(gnd,OUTPUT),digitalWrite(gnd,LOW);
  pinMode(v5,OUTPUT),digitalWrite(v5,HIGH);
  
  pinMode(dataPin,OUTPUT);
  pinMode(latchPin,OUTPUT);
  pinMode(clockPin,OUTPUT);

  pinMode(dGnds[0],OUTPUT),digitalWrite(dGnds[0],HIGH);
  pinMode(dGnds[1],OUTPUT),digitalWrite(dGnds[1],HIGH);
  pinMode(dGnds[2],OUTPUT),digitalWrite(dGnds[2],HIGH);
  pinMode(dGnds[3],OUTPUT),digitalWrite(dGnds[3],HIGH);
  pinMode(dGnds[4],OUTPUT),digitalWrite(dGnds[4],HIGH);
}
void loop() {
  milliSec>1000 ? milliSec=0 : milliSec+=5;
  
  t = rtc.getTime();
  if (milliSec==950) Serial.print(t.sec, DEC);
  showTime();
}

void showTime(){
   int m=t.min;
   int h=t.hour%12;
   if (!h) h=12;
   //Minute
   showDigit(dGnds[0], digits[m%10]);
   showDigit(dGnds[1], digits[m/10]);
   //Blinking Second
   if (milliSec>500) showDigit(dGnds[2],digits[10]);
   //Houre
   showDigit(dGnds[3],digits[h%10]);
   showDigit(dGnds[4], digits[h/10]);
}

void showDigit(int digitGnd, int digitValue){
  //ResetGnd
  for (int i=0; i<5; i++) digitalWrite(dGnds[i], 1);
  //Digit High
  digitalWrite(latchPin, 0);
  shiftOut(dataPin,clockPin, LSBFIRST, digitValue);
  digitalWrite(latchPin, 1);
  //Selected segment Gnd High, So that, Show digit.
  digitalWrite(digitGnd, 0);
  delayMicroseconds(1000);//Stay digit for 1 millisecond.
}

void setTime(){
  //For set time please call this function from setup.
   rtc.setDOW(SATURDAY);//Day name
   rtc.setTime(1,0,00);//hh,mm,ss
   rtc.setDate(03,03,2022); //dd,MM,yyyy
}

A Question please, is it can possible with RTC internal battery issue?

I think yes, I had a RTC DS1307 and there were some clock issues, and actually I replaced the battery and it worked. I don't know if it's your problem, but try !

1 Like

Also, If it go off after several days, than would start (after off) with 12:00am. But It's not happening.

What convinces you that your loop() takes exactly 5 milliseconds to execute?

Is there some special reason for not using standard millis() timing here?

A wiring issue is more likely, for example one that would phantom power the device.

Also, what are you comparing the displayed time to? What is your time reference?

What is "phantom power"?

What kind of Arduino do you have? Uno, Nano,…?

Here milliSec I actually used for second blinking (Second is two dot. half of second turn on and half of turn off).

Why not used delay() method:
Here every digit blinking with 1000 MicroSec delay. My logic is that, if I used delay() than, DigitBlinking would increased. And it was visible.

Arduino nano (ATMega328p Old bootloader)

Can you try to identify which DS3231 library you have installed. Look under Sketch -> include library -> library manager in the IDE. You'll see something like this:

The problem you describe, that is extremely bad timekeeping from what is supposed to be a precision device, could be due to the library somehow returning the Arduino system time instead of the time obtained from the RTC.

Also, and possibly related, you are calling the method getTime() every 5 milliseconds which is an unusually high rate. Maybe try calling it every 1 second just to see if there is a change in its behaviour. Something like:

if (milliSec==950)  {
    t = rtc.getTime();
    Serial.print(t.sec, DEC) ;
} 

A module can power up and operate from the current that flows through its input/output pin protection diodes, even if Vcc is not connected. Of course, It will not be reliable. But it's enough to make you tear your hair out. It's often called "phantom power".

1 Like

I said, "millis", not "delay".

Your "digit blinking", whatever it is, should not be affected by any RTC updates. If it is, you have the whole logic wrong.

It seems to me, you have done a lot of programming without researching how things are normally done.

If your clock is off by several minutes per hour, this would suggest that the clock is either borked or that the battery in it is flat. If it was only a couple of seconds per day, you would have been able to fine tune it by setting the aging register:

#define DS3231_AGING_OFFSET 0x10

int8_t ds3231_get_aging_offset()
{
  //Returns the aging offset, defaults to 0
  Wire.beginTransmission(DS3231_ADDRESS);
  Wire.write(DS3231_AGING_OFFSET);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_ADDRESS, 1);
  return Wire.read() & 0xFF;
}

void ds3231_set_aging_offset(int8_t offset, bool force_conversion = true)
{
  //offset = a value from -127 .. 127
  //force_conversation = force the clock to use the value immediately
  //Negative values will speed up the module.
  //A change of +/- 1 will adjust the time base by 0.12ppm
  Wire.beginTransmission(DS3231_ADDRESS);
  Wire.write(DS3231_AGING_OFFSET);
  Wire.write(offset);
  Wire.endTransmission();
  if (force_conversion)
  {
    Wire.beginTransmission(DS3231_ADDRESS);
    Wire.write(DS3231_CONTROL);
    Wire.endTransmission();
    Wire.requestFrom(DS3231_ADDRESS, 1);
    uint8_t ctrl = Wire.read() | (1 << 5);
    Wire.beginTransmission(DS3231_ADDRESS);
    Wire.write(DS3231_CONTROL);
    Wire.write(ctrl);
    Wire.endTransmission();
  }
}

The aging register should be set when the time is also set, usually after a battery replacement.

EDIT: By fine tuning the aging offset of one of my cheap DS3231 modules, it is only off by less than one second over a period of several (5 as far as I recall) months.

It's interesting, the OP hasn't actually answered a single question that was asked...

Nope, you are not worthy his precious time! :face_with_raised_eyebrow: :stuck_out_tongue:

Oh, I don't know about that.

#14! :grin: