The DS3231 RTC temperature sensor

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 indicate by the MSB in the Upper byte. If that is  a ‘1’, then the number is negative.
ds3231 temp sensorAny 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 degreesit 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;
		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)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s