arduino intermediate 25 min

Arduino: read temperature with a DS18B20 one-wire sensor

Wire a DS18B20 temperature sensor to an Arduino using the OneWire protocol. Multiple sensors on one pin, accurate to 0.5C.

Code available for: Arduino CESP32 ArduinoMicroPythonPython
Published Aug 4, 2026

The DS18B20 is the temperature sensor I reach for when accuracy matters. It is a “one-wire” sensor, which means you can put multiple DS18B20s on the same single Arduino pin and read each one individually.

This tutorial gets you from a fresh DS18B20 to a reading on the Serial Monitor in about 25 minutes, then shows you how to add more sensors on the same wire.

What you need

  • Arduino (Uno, Nano, etc.)
  • DS18B20 (the bare TO-92 package, or the waterproof stainless steel probe)
  • 4.7k resistor (for the pull-up)
  • Jumper wires

The waterproof version comes pre-wired with red (VCC), black (GND), and yellow (data). It is about $3 and is great for outdoor projects.

Wiring

DS18B20 GND -- Arduino GND
DS18B20 DATA -- Arduino pin 2 --[ 4.7k pull-up ]-- Arduino 5V
DS18B20 VCC -- Arduino 5V

That pull-up resistor is mandatory. Without it, the one-wire bus does not work.

For multiple DS18B20s on the same pin, just connect all the data lines to the same Arduino pin. Each DS18B20 has a unique 64-bit address burned into it, so the Arduino can tell them apart.

Install libraries

In the Arduino IDE:

  • Sketch >> Include Library >> Manage Libraries >> search OneWire by Paul Stoffregen. Install.
  • Also install DallasTemperature by Miles Burton. Install.

The code

Arduino (Uno, Nano, Mega)

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

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

void setup() {
  Serial.begin(9600);
  sensors.begin();
}

void loop() {
  sensors.requestTemperatures();
  float tempC = sensors.getTempCByIndex(0);
  Serial.print("Temperature: ");
  Serial.print(tempC);
  Serial.println(" C");
  delay(2000);
}

Upload it. Open Serial Monitor. You should see the temperature.

ESP32 (Arduino)

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

#define ONE_WIRE_BUS 4   // any GPIO; pin 4 avoids the boot-strapping pins

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

void setup() {
  Serial.begin(115200);
  sensors.begin();
}

void loop() {
  sensors.requestTemperatures();
  float tempC = sensors.getTempCByIndex(0);
  Serial.print("Temperature: ");
  Serial.print(tempC);
  Serial.println(" C");
  delay(2000);
}

Same libraries, same code. The ESP32 version uses 115200 baud over its USB-serial bridge and a different GPIO pin (the Uno’s pin 2 is not an GPIO on the ESP32; pick any other pin).

MicroPython (ESP32 or Pico)

from machine import Pin
import onewire, ds18x20
import time

# ESP32: GPIO 4. Pico: GP4.
ow = onewire.OneWire(Pin(4))
sensor = ds18x20.DS18X20(ow)

roms = sensor.scan()
print(f'Found {len(roms)} DS18B20 sensor(s)')

while True:
    sensor.convert_temp()
    time.sleep_ms(750)
    for rom in roms:
        t = sensor.read_temp(rom)
        print(f'Temperature: {t:.1f} C')
    time.sleep(2)

The ds18x20 driver is in micropython-lib. Install with mip install ds18x20 on the Pico, or copy onewire.py and ds18x20.py from the MicroPython repository into the ESP32’s /lib/.

Raspberry Pi Python

The Raspberry Pi does not have OneWire support in the kernel’s GPIO driver by default. To read a DS18B20 on the Pi:

  1. Enable 1-Wire on the GPIO: add dtoverlay=w1-gpio to /boot/config.txt (or /boot/firmware/config.txt on Bookworm), then reboot.
  2. The sensor shows up at /sys/bus/w1/devices/28-*/w1_slave.
import glob
import time

def read_ds18b20(device_path):
    with open(device_path) as f:
        lines = f.readlines()
    if lines[0].strip()[-3:] != 'YES':
        return None
    raw = lines[1].split('=', 1)[1]
    return int(raw) / 1000.0

devices = glob.glob('/sys/bus/w1/devices/28-*/w1_slave')
print(f'Found {len(devices)} DS18B20 sensor(s)')

