Reading DS18B20 into bytes

Hi,
I'm new to Forum and fairly new to Arduino.
I hope I did OK with the code. I put it in code tags:slightly_smiling_face:
I'm reading DS18B20 temp sensor and use UNO R3.
I get the correct temperature on the serial monitor.
But I want to display the value on an LED matrix display (built of 3x 8x8 WS2812B RGB LED arrays). Displaying time ( with other sketch) is no problem.

I convert the float tempC via memcpy() into 4 bytes.
I was hoping to be able to extract the temperature from these. I understand the DS18B20 2byte format for temperature.
First I send the 4 bytes to the serial monitor. But I do not fully understand the meaning.

Serial monitor shows e.g.:
16.31°C bin 0 10000000 10000010 1000001
Extracted temperature: 0 10000000 1|0000|010 1|000001
which is 16 5x0.0625

But why for instance is the last byte 1000001, so 7 bits iso 8 bits.
And apparently when byte=00000000 it is shown as 0, that is OK.

16.25°C bin 0 0 10000010 1000001
Extracted temperature: 0 0 1|0000|010 1|000001
which is 16 5x0.0625
Why is byte content the same as for 16.31°C except for the 2nd byte (0 vs 10000000) ?

17.37°C bin 0 0 10001011 1000001
Extracted temperature: 0 0 1|0001|011 1|000001
which is 17 7x0.0625

-4.19°C bin 0 0 10000110 11000000
I didn't try extracting this one yet, but I expect to be able to do this (I think something like 128- value) when the above is clear to me.

#include <DallasTemperature.h>
#include <OneWire.h>

#define ONE_WIRE_BUS 10  // 1-Wire bus data pin

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);



void setup() {
  Serial.begin(9600);         // start serial port
  sensors.begin();            // Start up the DallasTemperature library
  sensors.setResolution(12);  // Set up the resolution for our sensors
}

void loop() {
  sensors.requestTemperatures();  // Send the command to start the temperature conversion
  float tempC = sensors.getTempCByIndex(0);
  byte b[4] = { 0 };
  memcpy(b, &tempC, sizeof(b));  // copy float tempC into 4 bytes

  // Check if reading was successful
  if (tempC != DEVICE_DISCONNECTED_C) {
    Serial.print(tempC);  // Print temperature of device 1 (index 0)
    Serial.print("°C     bin ");
    for (int i = 0; i < 4; i++)  // send the 4 bytes to monitor
    {
      Serial.print(i);
      Serial.print("=");
      Serial.print(b[i], BIN);
      Serial.print(" ");
    }
    Serial.println(" ");
  } else {
    Serial.println("Error: Could not read temperature data");
  }
}

Do you want to display the binary representation of the temperature, or the actual ASCII characters for the temperature?

The temperature is a float, with a rather complicated binary structure, see the following https://en.wikipedia.org/wiki/IEEE_754

Then take the temperature and multiply it by 1000, make it an integer and treat it as a time.

99.99 degrees x 1000 = 9999 or 99 hours and 99 minutes.

How the temperature value should be rendered with this quite limited display?

16.25 -> 16.3 on the matrix display?

Thanks Jim.

Yes, of course. But I would then need the individual digits (tens, units, decimal) and would like some guidance how to extract these.
Regards, Hobbybok

Thanks David.

I would like to extract the digits (binary, hex or BCD). E.g. 16.31°C >> 1 6 3(rounded).

I have briefly looked at IEEE 754 - Wikipedia but that didn't really help, very complicated as you say.

And if the byte representation as I have tried was clear to me (why is last byte only 7 bits and sometimes 8 bits as for negative temp) I can write code to extract. That is the fun of programming :slightly_smiling_face:

Reards, Hobbybok

Thanks LeGuin.

Yes, I'll do that in my program but first I need the digits (tens, units, decimals).

Regards, Hobbybok

That's easy. Say you have 1234
divide by 1000 will give you 1
by 100 gives 12
by 10 gives 123
Subtract 123x10 from 1234 and you have 4
Subtract 12x10 from 123 and you have 3
Subtract 1x10 from 12 and you have 2

Thanks Jim.

Yes, of course. But first I need to extract the "1234" of so from the bytes that represent float tempC. And there lies my problem.

Regards, Hobbybok

No
You have the float. Just multiply it by 100 and make it an integer
12.34 x100 = 1234

'LeGuin' isn't fiso42's name.
It is one of the forum's badges to indicate how many posts the user has made.

forum.arduino.cc/badges/114/le-guin

Likewise, my name isn't 'Regular' :rofl:

forum.arduino.cc/badges

@hobbybok

Hi

Use the dtostrf() function to convert the float to a c string

Something like...

char tempStr[7];
float temp = 22.8;
dtostrf(temp, 3, 1, tempStr);

Thanks Jim.

Mmmm, so simple. It works OK and extracting the digits from the int is no problem then.

Lets see how it goes with negative numbers. I'll let you know.

Regards, Hobbybok

You can get the integer version of the temp with
getTemp(const uint8_t* deviceAddress)

It returns a 16 bit integer with the LSB = 1/128

For the negative float values just multiply by -1

Thanks Jim for your great help. I'll proceed with your hints.

Regards, Hobbybok

1. The following diagram (Fig-1, Fig-2) may help you to extract the individual digits of the temperature (16.31).


Figure-1:


Figure-2:

2. 16.31
(1) Codes executed to get Temperature data:

byte myData[9];
ds.read_bytes(myData); 

(2)
Lower 4-bit of myData[0] holds fractional part (0.3100, Fig-1).
Uppler 4-bit of myData[0] and lower 3-bit of myData[1] holds integer part (16, Fig-1 & Fig-2).

(3) Extracting 1 and 6 from 16 ===> 0001, 0006 : D1, D0

unsigned int rawTemp = (int)(data[1] << 4)|myData[0]>>4;	//integer part 
byte D0 = rawTemp%10; //D0 = 0x06 (0000 0110 = 6)
rawTemp = rawTemp/10; //rawTemp = 0x01  (0000 0001 =1)
byte D1 = awTemp%10;   //D1 = 0x01 (0000 0001 = 1) 

(4) Following Step-(3), individual digits of the fractional part can be seperated.

Note: If OP could mention the type number of his display unit, I would try to write codes to display the float type temp data on it.

Thanks Golam

Extracting the individual decimal digits of the fractional part of temperature (say: 0.1875 ==> 1 8 7 5) assuming 12-bit resolution:

float fracTemp = 	0.5 * bitRead(n, 3) + 0.25 * bitRead(n, 2) + 0.125
            		* bitRead(n, 1) + 0.0625 * bitRead(n, 0); //temp in float format

int fTemp = (int) fracTemp*10000;// converting 0.1875 to 1875
byte myFracTemp[4]; //F0 = 5,  F1 = 7,  F2 = 8,  F3 = 1
for(int i = 0; i < 4; i++)
{
        myFracTemp[i] = fTemp%10;     //myFracTemp = F0 = 1 = 0000 0001
        myFracTemp = myFracTemp/10;
}

Thanks again Golan

Do you still need help?