Incorrect operation of the PCF8523 real-time clock

In my project I use PCF8523 real-time clock and Adafruit RTClib library to work with this module. However, I encountered a problem that this chip does not return the correct seconds (only such codes as 1, 0, 11, 10, 01 and similar). And in general its work is incorrect because some minute values ​​are not displayed, the time of day and day of the month are recorded incorrectly. They are either shifted by several units, or are incorrect at all.
Has anyone encountered such problems? What do you think could be the problem?

I would be grateful for the answer!!

Most RTC’s have the same layout for the base time units, however the PCF8523 might be a litlle different. Have you compared the datasheet of the PCF8523 with the code in the RTClib?

Another cause might be a broken clock.

update:

DS3232 = “well known RTC”

And the PCF8523

Note the register mapping look different.

Post your sketch.

Can I, without a library, use I2C functions to just establish communication with the clock to set it and read the time?

Are you using the RTClib library by Adafruit? If so, does the example sketch for the PCF8523 show the same problems?

Yes, the example from the library gives exactly this result.

Yes! You can always do it if you know the commands and functions of I2C Protocol. Do you know the I2C Slave address for your RTC? If yes, what is this?

Are you using a breakout borad or a barebone clock chip? How many pins are there in your RTC?

Do you have solid connections to the RTC? Have you tried different wires, sometimes the dupont style jumpers will have broken wires inside the insulation.

Yes, assuming the I2C address is 0x68 (This cannot be changed).

Write to register Control_1 -0x00, the value 0x00 - This starts the oscillator

Write to register Control_2 - 0x01, the value 0x00 - This sets no alarms/interrupts

Write to register Control_3 -0x02, the value 0x00 - This will enable the battery circuit to enable (Assuming you're using a breakout board as you haven't replied to @GolamMostafa yet)

To check its working change something simple, like the day. So write to register 0x06 , write the value 0x07 to set the day to the 7th to see if it changes.

Read back the register 0x06, but the format of the data will be in Binary-Coded Decimal Format (BCD) so you will need to convert that to a decimal value (7). To do that

date = ((bcd >> 4) * 10) + (bcd & 0xFF);

where bcd is the value you received back from the PCF8523.

The Arduino documentation for Wire.h explains how to do each of those steps, just fill in the address and data to send. I2C Commands.

It might be useful to post a wiring diagram of your setup and the example code you have already tried.

Some more information about your setup would be useful, like what board are you using? Is it a 5V logic level or 3.3V logic level board? What I2C pins/bus are you using?

1 Like

If the OP @arduspec had read the posts and responded, I think his problems would have been solved by now.

1 Like

Thank you, very useful advice! I will try. I have my own board on which a microcontroller is installed, like on the Arduino UNO. The logic level of the I2C bus is 3.3V. A BME280 sensor is also installed on the I2C line.

#include <Wire.h>
#include <SPI.h>
#include <LCDWIKI_GUI.h>
#include <LCDWIKI_SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <RotaryEncoder.h>
#include <RTClib.h>
#include <avr/pgmspace.h>

// ====== Піни ======
#define LCD_CS 10
#define LCD_CD 5
#define LCD_RST -1
#define LCD_LED -1

LCDWIKI_SPI mylcd(ILI9341, LCD_CS, LCD_CD, LCD_RST, LCD_LED);

Adafruit_BME280 bme;

RotaryEncoder encoder(A1, A2,RotaryEncoder::LatchMode::TWO03); // CW → PC1/A1, CCW → PC2/A2
#define BUTTON_PIN A3           // ON → PC3/A3

RTC_PCF8523 rtc;

#define BLACK 0x0000
#define WHITE 0xFFFF
#define BLUE 0x00FF
#define RED 0xF000
#define GREEN 0x0FF0
#define YELLOW 0xFF00

int lastButtonState = HIGH;
int lastPos = 0;

float temperature = 0;
float pressure = 0;
float humidity = 0;


