I am using an NTC to read temperature. I use the Steinhart-Hart formula to calculate the temperature from the Resistance of the NTC. The output of that formula is a float (double integer, 4 bytes).
I also want to log the results in memory. For that I have a couple of choices
Store the floating point variable : that will cost me 32 bits of memory for every temperature value logged
Store the original NTC reading and just pull that through the Steinhart-Hart formula again when needed, that will cost me 16 bits for every temperature logged.
As I really don’t need the high decimal precision that a floating point value can give and as I really didn’t expect my temperature range to go outside -15 to +30 degrees Celcius, both 16 bits and 32 bits seemed serious overkill.
So I was wondering if I just couldn’t store it in in 1 Byte. As the Steinhart-Hart formula gives an approximation of the temperature, one can wonder how precise of a reading one needs, but I decided I wanted a solution of 0.25 degrees, though no doubt 0.5 degrees would have been enough already.
I figured I would use the MSB for the sign bit, that left 7 bits
decimal number 31 is equal to 0b00011111, so to cover my range I needed 5 bits for the temperature that left 2 bits
In those two bits I can store numbers 0-3, that I could use for the decimal fraction.
Extracting the essential bits from the binary level of the float seemed to much of a problem so I mainly worked with the decimal values.
In the function floatToByte I do a couple of essential things: I first check if it is a positive or a negative number as that determines the MSB I need to set in my byte. Then Itake the absolute value of the float so I get rid of o potential minus value, which would complicate calculations.
Then I turn the float into an integer and subtract that from the float. That leaves the decimal fraction. In order to keep at least some precision in that I have to put that in a double. Initially it was my idea to turn the values 0-9 into 0-3, but a simple division by 3 didnt have the desired effect as ‘9’ was sometimes 0.89 which by division would give a 2, So I decided on some simple ‘if’ conditions to convert the double fraction into half a nibble.
I then would shift the 5 bit temperature 2 bits to the right bitwise OR it with the fraction (on the two least significant bits and bitwise OR it with the sign bit.
That gave me temperature values that I can store in 1 Byte of EEPROM.
The way back – from memory byte to sensible temperature. Goes the other way around
byte floatToByte(float temp2) { byte sign = 128; if (temp2 >= 0) { sign = 0; } double temp = abs(temp2); int heel = int(temp); double fractie = temp - heel; fractie = (temp - heel); fractie = fractie * 100; byte fractie2 = 0; if (fractie >= 25) { fractie2 = 1; } if (fractie >= 50) { fractie2 = 2; } if (fractie >= 75) { fractie2 = 3; } byte temperatuur = (((heel << 2) | fractie2) | sign); return temperatuur; } void getTempByte(byte Temp) { float temperatuurCelcius; if (Temp & 0b10000000) // check negative { Temp = Temp ^ 0b10000000; // knock out MSB byte double fractie = (Temp & 0b00000011); byte body = (Temp >> 2); Serial.println(-1 * (body + (fractie * 0.25))); } else { byte fractie = (Temp & 0b00000011); byte body = (Temp >> 2); Serial.println(body + fractie * 0.25); } } void setup() { Serial.begin(9600); byte x = floatToByte(+31.10); Serial.println(x, BIN); x = floatToByte(+31.25); Serial.println(x, BIN); x = floatToByte(31.50); Serial.println(x, BIN); x = floatToByte(+31.75); Serial.println(x, BIN); x = floatToByte(-31.75); Serial.println(x, BIN); x = floatToByte(+0.15); Serial.println(x, BIN); Serial.println("temperatuur "); getTempByte(0b1111101); } void loop() { // put your main code here, to run repeatedly: }