4

I've got a 2 byte array (21, 121) that needs to be converted to a decimal value. The piece of hardware I read the numbers from includes this handy little table in the manual:

High Low Conversion

The problem is that I'm not sure what this handy little table is trying to tell me. Can someone help interpret it and suggest a way I can convert it to decimal using c#?

I've generally used BitConverter to get this converted, but in this case, I get a value of 30977. Since this is a temperature value, I find it hard to believe it's that hot... so I suspect my regular use of BitConvert isn't sufficient.

bugfixr
  • 7,997
  • 18
  • 91
  • 144
  • As one signed byte (-127/+127) should be enough for all climate on earth, maybe it's higher precision. Assuming you are right, how does "30.977C" sound? – nvoigt Aug 31 '15 at 13:20
  • Could it be that it's 31° C ? Or 30.997 to be precise? At least that's how thermometers like DS18B20 return their data – Panagiotis Kanavos Aug 31 '15 at 13:20
  • What is the actual (hex) value that gets converted to 30977 ? – Panagiotis Kanavos Aug 31 '15 at 13:23
  • @PanagiotisKanavos The byte values are 21 and 121 in the sample reading I took. – bugfixr Aug 31 '15 at 13:29
  • Possible duplicate of [How do I save a floating-point number in 2 bytes?](https://stackoverflow.com/questions/10414889/how-do-i-save-a-floating-point-number-in-2-bytes) – iammilind Oct 27 '17 at 07:16

4 Answers4

5

This table tells you that you can get the value this way:

public static float GetTemperature(byte[] data, int start = 0)
{
    return (sbyte)data[start] + data[start + 1] / 256.0f;
}

EDIT: negative numbers were not decoded correctly.

EDIT: as others mentioned, the table shows you that how the value is encoded. The top row is the bit index in the binary data, the bottom row is the weight of the bit. All you have to do is to multiply all the bit values with their weights, and add them together. Sidenote: the first bit is not a sign, it shows that it is encoded in two's complement. Fortunately, you don't have to calculate the separate bits, because this is pretty much how the computer stores all the data. It is like a signed short value stored on two bytes, scaled by 256 (2**8).

BitConverter uses platform-dependent byte order, so basically you can't use it here.

Another way to get this right:

public static short GetShort(byte[] data, int start)
{
    return (short)(data[start] * 256 + data[start + 1]);
}

public static float GetTemperature(byte[] data, int start)
{
    return GetShort(data, start) / 256.0f;
}
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97
  • Thanks - this gives me a value of 21.47 degrees, which sounds reasonable... but why? :) I'd ideally like to understand how it all works so I can figure out the next mystery table on my own. – bugfixr Aug 31 '15 at 13:43
  • This will run into issues when the sign-bit comes into play. Note that the high-byte has a sign-bit whilst the low-byte doesn't. – flindeberg Aug 31 '15 at 13:55
  • @flindeberg Thanks, fixed – Tamas Hegedus Aug 31 '15 at 14:08
1

This table tells you that the low byte value describes values between 0,0039 (the first bit in the byte) and 0,5 (the last bit in the byte). Combined it is close to 1, the first bit in the high byte. The highest value is 128, which is the sixth bit of the high byte. The seventh bit tells you if the number is negative or positive.

So this is a signed integer of 8 bits with some extra precision.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
1

The result is 21.472 C The table is saying the first byte (21) is a "char" and has values from -127 => 127. (2^6 + 2^5 + ...) It looks like the 2^7 bit is a sign. That would mean that

21 = 21

and

149 = - 21

149 = 128 (0x80) + 21

The second number is a fraction, which you can resolve by dividing by 256 (2^8) So 121 / 256 = 21.472

mksteve
  • 12,614
  • 3
  • 28
  • 50
1

Answering without referring to programming per say, but the problem at hand could be seen as a simple mathematics problem. Think of it as a new numbers-system, but instead of binary where the first "digit" is "worth" 1, the first digit is worth 1/256 or 2^-8, and the next one worth the double. Until the 16th place which if it is a "one" illogically is worth -2^7 instead of 2^7.

To make an example, high 7 in your table is my "16th place", and is worth negative 2^7; high 4 is worth 2^4 and is my "13th place", ie 1/256 * 2^12.

Does that make sense?

(in a programming sense, byte_high (signed) + byte_low (unsigned) / 256f does it, sign matters here a lot!)

PS: This make your (21,121) into 21 + 121/256, roughly 21.47 which seems to be a valid indoor temperature in Celsius.

flindeberg
  • 4,887
  • 1
  • 24
  • 37