RTC PCF8523 read offset register

I really didn't know where to put this question.

I am using a RTC PCF8523 together with the Adafruit RTClib library. I have no problem performing the calibration and setting the offset register. After changing things around a bit I thought it would be handy to be able to read the offset register. Wth this RTC, as far as I can see, the offset register is zeroed after a change in the backup battery, or power up if the backup battery is flat etc.

As far as I can see it should be possible to read the offset register and output the result to the serial monitor. If the RTC is already calibrated it would save performing a new calibration and the actual calibration could be inserted in the setup section of the sketch.

Any suggetion of a few lines of code would be gratefully accepter.

I do not know this subject material... but...
https://docs.circuitpython.org/projects/pcf8523/en/latest/api.html

Ok. In the end I worked out how to do this. My solution may not be particularly elegant but it works. Any suggestions from coding wizards on how to improve it would be gratefully accepted.

First of all in the sketch, in the case the pcf8523.ino, I declared the following variables (these would probably be better declared in the library as global variables):

int8_t offset;
char OffsetMode[18];

Then in setup() below the calibration section:

  Serial.print("Calculated Offset for calibration is: ");
  Serial.println(offset);  // Print to control calculated offset
  Serial.println("Read RTC PCF8523 Offset Register");  // Print to control offset
  rtc.ReadOffset();
  Serial.print("Offset mode is: ");
  Serial.println(OffsetMode);  // Print to control offset
  Serial.print("Offset is: ");
  Serial.println(offset);  // Print to control offset

RTClib library I made the following additions.
In the RTClib.h added to the declared functions in

class RTC_PCF8523 : RTC_I2C {
public:
// Line below added
  void ReadOffset(void);
};

Then in RTC_PCF8523.cpp the following function was added:

// read the offset register ********************
void RTC_PCF8523::ReadOffset() {
  extern int8_t offset;
  extern char OffsetMode[18];
  int8_t OffsetReg = read_register(PCF8523_OFFSET);
  if bitRead(OffsetReg, 7) {
    strcpy(OffsetMode, "PCF8523_OneMinute");
  }
  else {
    strcpy(OffsetMode, "PCF8523_TwoHours "); 
  }
  offset = OffsetReg;
  bitWrite(offset, 7, bitRead(OffsetReg, 6));
}

Note that the register contains the offset (-64 to +63) in 7 bits. In order to create an signed 8 bit int8_t it is necessary to copy bit 6 to bit 7.

As I say, perhaps not elegant but it works.

According to the datasheet, bit 7 of the register is the Mode setting, which has nothing to do with the value.

Does your library not already have code for reading and setting the offset register? If not, perhaps another library would.

You are absolutely correct. The library already has a function for setting the offset but I want to read what has been previously set. I am reading that bit 7 to find the mode that has been used.

I am, in effect, converting the other 7 bits which are used to store the offset itself, a number between -64 and +63, from a 7 bit signed integer to an 8 bit signed integer. In this case the first 6 bits are used to represent the number and the 7th bit, bit 6, is used for the sign. In this case it is valid to copy bit 6 to bit 7 to convert to an 8 bit signed integer which C++ interpret. This operation is performed on the variable int8_t offset, which is then Serial printed in the sketch.

I hope I have been able to explain this clearly enough.

If you are reading the register value, then after copying bit 6 to bit 7, I think you have to zero out bit 6. That would produce a value between 63 and -64.

No.

Dec -64 = 7bit signed 1000000 = 8bit signed 11000000
Dec -63 = 7bit signed 1000001 = 8bit signed 11000001
Dec 63 = 7bit signed 0111111 = 8bit signed 00111111

So, as you can see, to convert the 7bit signed binary to an 8bit signed binary you must copy bit 6 to bit 7. In the case of a positive number it is probably not necessary as I suspect it would pad with a zero anyway but it is easier to perform the copy regardless of the actual value.

On consideration I decided that using global variables was not a good idea because it created an obligation to declare them otherwise it would create a problem with the library.
To this end I moved the interpretation of the offset register back into the sketch.
So in the sketch, a modification of the example pcf8523.ino, I added the following lines in setup() below the calibration section:

  Serial.print("Calculated Offset for calibration is: ");
  Serial.println(offset);  // Print to control calculated offset
  Serial.println("Read RTC PCF8523 Offset Register");  // Print to control offset
  int8_t OffsetReg = rtc.ReadOffset();
  Serial.print("Offset mode is: ");
  if bitRead(OffsetReg, 7) {
    Serial.println("PCF8523_OneMinute");
  }
  else {
    Serial.println("PCF8523_TwoHours "); 
  }
  offset = OffsetReg;
  // OffsetReg contains the offset (-64 to +63) in 7 bits. 
  // In order to create an signed 8 bit int8_t it is necessary to copy bit 6 to bit 7.
  bitWrite(offset, 7, bitRead(OffsetReg, 6));
  Serial.print("Offset is: ");
  Serial.println(offset);  // Print to control offset

RTClib library I made the following additions.
In the RTClib.h added to the declared functions

class RTC_PCF8523 : RTC_I2C {
public:
// Line below added
  int8_t ReadOffset();
};

`Then in RTC_PCF8523.cpp the following function was added:

// read the offset register ********************
int8_t RTC_PCF8523::ReadOffset() {
  int8_t OffsetReg = read_register(PCF8523_OFFSET);
  return OffsetReg;
}

I believe that this version is better because it simply returns the value of the offset register and leaves the interpretation of the value in the sketch.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.