The DS3231 RTC is a rather accurate RTC that has an internal temperature sensor that is used to calibrate the oscillator. The sensor is however also readable from external software. It has a 10 bit solution and uses two registers: 0x11 and 0x12. The information in the upper byte is stored in 2-complement notation. The lowerbyte is there for the fractional part and has a solution of 0.25 degrees Celsius.

Two’s complement notation means that with positive numbers it just follows the regular binary storage, but with negative numbers it does it a bit different. Knowing whether a number is negative or positive is indicated by the MSB in the Upper byte. If that is a ‘1’, then the number is negative.

Any reading of the registers therefore needs to include a check to see if the number is positive or negative. As the Lower byte only indicates the fraction with an accuracy of 0.25 degrees it only needs to count to 4 (0.0. 0.25, 0.50, 0.75), hence two bits are enough

So suppose we have retrieved the number:

0b0001100101 => +25.25°C. We can easily see it is 25.25°C because the top 8 bits are 00011001, which is 25, while the lower two bits 0b01, mean 1×0.25.

As the lower byte, only uses the top 2 bits, it may need to be rightshifted 6 positions for calculations. So how about negative numbers, say -18 degrees.

Well -18 is 0b11101110 (=238 in twos complement notatie).

We can see that the highest bit is a 1, indicating a negative number. In order to make a check, we do the following:

0b11101110 & 0b10000000 => 0b10000000 So we know it is negative

Then we need to convert the 2 complement notation

0b11101110 XOR 0b11111111 => 0b00010001 (=17) // first XOR it

17+1= 18 // and add a ‘1’

18*-1 = -18 // and then we turn it negative

So, how does that look in a program?

float getTemperature() { int temperatureCelsius; float fTemperatureCelsius; uint8_t UBYTE = readRegister(REG_TEMPM); //Two's complement form uint8_t LRBYTE = readRegister(REG_TEMPL); //Fractional part if (UBYTE & 0b10000000 !=0) //check if -ve number { UBYTE ^= 0b11111111; UBYTE += 0x1; fTemperatureCelsius = UBYTE + ((LRBYTE >> 6) * 0.25); fTemperatureCelsius = fTemperatureCelsius * -1; } else { fTemperatureCelsius = UBYTE + ((LRBYTE >> 6) * 0.25); } return (fTemperatureCelsius); }

Obvously this isnt a full program but just a function. You still need to define REG_TEMPM (0h11) and REG_TEMPL (0x12), and ‘readRegister’ is another function that just reads the specified registers (using the ‘Wire’library)

The datasheet does not specify if you should subtract the fractal if its a negative temperature. That makes more sense to me. So if temperature is -30 and fraction is 0.25 that means -30.25 and not -29.75.

Or will my way of doing it be wrong?

Good question and as a matter of fact, from doing some orientation on the internet, the judge is still out on the right way. As I understand LadyAda’s addition to the RTC lib, she adds the fraction to the two’s complement part, which means that say 0.25 is added to the negative temperature, making -30 into -29.75. But then again, other sources say that the fraction is part of the two’s complement, which could mean that you add the fraction, making 30 into 30.25 and then exercise the top bit, multiplying with -1 if that is set, making it -30.25. I must confess I am not sure