need to compare if a byte is less than 80 hex

I am using an infrared sensor called OTI301. In its data sheet it says that in order to obtain object temperature and ambient temperature values I need to extract the binary information from the sensor and use the binary information in given formulas. I have done all that but for some reason I am not getting the right values for the object temperature. The ambient temperature seems to work well but when I put a hot object, more than 320 F, the formula returns a random negative number. Also the the sensor can go up to 780 F so I know the temperature has not been capped. Please see pictures for important data sheet information, or here are the links for the complete data sheets https://drive.google.com/file/d/1XMRDCNzY3fn0q6lkGejs5D-pqksfRuZ8/view?usp=sharing. https://drive.google.com/file/d/1mmdkHkNbwC5VgQxGMrq07XolajNvgBkN/view?usp=sharing. Lastly, here is the part of the code where I extract the information and apply formulas.

``````     void loop()
{
if (Wire.read()) // On success, read() will return 1, on fail 0.
{
//Serial.println(buttonState);
Wire.endTransmission(false);
Wire.requestFrom(DEVICE_ADDRESS, 6); // request 6 bytes
uint8_t data[6];
for (int i = 0; i < 6; i++) {
}

//Calculate Object Temperature
if(data[5] < 0x80) {
TA = (data[3]+ data[4]*256+data[5]*65536)/200;
}
else {
TA = (((data[3]+ data[4]*256+data[5]*65536)) - 16777216) /200;
}

//Calculate Ambient Temperature
if(data[2] < 0x80) {
TA = (data[0]+ data[1]*256+data[2]*65536)/200;
}
else {
TA = (((data[0]+ data[1]*256+data[2]*65536)) - 16777216) /200;
}
``````

• What data type is `TA`?
– Majenko
Nov 23, 2019 at 23:36
• on a nano, int calculations are 16 bit. A multiplication by *65536 wont work as expected if you don't force it into 32bit arithmetics. Nov 24, 2019 at 0:26
• @Majenko I defined TA as a float. Nov 24, 2019 at 0:40
• When you calculate `TA` you are doing integer math. Try as DataFiddler wrote and cast the numbers to long, so that the result cannot overflow Nov 24, 2019 at 13:41
• @DataFiddler: A multiplication by 65536 will work as expected, because 65536 is a 32-bit `long int`. Nov 24, 2019 at 20:13

You said "I defined TA as a float." That doesn't matter. In C/C++, expressions are only "promoted" to a larger/different data type AFTER they are evaluated. Your calculations are being done using 16-bit ints, which overflow, and then cast to a float.

(C/C++ evaluates expressions from the inner-most outward, and if one of the operands to an operator is a larger type, it will "promote" the other operand to the larger type before doing a calculation. It won't notice that a calculation will overflow and promote the operands to fix that problem however.)

Try this:

``````   TA = (data[3]+ data[4]*256+uint64(data[5])*65536)/200;
``````

That version of the code forces data[5] to an unsigned long before multiplying it by 65536.

Do the same thing to the value that you multiply by 65536 in all of your expressions and you should avoid overflow.

• Thank you all. problem solved! Nov 24, 2019 at 16:30
• 1. On the Nano, `uint64` (I guess you mean `uint64_t`) is not the same as `unsigned long`: the latter is 32-bits only. 2. The overflow happens with `data[4]`, not with `data[5]`. 3. Your formula gives grossly bad results for temperatures larger than 163.84 °C (try data = {0,0,0,0,128,0}). Nov 24, 2019 at 21:36
• overflow on data(4)? Is data an int or a byte? Nov 24, 2019 at 22:04

The rules of integer arithmetics are tricky in C++. There are rules that give the type of integer literals:

• `256` and `200` are of type `int`, which is the default type for integer literals. On the Nano, this type is 16-bits, and covers the range from −32,768 to +32,767.

• `65536` being too large for the `int` type, it is implicitly considered a `long int`. This type is 32-bits on the Nano, and covers roughly ±2.15×109.

Then there are rules for the types used in arithmetic operations. No computation is ever done on a type smaller than `int`: anything smaller is promoted to `int`. Then, if you combine two operands of different types, the larger type “wins” and the compiler implicitly converts the other operand to the larger type. Note that if two types have the same bit size, the unsigned one is considered “larger”.

Let's go now through your formula, and see the types of the different terms:

``````data[3]       = uint8_t
data[4]*256   = uint8_t * int → int
data[5]*65536 = uint8_t * (long int) → long int
``````

Now you may see the problem. Your calculation will eventually overflow, but the overflow is not in `data[5]*65536`, as one may naively expect. What happens is than when the temperature reaches 163.84 °C (≈ 327 °F), `data[4]` becomes 128, and `data[4]*256` is 32,768, just too large for an `int`. The result overflows to −128, hence the negative values you see.

The simplest solution is to force 256 to be a `long int`, by appending the `L` suffix to the number. Then the multiplication will be performed with the `long int` type, and there will be no overflow:

``````TA = (data[3] + data[4]*256L + data[5]*65536) / 200;
``````

On a final note, it is worth noting that the numbers 256, 65536 and 16777216 used in the formula are all powers of two. Even powers of 256. You may notice that, save for the division by 200, what this formula describes is the coding of an integer as a 24-bit, little-endian, two's complement number. This format (two's complement little-endian) is exactly what the Arduino uses internally for representing numbers. You could then avoid all those calculations and get your result by just telling the compiler that what those memory cells are actually holding is a 24-bit integer:

``````float TA = *(__int24*)&data[3] / 200.0;
``````

This works for both positive and negative temperatures, but it has the drawback of breaking some C++ rules (aliasing rules), and using the non-standard type `__int24`. A safest way to achieve the same is to build a 32-bit integer by putting the bits in place using bitwise operations. But note that then a sign-extension byte is needed to convert the 24-bit number to 32 bits:

``````uint8_t sign_extension = data[5] & 0x80 ? 0xff : 0x00;
int32_t reading = (uint32_t) data[3] <<  0
| (uint32_t) data[4] <<  8
| (uint32_t) data[5] << 16
| (uint32_t) sign_extension << 24;
float TA = reading / 200.0;
``````
• `int32_t reading = (int32_t)(int8_t)b[5] <<16 | (uint16_t)b[4] << 8 | b[3] ; `the highbyte just has to be signed, then it's still tricky but a bit simpler. Nov 24, 2019 at 23:32