void setup() 
{
	Wire.begin();
	Wire.setClock(100000);
  Serial.begin(9600);
  bme.begin(0x76, &Wire);

  mylcd.Init_LCD();
  mylcd.Set_Rotation(1);
  mylcd.Fill_Screen(BLACK);

	mylcd.Set_Text_Mode(0);
  mylcd.Set_Text_colour(WHITE);
  mylcd.Set_Text_Back_colour(BLACK);
  mylcd.Set_Text_Size(2);

  encoder.setPosition(0);
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  pinMode(SDA, INPUT_PULLUP);
  pinMode(SCL, INPUT_PULLUP);

  rtc.begin(&Wire);
	rtc.adjust(DateTime(2026, 1, 14,13, 55, 0));
	rtc.start();
	
  mylcd.Fill_Screen(BLACK);
}

void loop() {
  DateTime now = rtc.now();

  mylcd.Set_Text_Size(3);


  temperature = bme.readTemperature();
  pressure = bme.readPressure() / 100.0;
  humidity = bme.readHumidity();
  
	mylcd.Set_Text_colour(RED);
	mylcd.Set_Text_Size(5);
  mylcd.Print_Number_Int(temperature, 215, 45, 0,'.', 10);
  mylcd.Print_String("C", 285, 45);
	mylcd.Draw_Circle(277, 50, 4);

  mylcd.Set_Text_colour(BLUE);
  mylcd.Set_Text_Size(5);
  mylcd.Print_Number_Int(humidity, 220, 110, 0, ' ', 10);
  mylcd.Print_String("%", 280, 110);

	mylcd.Set_Text_colour(GREEN);
  mylcd.Print_Number_Int(pressure, 220, 170, 0, ' ', 10);
  mylcd.Print_String("hPa", 125, 170);

	mylcd.Set_Text_colour(GREEN);
  
	mylcd.Set_Text_colour(WHITE);
  mylcd.Set_Text_Size(6);

  char buf[9]; // "HH:MM:SS"
  sprintf(buf, "%02d:%02d", now.hour(), now.minute());
  mylcd.Print_String(buf, 10, 45);

  mylcd.Set_Text_colour(YELLOW);
  mylcd.Set_Text_Size(4);
	
	char lol[20]; // "HH:MM:SS"
  sprintf(lol, "%02d.%02d", now.month(), now.day());
  mylcd.Print_String(lol, 10, 100);

	Serial.println(now.second(), DEC);

	static int pos = 0;
  encoder.tick();

  int newPos = encoder.getPosition();
  if (pos != newPos) {
    Serial.print("pos:");
    Serial.print(newPos);
    Serial.print(" dir:");
    Serial.println((int)(encoder.getDirection()));
    pos = newPos;
  }

}

Here is my code.

I'd possibly remove these lines as the Wire.begin() should set the pins/interface up correctly (assuming you are using the default I2C0 pins for your Microcontroller).

Also you don't check if either I2C device (BME280 or PCF8523) actually "begins" correctly. Have a look at the example code for each and how they may implement those checks.

The Wire library also has an i2c_scanner example code, maybe try that first to see if you can detect the sensors on the I2C bus.

-Harvey

1. I hope you can operate your UNO like MCU Board using Arduino IDE. Can we see the picture of your board?

2. Disconnect BME280 from the MCU board and leave only the RTC. Can we see the picture ofyour RTC breakout board?

3. Upload the following sketch to check that the MCU can detect the RTC chip on the I2C bus at Slave Address 0b1101000 (0x68).

#include<Wire.h>
byte busStatus;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  for (int i2cAddress = 0x00; i2cAddress < 0x7F; i2cAddress++)
  {
    Wire.beginTransmission(i2cAddress);
    busStatus = Wire.endTransmission();
    if (busStatus == 0x00)
    {
      Serial.print("I2C Device found at address: 0x");
      Serial.println(i2cAddress, HEX);
    }

    else
    {
      Serial.print("I2C Device not found at address: 0x");
      Serial.println(i2cAddress, HEX);
    }
  }
}

void loop()
{

}

I managed to fix the problem. The fact is that in addition to the RTC and BME280, I have an MPU6050 sensor on the I2C bus. The default address of the MPU6050 is the same as the RTC - 0x68. I changed the MPU6050 address to 0x69 and everything worked.

Thanks everyone!!

1 Like