while True:
    for path in devices:
        t = read_ds18b20(path)
        if t is not None:
            print(f'{path}: {t:.1f} C')
    time.sleep(2)

This works on any Pi with the 1-Wire overlay enabled. The kernel driver handles the timing; the Python code just reads the sysfs file.

If you see -127.00 C, the sensor is not responding. Check the wiring, especially the 4.7k pull-up.

Reading multiple sensors

Each DS18B20 has a unique address. You can find the address of every sensor on the bus with this:

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

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress addresses[10];   // up to 10 sensors
int numSensors;

void setup() {
  Serial.begin(9600);
  sensors.begin();
  numSensors = sensors.getDeviceCount();
  Serial.print("Found ");
  Serial.print(numSensors);
  Serial.println(" sensors");

  for (int i = 0; i < numSensors; i++) {
    sensors.getAddress(addresses[i], i);
    Serial.print("Sensor ");
    Serial.print(i);
    Serial.print(": ");
    for (int j = 0; j < 8; j++) {
      if (addresses[i][j] < 16) Serial.print("0");
      Serial.print(addresses[i][j], HEX);
    }
    Serial.println();
  }
}

void loop() {
  sensors.requestTemperatures();
  for (int i = 0; i < numSensors; i++) {
    float tempC = sensors.getTempC(addresses[i]);
    Serial.print("Sensor ");
    Serial.print(i);
    Serial.print(": ");
    Serial.print(tempC);
    Serial.println(" C");
  }
  delay(2000);
}

Run the address-discovery sketch first. Copy the addresses into a config file. Then read by address instead of index, so the order does not matter when you swap sensors.

DeviceAddress outsideSensor = {0x28, 0xFF, 0x64, 0x1E, 0xC2, 0x00, 0x00, 0x9A};
DeviceAddress insideSensor  = {0x28, 0xFF, 0x57, 0x32, 0xC2, 0x00, 0x00, 0x4D};

void loop() {
  sensors.requestTemperatures();
  float outTemp = sensors.getTempC(outsideSensor);
  float inTemp  = sensors.getTempC(insideSensor);
  Serial.print("Outside: ");
  Serial.print(outTemp);
  Serial.print(" C  Inside: ");
  Serial.print(inTemp);
  Serial.println(" C");
  delay(2000);
}

Parasitic power mode

There is a wiring variant where the DS18B20 draws power from the data line instead of a separate VCC wire. Wire it like this:

DS18B20 GND -- Arduino GND
DS18B20 DATA -- Arduino pin 2 --[ 4.7k pull-up ]-- Arduino 5V
DS18B20 VCC -- Arduino GND   (yes, both GND and VCC to ground)

Then in code:

sensors.setWaitForConversion(false);

Parasitic power is finicky for sensors on long wires. I use it for short runs (under 3 m) where saving one wire matters. For anything longer, use the normal wiring with three wires.

Why the DS18B20 is great

  • Accuracy: 0.5 C from -10 to 85 C.
  • Range: -55 to 125 C (with degraded accuracy outside the calibrated range).
  • Resolution: configurable from 9 to 12 bits (0.5 C to 0.0625 C).
  • Multiple sensors on one pin: up to about 100 sensors on a single Arduino pin if your wiring is clean.
  • Wire length: up to about 100 m on a single twisted pair.
  • No calibration: each DS18B20 is factory-calibrated and the calibration data is stored in ROM.

That last one is the killer feature for multi-sensor projects. No per-sensor calibration, no per-sensor offset, no per-sensor lookup table. Plug them in and they report the right number.

When to use DS18B20 vs. DHT22 vs. BME280

  • DS18B20: temperature only, accurate, multiple sensors on one wire. Best for “monitor temperature in 5 places” projects.
  • DHT22: temperature and humidity, slow (one reading every 2 s), cheap. Best for “one sensor, indoor, hobbyist” projects.
  • BME280: temperature, humidity, pressure. I2C, fast, accurate. Best for “weather station” projects.

For outdoor projects with a long wire run, the DS18B20 is the right call every time.

What to build next

  • A multi-zone home temperature monitor.
  • A sous-vide controller (DS18B20 + relay + PID loop).
  • A greenhouse monitor with sensors in different soil beds.

The sous-vide controller is one of the next tutorials on this site. The greenhouse version is in the book Arduino Sensors.