1-wire-ds18b20-nanoframework

1-Wire in nanoFramework: DS18B20 sensor

  • 4 min

The 1-Wire bus is a communication protocol that uses a single data line to talk to one or more devices.

It is widely used in simple sensors and identification memories that require few wires. The most common example is the DS18B20 temperature sensor, present in many Arduino projects.

The name 1-Wire can be misleading. We will normally need data and GND, and in practice it is very common to also power the sensor with VCC. Parasitic power mode exists, but it is not the most convenient way to get started.

How 1-Wire works

1-Wire works with a shared data line. The microcontroller acts as the master and the sensors as slave devices.

Each 1-Wire device has a unique 64-bit identifier. This allows connecting multiple sensors on the same wire and enables the microcontroller to distinguish who is who.

The data line requires a pull-up resistor, typically 4.7 kΩ, between data and VCC. Without this resistor, the bus floats, resulting in erratic readings (and that’s when you stare at the ceiling and start suspecting the wiring).

Typical DS18B20 connection

For a three-pin DS18B20, the typical connection is:

DS18B20 PinConnection
GNDGND
DQ1-Wire data pin
VDD3.3V

Additionally, place a 4.7 kΩ resistor between DQ and 3.3V.

On ESP32, do not connect the DS18B20 to 5V if the data line goes directly to the microcontroller. The ESP32 operates at 3.3V, and its GPIOs are not 5V tolerant.

1-Wire support in nanoFramework

nanoFramework includes support for 1-Wire via the nanoFramework.Device.OneWire package.

On ESP32, the official images use the internal serial peripheral to implement the bus. Therefore, before creating the 1-Wire host, it is advisable to configure the pins associated with the port used by the firmware.

using nanoFramework.Device.OneWire;
using nanoFramework.Hardware.Esp32;
using System.Diagnostics;

// On official ESP32 images, COM3 is used for 1-Wire.
// Adjust the GPIOs to the actual pins you are using on your board.
Configuration.SetPinFunction(21, DeviceFunction.COM3_RX);
Configuration.SetPinFunction(22, DeviceFunction.COM3_TX);

using OneWireHost oneWire = new OneWireHost();

if (oneWire.TouchReset())
{
    Debug.WriteLine("There are devices on the 1-Wire bus");
}
else
{
    Debug.WriteLine("No device detected");
}
Copied!

Check the firmware target you have flashed. 1-Wire support depends on the nanoFramework image having that capability enabled.

Finding devices

One of the interesting things about 1-Wire is that we can search for devices connected to the bus. nanoFramework exposes methods like FindAllDevices, FindFirstDevice, and FindNextDevice.

using System.Collections;
using System.Diagnostics;
using nanoFramework.Device.OneWire;

using OneWireHost oneWire = new OneWireHost();

ArrayList devices = oneWire.FindAllDevices();

Debug.WriteLine($"Devices found: {devices.Count}");

foreach (byte[] serialNumber in devices)
{
    Debug.Write("ROM: ");

    for (int i = 0; i < serialNumber.Length; i++)
    {
        Debug.Write(serialNumber[i].ToString("X2"));
    }

    Debug.WriteLine(string.Empty);
}
Copied!

This helps us verify that the wiring is correct and that the sensor responds. If the list is empty, it’s almost always a poorly placed pull-up, wrong pin, or incorrectly powered sensor.

Reading temperature from a DS18B20

The DS18B20 uses commands defined in its datasheet. For a first example, if we only have one sensor on the bus, we can use Skip ROM (0xCC) to talk to all devices at once.

Then we initiate a temperature conversion (0x44), wait for it to finish, and read the scratchpad (0xBE).

using System;
using System.Diagnostics;
using System.Threading;
using nanoFramework.Device.OneWire;

using OneWireHost oneWire = new OneWireHost();

// Initiate conversion
oneWire.TouchReset();
oneWire.WriteByte(0xCC); // Skip ROM
oneWire.WriteByte(0x44); // Convert T

// Maximum resolution: up to 750 ms
Thread.Sleep(750);

// Read scratchpad
oneWire.TouchReset();
oneWire.WriteByte(0xCC); // Skip ROM
oneWire.WriteByte(0xBE); // Read Scratchpad

byte[] scratchpad = new byte[9];

for (int i = 0; i < scratchpad.Length; i++)
{
    scratchpad[i] = oneWire.ReadByte();
}

short rawTemperature = (short)((scratchpad[1] << 8) | scratchpad[0]);
double temperature = rawTemperature / 16.0;

Debug.WriteLine($"Temperature: {temperature} ºC");
Copied!

This example is intended to understand the protocol. In a real project, it is better to use a high-level driver when available, as it already handles details like CRC, resolution, read errors, and multiple sensors on the same bus.

Things to watch out for

1-Wire is simple, but it has its quirks:

  • Pull-up resistor: Without it, the bus does not operate reliably.
  • Long wires: The longer the cable, the more care is needed with noise, capacitance, and connections.
  • Multiple sensors: If you connect several, stop using Skip ROM and select each specific ROM.
  • Conversion time: The DS18B20 can take up to 750 ms at maximum resolution.

1-Wire is one of those protocols that may seem old but are still very useful. With one data wire, we can have several individually identified sensors, perfect for distributed temperature sensing, cold storage rooms, aquariums, or home automation.