DS18B20: Arduino Temperature Measurement made
Easy. Using One digital I/O pin, Instantly measure temperature using the
1-wire protocol; Find out why the chip has three connections when you only need two!
The DS18B20 : Do you want to measure temperature easily?...
...this chip is probably the easiest!
To read more temperatures around a house add more chips to your 1-wire system!
All you need is a spare digital I/O pin, ...
...install a library, and you're done.
It is a 0.5°C accuracy thermometer operating with a 1-wire interface
(there are also many other 1-wire chips - not only thermometers).
By clever design you can have many devices attached at intervals on
the same wire (each one has a unique id number). So you can easily
populate a building with multiple sensors without using individual wires for each one!
You can actually use it with any microcontroller that allows bi-directional I/O pin i.e. virtually
any modern microcontroller - then all you need is a bit of code.
Note: The DS18B20 can take its power
entirely from a data line pin requiring no positive supply other than that pin
- this means you can place it in locations that do not have an easily
accessible power source. You do need to add a ~5k pullup as the devices are
open drain and the idle state is bus high.
You can see that the DS18B20 has three connections so you would
expect that you must use three cables to allow operation. However in a
large installation e.g. a hotel with many sensors the cable costs can be
reduced by using only two wires! The third pin is used to supply local
power so you never need to use more than two wires for an installation.
Warning: You must add a pull-up resistor to the DQ line.
You always have to connect Ground and the DQ line - and you always
have to pull up the DQ line to allow communication - in two and three
pin mode.
Two wire operation
The really good thing about this sensor is that it uses a 1-wire interface
for multiple 1-wire devices - that
means you only need 1 signal wire and a ground return line i.e. a single two
core cable (the signal line can be used to power the devices!)
In this mode the chip draws power from the data line i.e. parasitic
power. This presents its own problem as now you have to ensure there is
enough power to drive the chip.
Three wire operation
You use the three wire connection where you have a local power source, supplying it to the chip on pin VDD. It means that you don't have parasitic powering problems in this mode.
DS18B20 Identification
Each 1-wire device, including the DS18B20, has a unique laser engraved
identifier so you can individually communicate with 1-wire devices. This is how
each sensor is distinguished from another on the same bus.
This is both good and bad; good because you can attach multiple devices and
bad (but not too bad) because you have to identify and locate each device e.g
in a large building installation you have to get the ID and log it in some
software that shows where it is.
The 1-wire interface is actually signal and ground so it should really be
called a '2-wire' interface; It is called 1-wire because it is taken for
granted that there is always a ground return path.
This temperature sensor is a digital sensor with a basic accuracy of 0.5°C
(and it only outputs data in °C) - it also has an adjustable resolution from
0.5°C (9bits) to 0.0625°C (12 bits) - the acquisition speed is affected by
the chosen resolution - from 93ms (9bit res.) up to 750ms - nearly 1s - for
max. res. of 12bits.
Note: You can attach multiple 1-wire
devices to a single I/O pin.
One of the key points about the device is that it does not always have to be
fully active because it performs a temperature conversion at higher power and
then stores the value in its own internal NV memory. This important if you use
the two wire mode GND and signal - parasitic power - where the signal wire also powers the
device.Acquisition Speed vs
Resolution
Note that resolution is not the same as accuracy - Any increase in
resolution does not increase the accuracy at all rather it just allows you to
monitor relative changes more easily.
Note: Resolution is calculated from the
data representation in Table 1 in the datasheet where hex code 0 is 0°C
and hex code 8 is 0.5°C therefore 1 bit represents 0.5/8 °C or 0.0625°C (at
12 bit resolution).
Remember that the lower bits of the device output hex data must be ignored
when using lower resolutions because the values of these bits are undefined so
make sure they are zero when you use the output data.
Pinout
Do not wire this backwards - it will blow up - make sure you use the correct
DS18B20 pinout to wire it up!
Note: Some datasheets use the label "ds18b20-par" - the par text just stands
for parasitic powered.
Power Sources
There are two ways to power a DS18B20 :
External 3-5V power supply.
Parasitic power (from the data line of the microcontroller).
Warning : I thought I could get away with just powering the
DS18B20 using GND and VDD, and using only a signal wire : Nope
- you must have a pullup resistor from the chip control pin to the Vcc pin of about 4k7
As Well (I used 3k3 at a pinch).
If you don't, the Arduino library (1st example below) can not see the
device. The device must be pulled-up with a resistor when the signal wire is
tristate (even with GND and VCC supplied). If you do not do
this you'll just see the message "No more addresses.". This be due to the
signal method used (open collector) - so don't forget (as I did) that the
pull-up is not just supplying power.
Only a single pull-up will be needed and it can be placed close to the
microcontroller pin.
External Power Supply
The first method "external power" is the better way for correct
operation but requires a local source of power - also either method is fine for use on a microcontroller development board.
Since these devices can operate
over very long cable distances i.e. within a building it is not always
convenient to connect to a power supply where you want to measure the
temperature. In this case you would use the Parasitic Powering method but there are complications:
Parasitic power
Parasitic power is power derived from the single 4k7Ω pull-up
resistor on the
One-Wire bus (I use a 1kΩ sometimes - its not that crucial on a local
board - but the lower the resistance the more current is used) and fed
into the DQ line while you keep the VDD pin at Ground - this indicates that the chip should use parasitic power.
TIP: Connect VDD pin to ground to indicating use parasitic power mode
Parasitic power charges an internal capacitor in the 1-wire
devices so there is still some energy there when the bus is pulled low by
another device. The key issue with this is that during an internal EEPROM write
(to the DS18B20) or while updating the temperature reading, up to 1.5mA can be
drawn.
Using the pull-up resistor alone to supply power, can cause the voltage
supplied to the DS18B20 to drop possibly causing a reset. One solution is to
use a stronger pull-up resistor e.g. 1kΩ.
Note: You can use a stronger pullup e.g. 1kΩ to allow more power.
The datasheet indicates that a strong current driver (a MOSFET from Vcc to
the 1-wire bus) should be used to supply power while these actions are
executing i.e. to override the 4k7Ω pull-up - allowing more current to the
sensor.
The problem is that during the strong pullup action no other communication can be made over the onewire
bus. A write to the NV (twr in the datasheet) EEPROM can take a maximum
of 10ms (for the copy scratchpad
command) - for a convert command the pull-up is held for the conversion time
(93ms ~ 750ms)- that is how long the
strong pull-up must be held to ensure valid operation!
For continuous comms. i.e. communication with other devices use a power
individually supplied to the Vcc pin of the DS18B20. This may mean using a 3 core wire
instead of 2 wire or using a separate power supply at the DS18B20 device
location.
In the 'DallasTemperature' library provision is made to hold the
microcontroller pin high for a time to perform a similar action to the MOSFET -
most microcontroller pins have fairly high output current capability ~20mA.
Using this method will still stop bus communications though.
Note: You can mix parasitic and
external power devices on the same 1-wire bus. There is a mechanism to query
the device on how it is powered i.e. to avoid having to use strong pull-up for
an external powered device (see the datasheet).
Distance
Some people recommend a 30m maximum but the note below indicates 60m
can be achieved (even further 200m if a fet driver is used):
With any network system transmission line effects come into play and
it can get very complicated (the above application note goes into a
little detail about this).
Also in that note, is the concept of 'weight' which is a value
assigned to each device added to the bus (Each device has a value of
'weight' that shortens the maximum length of cable that can be used).
'weight' is measured in metres.
You start from the network 'weight', again measured in metres, and is
the total length of cable used in the network - and how much cable can
be driven. The examples quoted in the application note suggest that the
'weight' for using a simple pull-up is 200m. However by using active
pull-ups this can be increased to 500m.
Each device added to the network adds a 'weight' cost to the network
since it loads the cable with capacitance - reducing the pull-up time
and also consuming power.
You can think of the 'weight' cost as the amount of cable "used up by each added device". If you added 30 devices of
'weight' cost 1m then the maximum cable length would have to be reduced
by 30m. Note that this is a simple view and the achievable length may be
shorter due to cable connections causing transmission line reflections
but it is a good starting point.
Cable Type
The recommended wire is CAT5 and you arrange them as a bus or a daisy
chained chained network - helping to avoid transmission line reflection
problems - as opposed to a star network.
Originally the 1 wire protocol was intended for PCB communication only but
its use grew into networked topologies with 100's of metres of cable. In fact
using special driver considerations, 500m is achievable.
There are many different topologies for DS18B20 layout
including linear, linear with stubs, star network and switched linear (see the
diagrams below). The maxim application note AN148 has a lot of detailed
information on types of networks that can be used:
The following figures are extracts from the that application note.
DS18B20 Network Connections
There are many different ways to connect up multiple devices which
include the following layouts: Series, stubs, Star and switched.
Multiple Sensor Linear network with stubs
Multiple Sensor Star Network
Multiple Sensor Switched linear network
1-wire application notes
There is also a lot more information on 1-wire interfaces in general here (See the "1-wire" devices entry).
Temperature Sensor Alarm State
You can program into the DS18B20 upper and lower temperatures (into
non-volatile memory - internal EEPROM within the DS18B20 itself) so that if the
temperature goes outside the upper or lower limits an alarm condition is
created. This means you don't have to continuously poll each (of possibly
hundreds of devces) to check for an out of range temperature condition.
The master controller can issue an alarm search command at regular
intervals- any DS18B20 connected to the 1-wire bus that has an alarm condition
will respond. The controller can then find out which device has the alarm
condition flag set.
Both parasitic and external power connections can be used on the same
One-wire bus.
Note: Two DS18B20 devices are shown in
the following circuits, but the code will work just fine with one - since it
auto detects devices attached to the one wire bus.
The left hand device is parasitic powered (the so-called 1-wire interface
which is actually a 2 - wire interface - GND and signal) while the right hand
device is externally powered (3 - wire interface - GND, signal and power).
You can remove either device from the solderless breadboard and you'll
still get a temperature reading from the other one!
Arduino DS18B20 with multiple devices on a single bus
wire:
Parts List: Temperature Sensor Arduino Uno
project:
Device Used : DS18B20 (either on a breakout board or stand-alone).
4k7.
Breadboard.
Arduino Uno R3.
10uF Electrolytic.
Arduino Software Setup
IDE Version Used : 1.6.4
Board used : Arduino Uno R3
Library : OneWire V2.2
Example 1 OneWire Library
Arduino Library 1 (OneWire)
The first library is a user contributed i.e not included with the Arduino
IDE but you can still install it using the Arduino IDE library manager.
Install Library 1
Goto Menu Sketch --> Include Library --> Manage Libraries...
In the Filter Search type onewire.
Click on the OneWire Library.
Hit install.
Note: If you don't see the above library structure then you
have got the wrong IDE (the correct one is from arduino.cc).
The following code is the example included with the OneWire library (only
changed to put the OneWire bus (for the DS18B20) on pin 4 of the Arduino Uno
R3:
Note: Clicking any text in the box below will copy it to the
clipboard.
#include <OneWire.h>
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library
OneWireds(4);// on signal pin (a single 4.7K resistor is necessary)
voidsetup(void){
Serial.begin(9600);
}
voidloop(void){
bytei;
bytepresent=0;
bytetype_s;
bytedata[12];
byteaddr[8];
floatcelsius,fahrenheit;
if(!ds.search(addr)){
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for(i=0;i<8;i++){
Serial.write(' ');
Serial.print(addr[i],HEX);
}
if(OneWire::crc8(addr,7)!=addr[7]){
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch(addr[0]){
case0x10:
Serial.println(" Chip = DS18S20");// or old DS1820
type_s=1;
break;
case0x28:
Serial.println(" Chip = DS18B20");
type_s=0;
break;
case0x22:
Serial.println(" Chip = DS1822");
type_s=0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}ds.reset();
ds.select(addr);
ds.write(0x44,1);// start conversion, with parasite power on at the end
delay(1000);// maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present=ds.reset();
ds.select(addr);ds.write(0xBE);// Read Scratchpad
Serial.print(" Data = ");
Serial.print(present,HEX);
Serial.print(" ");
for(i=0;i<9;i++){// we need 9 bytes
data[i]=ds.read();
Serial.print(data[i],HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data,8),HEX);
Serial.println();
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_traw=(data[1]<<8)|data[0];
if(type_s){
raw=raw<<3;// 9 bit resolution default
if(data[7]==0x10){
// "count remain" gives full 12 bit resolution
raw=(raw&0xFFF0)+12-data[6];
}
}else{
bytecfg=(data[4]&0x60);
// at lower res, the low bits are undefined, so let's zero them
if(cfg==0x00)raw=raw&~7;// 9 bit resolution, 93.75 ms
elseif(cfg==0x20)raw=raw&~3;// 10 bit res, 187.5 ms
elseif(cfg==0x40)raw=raw&~1;// 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius=(float)raw/16.0;
fahrenheit=celsius*1.8+32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
Serial.print(fahrenheit);
Serial.println(" Fahrenheit");
}
Warning: Again as with the DHT22 code the above code uses hard coded
delays - they are also the maximum delays, so even for 9bits the code uses a 1s
delay! Of course you can change that but you have to be aware of it.
See the Dallas Temperature library: Asynchronous
mode for a different solution.
Output from above code
(oneWire Library).
This is the output from the Arduino serial monitor showing:
ROM data (The hard coded chip code and family code (28)),
Chip Type,
Scratch pad data,
Temperature in and °C and °F ( °F is calculated using a floating point
calculation).
Output with one sensor
Output with two sensors
Output with three
sensors
Example 2 A different library
(DallasTemp)
You can get the same results with this library but this one has more
functions for better control over devices on the one-wire bus.
Arduino Library 2 (DallasTemp)
Note: The MAX31850 DallasTemp library also supports the
DS18B20.
This library builds on the OneWire Library (references to the OneWire
library are accessed through the variable '_wire' in DallasTemperature.cpp). It
gives you a more complete access mechanism to control devices on the bus. In
addition it tailors the delays required before update to the resolution in use
(delays change with resolution). There is also an asynchronous mechanism to avoid wasting
processor time while the sensor updates.
Install Library 2
Goto Menu Sketch --> Include Library --> Manage Libraries...
In the Filter Search type dallas.
Click on the MAX31850 DallasTemp Library (this also supports
DS18B20).
The following sketch uses the OneWire and DallasTemperature libraries (Maxim
bought Dallas - hence the old name).
The first sketch is labelled "Simple"; Edit the pin 2 changing it to pin 4.
Then use saveas to Simple_DallasTemp in your Arduino Library folder (default
location). In the sketch below I added 2 more outputs as I have 3 DS18B20
devices on the bus - you can add as many output statements as device you
have.
#include <OneWire.h> #include <DallasTemperature.h> // Data wire is
plugged into port 2 on the Arduino #define
ONE_WIRE_BUS 4
// Setup a oneWire
instance to communicate with any OneWire devices (not just Maxim/Dallas
temperature ICs) OneWireoneWire(ONE_WIRE_BUS);
// Pass our
oneWire reference to Dallas Temperature. DallasTemperaturesensors(&oneWire);
voidsetup(void)
{ // start serial port Serial.begin(9600); Serial.println("Dallas Temperature IC Control Library
Demo");
// Start up the library sensors.begin();
}
voidloop(void)
{//
call sensors.requestTemperatures() to issue a global temperature // request to all devices on the bus Serial.print("Requesting temperatures..."); sensors.requestTemperatures();// Send the command to get temperatures Serial.println("DONE"); Serial.print("Temperature for the device 1 (index 0)
is: "); Serial.println(sensors.getTempCByIndex(0));Serial.print("Temperature for the device 2 (index 1)
is: "); Serial.println(sensors.getTempCByIndex(1));Serial.print("Temperature for the device 3 (index 2)
is: "); Serial.println(sensors.getTempCByIndex(2)); }
Output with three sensors
Asynchronous Delays
If you want the processor to do something else while waiting for a
temperature update there is a mechanism in the DallasTemperature.cpp code you
can activate called ASYNC Mode - a private boolean flag (waitForConversion) is controlled from a public
function:
// // sets the value of the waitForConversion flag
// TRUE : function requestTemperature() etc returns when conversion is
// ready
// FALSE: function requestTemperature() etc returns immediately (USE
// WITH CARE!!)
// (1) programmer has to check if the needed delay has passed
// (2) but the application can do meaningful things in that time voidDallasTemperature::setWaitForConversion(boolflag)
{ waitForConversion=flag;
}
// gets the value
of the waitForConversion flag boolDallasTemperature::getWaitForConversion()
{ returnwaitForConversion;
}
Simplifying the above, the member functions are:
setWaitForConversion(boolflag)
You can query the flag state using the public function:
boolgetWaitForConversion()
Basically, if the flag is true and you initiate a temperature update for a
device, then the code will return immediately - it is up to you to wait for the
required time. You could make an interrupt timer to trigger fetching of the
temperature while your code does something else e.g. updates a display, reads a
keyboard or reads another device such as a humidity sensor.
Note: The asynchronous delay mechanism
allows you to avoid wasting processing time while a sensor updates BUT it is up
to you to wait the appropriate length of time.
This mechanism is encoded within the library like this:
So the routine either returns to your code immediately or performs a delay
wait.
Sketch Example Non Blocking Code
The following example shows you exactly what non blocking code looks
like. The key idea is not that the code does something magic, it's just
that the member function:
requestTemperatures();
Does not wait for a result - it returns immediately. It is up to you
to wait for the minimum time before asking for a new result.
The code below performs a non-blocking read of the DS18B20 and then
periodically updates the value (5s period timer) to the serial port. To
demonstrate that other code can go full speed, the LED is flashed on and
off using a 500ms period timer.
// Copyright John Main: TronicsBench.com
// Free for use in non-commercial projects.
// DS18B20 simple non blocking mode
#include <OneWire.h>
#include <DallasTemperature.h>
#define LED LED_BUILTIN
staticlongsampleTime=5000;// Update repeat period.
staticlongtw=millis();// time was non-blocking timer for update.
staticlongtw2=millis();
byteledTog=0;
// setup DS18B20 objects
OneWireds(4);// on signal pin (a single 4.7K resistor is needed).
// Pass our oneWire reference to Dallas Temperature.
DallasTemperaturesensors(&ds);
voidsetup(void){
Serial.begin(115200);
Serial.println("DS18B20 in non blocking mode...");
sensors.begin();// Start up the library: starts in blocking mode as default.
sensors.requestTemperatures();// Send the command to get temperatures (blocking).
floatcelsius=sensors.getTempCByIndex(0);// Show what have got.
show_temp(celsius);
sensors.setWaitForConversion(false);// Makes request = async - non blocking mode.
sensors.requestTemperatures();// Start non blocking temperature retrieval.
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
}
voidloop(){
if(millis()-tw>sampleTime){
tw=millis();
// The following line of code is only non blocking due to previous use of:
// sensors.setWaitForConversion(false);
sensors.requestTemperatures();// Non blocking get temperatures - for next udpate.
floatcelsius=sensors.getTempCByIndex(0);// Show what have got now.
show_temp(celsius);
}
// Show activity i.e. that temperature measurement is non- blocking.
if(millis()-tw2>250){
tw2=millis();
digitalWrite(LED,(ledTog=!ledTog)?HIGH:LOW);
}
}
voidshow_temp(floatcelsius){
Serial.print("Temperature: ");Serial.print(celsius);
Serial.println("C");
}
ds18b20-non-blocking.ino
MAX31850
The MAX31850 library is also capable of supporting the DS18B20 plus a few
more temperature sensing 1-wire devices. So you could mix this sensor with the
DS18B20 on the same 1-wire bus. This library is more capable than the 1-wire
library alone.
The MAX31850 is a Cold-Junction Compensated Thermocouple sensor that is also
a OneWire sensor meaning you can choose any of the available thermocouples (K,
J, N, T, and E). As with the DSB1820 it has 12bit resolution. You buy a
different MAX31850 (with different end code in the part number) that is matched
to a specific thermocouple type (K, J, N, T, and E).
Note: To use the MAX31850 they say
(Adafruit) that you need to use the OneWire Library supplied by Adafruit -
which is a a bit naughty since they are making branches in code instead of
updating the original. I have not looked at it though - best to do as they say
if you want a MAX31850 to work!
Using a different thermocouple type increases the max min range or
sensitivity e.g type K has a -200?C to 1350?C range.
DallasTemp Library Functions :
(MAX31850,DS18B20)
The "MAX31850 Dallas Temperature" library has many useful functions that are
built on top of the OneWire library and if you are going to seriously use the
Maxim OneWire devices, then it is worth studying. To give you an overview
here's a list of the functions it provides:
Get started with an Arduino humidity sensor using the DHT11, which reports both humidity and temperature. Complete guide with full code for using this sensor
The Arduino delay function is an Extremely Useful function which you can use to get small delays. However, sometimes it's not the right function to use � there is another!
Control the colors of an RGB LED through Arduino code. This beginners guide covers connections and provides example sketches for interesting LED control...
Tired of wasting time trying to get the notoriously bad KY-032 IR sensor module to work reliably? How to use a 3 component substitute that actually works!
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.