In this tutorial we will learn how to get temperature measurements from a Maxim Integrated DS18B20 temperature sensor, using the ESP32 and the Arduino core.
In our introductory example, we will learn how to interact with the sensor and fetch temperature measurements periodically.
Note that, in order to focus on the functions needed to interact with the device, we will implement our reading logic in the Arduino main loop using some delays. For a more optimized approach, please check an example on how to use interrupts to perform periodic measurements. The example can be easily adapted for the sensor we are covering here.
The tests were performed using a DFRobot’s ESP32 module integrated in a ESP32 development board.
The DS18B20 is a digital thermometer that allows to get 9-bit to 12-bit Celsius temperature measurements (programmable resolution) [1]. The temperature conversion time depends on the resolution used. For a 9-bit resolution it takes at most 93.75 ms and for a 12-bit resolution it takes at most 750 ms [1].
The device is able to measure temperatures from -55°C to +125°C and has a ±0.5°C accuracy in the range from -10°C to +85°C [1].
Additionally, it has an alarm functionality with programmable upper and lower temperature trigger points [1]. These thresholds are stored internally in non-volatile memory, which means they are kept even if the device is powered off [1].
The sensor communicates using the OneWire protocol [1], which means it only requires a pin from a microcontroller to be connected to it. Furthermore, each sensor has a unique 64-bit serial code, allowing multiple DS18B20 devices to function on the same OneWire bus [1].
In terms of power supply, the device can operate with a voltage between 3.0 V and 5.5 V [1], which means it can operate with the same voltage of the ESP32 without the need for level conversion.
In order to facilitate the interaction with the device, we will need two libraries, which can be both installed using the Arduino IDE library manager.
The first one is the OneWire library, which allows to interact with devices using the OneWire protocol. The GitHub page of the library can be seen here.
Figure 1 shows how to install it using the Arduino IDE library manager. After opening that tool, just type “OneWire” on the search box and install the highlighted library.
Figure 1 – Installing the OneWire library.
Additionally, we will need this library, which offers a higher level API to interact with DS18B20 temperature sensor.
Figure 2 shows how to search for this library and how to install it using the library manager. Just type “DS18B20” on the search box and install the highlighted library.
Figure 2 – Installing the higher lever library for the DS18B20 library.
In this case, the library include we will use is DallasTemperature.h because it supports other sensors from the Dallas Semiconductor brand. Nonetheless, Dallas Semiconductor was acquired by Maxim Integrated in 2001 [1], which is why I’ve mentioned in the introductory section that this sensor is from Maxim Integrated.
For this tutorial, I will be using this waterproof version of the DS18B20 sensor, which gives much more flexibility regarding the scenarios where it can be used. Additionally, I will be using this adapter, which already contains pull resistors and a more user friendly wiring terminal.
Figure 3 illustrates the connection between the ESP32 and the DS18B20. I’m assuming the use of the previously mentioned adapter, which is why the pull resistor is not included.
Basically, we only need to connect the data pin of the sensor to a GPIO of the ESP32, use a common ground and supply a voltage of 3.3 V to the sensor. Note that in the image below the pin is generically labeled as “Data”, but depending on the module you are using it can have other naming.
Figure 3 – Connection diagram between the ESP32 and the DS18B20, assuming the use of the adapter.
If you are using the mentioned sensor version and adapter, take in consideration that the wires have the following color convention:
We will start our code by including the previously installed Arduino libraries, so we can interact with the temperature sensor using a higher level API, without having to worry about the lower level details of the OneWire protocol.
#include "OneWire.h" #include "DallasTemperature.h"
Next, we will need to create an object of class OneWire, passing as input of the constructor the number of the microcontroller pin that is connected to the sensor. I’ll be using pin 22 but you can use other if you want.
Note that this class exposes the methods needed to exchange bytes with the devices connected to the OneWire bus, as can be seen here. Nonetheless, we are not going to directly use the object we have created, since it will be used under the hood by the DallasTemperature.h library, hiding from us those lower level details.
OneWire oneWire(22);
Next we will need an object of class DallasTemperature, which will expose to us the higher level API that we will use to interact with the sensor.
The constructor of this class receives as input the address of a OneWire object (recall that we have just created one), so it can use it to exchange data with the sensor.
DallasTemperature tempSensor(&oneWire);
Moving on to the setup function, we will start by opening a serial connection, so we can output the measurements.
Serial.begin(115200);
Next, we call the begin method on out DallasTemperature object. This method will take care of initializing the OneWire bus.
tempSensor.begin();
Moving on to the Arduino main loop, we will take care of performing the actual measurements.
The first thing we need to do is calling the requestTemperaturesByIndex method on our DallasTemperature object, so it starts performing a temperature conversion. This procedure is needed before we can get the actual measurement.
One important thing to mention about the OneWire protocol is that it allows to connect multiple devices to the same bus (which means, to the same wire that is connected to our microcontroller digital pin).
So, both of the libraries we have installed take this in consideration and the classes we are using allow to communicate with multiple devices without the need to instantiate an object per device. This is why the methods we are going to use receive as input an index, which correspond to the index of the device we want to contact.
In our case, since we only have a single sensor connected to the bus, we can use the index 0.
By default, this function call will block until the conversion is complete. Nonetheless, we can call the setWaitForConversion method to change this behavior to be unblocking (it receives as input a Boolean value indicating if it should wait for conversion or not). Note however that, if we set this value to false, its our responsibility to make sure the time needed for the conversion has passed before we get the measurement. For this tutorial, we will keep it blocking.
tempSensor.requestTemperaturesByIndex(0);
After requesting a temperature measurement conversion, we can obtain it using the getTempCByIndex method, passing again as input the index 0.
This method will return the temperature in degrees Celsius, as a float. We will directly print this value to the serial port.
Serial.print(tempSensor.getTempCByIndex(0));
The final source code can be seen below. We have added some extra prints for better readability and a small delay between each iteration of the loop.
#include "OneWire.h" #include "DallasTemperature.h" OneWire oneWire(22); DallasTemperature tempSensor(&oneWire); void setup(void) { Serial.begin(115200); tempSensor.begin(); } void loop(void) { tempSensor.requestTemperaturesByIndex(0); Serial.print("Temperature: "); Serial.print(tempSensor.getTempCByIndex(0)); Serial.println(" C"); delay(2000); }
To test the code, simply compile it and upload it to your ESP32, assuming you have already completed all the wiring needed. Once the procedure finishes, open the Arduino IDE serial monitor.
You should start obtaining periodic temperature measurements, like the ones shown in figure 4.
Figure 4 – Output of the program.