Two's complement math question

Hi all,

I'm reading a temperature sensor that returns a 10 bit number. The data returned is in this format (2 bytes):

Most significant byte
[SIGN BIT8 BIT7 BIT6 BIT5 BIT4 BIT3 BIT2]

Least significant byte
[BIT1 BIT0 xx xx xx xx xx xx ]

The 10 bit number represents the temperature in Degrees C with a 0.25 degree/bit resolution. So here's how I am trying to get the value of the registers:

float DS3234::get_temp(void)
{
        int16_t temperature = 0x00; // initialize to zero
        this->_busy_wait(); // wait for chip not busy
        this->_write_spi(0x8E, 0x20); // force a temperature conversion
        temperature |= (this->_read_spi(0x11, 0x00) << 8); // get hi bits
        temperature |= this->_read_spi(0x12, 0x00); // get lo bits
        return (float)(temperature / 256.0); // return chip temperature
}

What the code does is take a SIGNED 16 bit int (temperature), then OR in the two register values. The sign bit gets placed in bit 15 of "temperature" which makes it positive or negative depending on the sign bit. Finally I divide by 256.0 which in effect "bit shifts" the data down to where the "xxx" bits are, then divides by 4 to convert each bit into 0.25 degree increments and returns the result as a float.

My question is: Am I right in "depending" on a signed int to work properly to give me my positive and negative values, or is there a "better way" to do it?

Any help will be appreciated!

-- Roger

This is a class method, right? Your use of "this->" is rather distracting.

2^6 is not 256 you know, it's 64.

You could just shift right 6, as this test program demonstrates:

void setup ()
  {
  Serial.begin (115200);
  int foo = 0b1010101010000000;
  
  foo >>= 6;
  
  Serial.println (foo);
  Serial.println (foo, HEX);
  
  }  // end of setup

void loop () { }

Output:

-342
FFFFFEAA

The sign bit is preserved in the shift.

What you have done is fine as long as the sensor (which one is it??) gives you a twos complement number.
One slight/minor tweak would be to not initialize temperature to zero and then the first read would be:

temperature = (this->_read_spi(0x11, 0x00) << 8); // get hi bits

But I have seen (IIRC) a sensor that gives the temperature in sign-magnitude format. In that case the number must be handled a bit differently.

Pete

I divide by 256 because I divide by 64 (for the "bit shift") then by 4 because the data is 0.25 degrees per bit (or 4 bits per degree).

Instead of doing this:

value >> 6
value / 4

I did it all in one shot:

value / 256

I didn't do this:

value >> 8

because I wanted to preserve the fractional part of the number.

If I shift the number down by 6 bits, will the sign be preserved so that then a divide by 4.0 (float) will return a positive or negative result?

Oh and why is using "this->" distracting? Is it wrong?

el_supremo:
What you have done is fine as long as the sensor (which one is it??) gives you a twos complement number.
One slight/minor tweak would be to not initialize temperature to zero and then the first read would be:

temperature = (this->_read_spi(0x11, 0x00) << 8); // get hi bits

But I have seen (IIRC) a sensor that gives the temperature in sign-magnitude format. In that case the number must be handled a bit differently.

Pete

It's the sensor in the Dallas/Maxim DS3234 RTC chip.

The datasheet describes the register as such:

The temperature is encoded in two’s complement format, with bit 7 in the MSB representing the SIGN bit. The upper 8 bits, the integer portion, are at location 11h and the lower 2 bits, the fractional portion, are in the upper nibble at location 12h. Example: 00011001 01b = +25.25°C.

I wish they had given a negative temperature example as well so I could check my function! :slight_smile:

OK so then this should work?

float DS3234::get_temp(void)
{
        int16_t temperature;
        _busy_wait(); // wait for not busy
        _write_spi(0x8E, 0x20); // force a temperature conversion
        temperature = (_read_spi(0x11, 0x00) << 8); // get hi bits
        temperature |= _read_spi(0x12, 0x00); // get lo bits
        temperature >>= 6; // slide bits down
        return (float)(temperature / 4.0);
}

Is there any functional difference between shifting right 6 and divide by 4 as opposed to divide by 256?

Yes, that looks OK. And you got rid of this->

Oh and why is using "this->" distracting? Is it wrong?

It's not necessary, class methods automatically get access to the "this" variable (the current instance of the class). It's a bit like this:

a = (2);

The brackets aren't necessary and are distracting.