# DS18B20 with only OneWire library

Peter Scargill found a way to use DS18B20 temperature sensor without any library and just using OneWire library, and it's amazing how blazing fast it is! (it's an old article from 2013)

``````#include <OneWire.h>
int16_t dallas(int x,byte start){
OneWire ds(x);
byte i;
byte data;
int16_t result;
do{
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
for (int i = 0; i < 2; i++) data[i] = ds.read();
result=(data<<8) |data;
result>>=4; if (data&128) result |=61440;
if (data&8) ++result;
ds.reset();
ds.write(0xCC);
ds.write(0x44, 1);
if (start) delay(1000);
} while (start--);
return result;
}
void setup (){
dallas(A0,1);
}
void loop (){
float currentTemp = dallas(A0,0);
}
``````

Problem is The accuracy, he converts float to int to get accuracy of 1 degree and it's working just fine.

How can i get accuracy of .5 (or .2?) degree using this semi library?

• Which is the pin of DS18B20? i dont understand – Uriel Aug 14 at 14:04

Actually he isn't really converting `float` to `int`. He never uses `float` since he don't need it. The datasheet of the DS18B20 shows at page 6, how the data is formatted: 1. The 4 highest bits just resemble the sign bit 11.
2. The first digit with full degrees is bit 4. Every bit below that has values below 1°C

So the data bytes `0b1111100001010000` will represent a temperature of -123°C and `0b1111100001011000` -122.5°C.

The author from the link then shifts this data 4 bits to the right, so that all bits representing values under 1 vanish. You can convert the received value per hand to `float` by also using this.

``````int16_t whole_degree = (result & 0x07FF) >> 4;
float temperature = whole_degree + 0.5*((data&0x8)>>3) + 0.25*((data&0x4)>>2) + 0.125*((data&0x2)>>1) + 0.625*(data&0x1);
if (data&128) temperature*=-1;
``````

As float does not have the same structure, as the data, we need to convert them. So I calculate first the number of whole degrees analog the your code. Then I add this up with the values of the lowest 4 bits. `((data&0x8)>>3)` and it's siblings will be 1, when the corresponding bit is set, and 0, if not.

So you get the full precision of the sensor (12 bits). Please note, that for this to work, you should not configure the sensor to less resolution. In that case you would have to ignore the corresponding lowest bits. But the sensor is in 12 bit mode at power up anyway and your code does not configure it otherwise.

Note: I'm unsure about the line `result |=61440;` in the original code. This sets the 4 highest bits of a 16 bit value to 1. I don't see, why this should be correct here, since a normal 16bit integer does only have 1 sign bit. In my understanding the original code would lead to false readings (way off), when reading temperatures below zero. I instead simply multiplied the resulting temperature with `-1`.

The whole code would look like this (I also added the statement for printing out the pure received data as binary, as I requested it in my comment. These statements are currently commented out):

``````#include <OneWire.h>
float dallas(int x,byte start){
OneWire ds(x);
byte i;
byte data;
int16_t result;
float temperature;
do{
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
for (int i = 0; i < 2; i++) data[i] = ds.read();
result=(data<<8) |data;
// Here you could print out the received bytes as binary, as requested in my comment:
// Serial.println(result, BIN);
int16_t whole_degree = (result & 0x07FF) >> 4; // cut out sign bits and shift
temperature = whole_degree + 0.5*((data&0x8)>>3) + 0.25*((data&0x4)>>2) + 0.125*((data&0x2)>>1) + 0.625*(data&0x1);
if (data&128) temperature*=-1;
ds.reset();
ds.write(0xCC);
ds.write(0x44, 1);
if (start) delay(1000);
} while (start--);
return temperature;
}
void setup{
//Serial.begin(9600);
dallas(A0,1);
}
void loop{
float currentTemp = dallas(A0,0);
}
``````
• Mhh, can you output the pure reading in binary and write this into a comment. You can do this via serial by `Serial.println(result, BIN);` – chrisl Jul 16 '19 at 16:52
• @newbie I added a not-tested implementation to my answer. You can try it. There are also the statements for printing the pure reading in binary. These statements just have to be uncommented in the case, that this code is not working correctly – chrisl Jul 16 '19 at 17:47
• Yes, surely it says that in loop, since you should not put it there, but into the function `dallas()`. But you can just use my provided code an uncomment the lines with `Serial` in `dallas()` and `setup()` – chrisl Jul 16 '19 at 17:54
• @newbie you asked me to look at this question, but I think this answer explained it well (and upvoted it)... or do you have something specific for me to look at? – Michel Keijzers Jul 16 '19 at 19:12
• @newbie I have corrected my code. The sign thing didn't work as I thought it would, so I now did it simply by multiplying with -1. Also I included a bit to to cut out the sign bits from whole_degree before shifting, so that the 1's there cannot make garbage values. Please again check, if this works for you. I hope, that it is correct now. I tested the calculations with a spare Arduino Nano and a mockup value (The one you posted as comment should result in 28,625°C) – chrisl Jul 16 '19 at 19:18

Why not rewrite the dallas() function so that it returns a float?

``````#include <OneWire.h>

OneWire ds(A0);

float dallas(OneWire& ds, byte start = false) {
int16_t temp;
do {
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
ds.reset();
ds.write(0xCC);
ds.write(0x44, 1);
if (start) delay(1000);
} while (start--);
return (temp * 0.0625);
}

void setup {
dallas(ds, true);
}

void loop {
float currentTemp = dallas(ds);
}
``````