1-wire-ds18b20-nanoframework

1-Wire en nanoFramework: sensor DS18B20

  • 4 min

El bus 1-Wire es un protocolo de comunicación que usa una sola línea de datos para hablar con uno o varios dispositivos.

Se usa mucho en sensores sencillos y memorias de identificación que necesitan pocos cables. El ejemplo más habitual es el sensor de temperatura DS18B20, presente en muchos proyectos de Arduino.

El nombre 1-Wire puede llevar a engaño. Normalmente necesitaremos datos y GND, y en la práctica es muy habitual alimentar el sensor también con VCC. El modo de alimentación parásita existe, pero no es lo más cómodo para empezar.

Cómo funciona 1-Wire

1-Wire funciona con una línea de datos compartida. El microcontrolador actúa como principal y los sensores como dispositivos seguidores.

Cada dispositivo 1-Wire tiene un identificador único de 64 bits. Eso permite conectar varios sensores en el mismo cable y que el microcontrolador pueda distinguir quién es quién.

La línea de datos necesita una resistencia de pull-up, normalmente de 4.7 kΩ, entre datos y VCC. Sin esa resistencia, el bus se queda flotando y empiezan las lecturas raras (y ahí es cuando uno mira al techo y empieza a sospechar del cableado).

Conexión típica de un DS18B20

Para un DS18B20 de tres patas, la conexión habitual es:

Pin DS18B20Conexión
GNDGND
DQPin de datos 1-Wire
VDD3.3V

Además, coloca una resistencia de 4.7 kΩ entre DQ y 3.3V.

En ESP32 no conectes el DS18B20 a 5V si la línea de datos va directa al microcontrolador. El ESP32 trabaja a 3.3V, y sus GPIO no son tolerantes a 5V.

Soporte 1-Wire en nanoFramework

nanoFramework incluye soporte para 1-Wire mediante el paquete nanoFramework.Device.OneWire.

En ESP32, las imágenes oficiales usan el periférico serie interno para implementar el bus. Por eso, antes de crear el host 1-Wire, conviene configurar los pines asociados al puerto usado por el firmware.

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

// En las imágenes oficiales de ESP32, COM3 se usa para 1-Wire.
// Ajusta los GPIO a los pines reales que estés usando en tu placa.
Configuration.SetPinFunction(21, DeviceFunction.COM3_RX);
Configuration.SetPinFunction(22, DeviceFunction.COM3_TX);

using OneWireHost oneWire = new OneWireHost();

if (oneWire.TouchReset())
{
    Debug.WriteLine("Hay dispositivos en el bus 1-Wire");
}
else
{
    Debug.WriteLine("No se ha detectado ningún dispositivo");
}
Copied!

Revisa el target de firmware que has flasheado. El soporte 1-Wire depende de que la imagen de nanoFramework tenga esa capacidad habilitada.

Buscar dispositivos

Una de las cosas interesantes de 1-Wire es que podemos buscar los dispositivos conectados al bus. nanoFramework expone métodos como FindAllDevices, FindFirstDevice y FindNextDevice.

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

using OneWireHost oneWire = new OneWireHost();

ArrayList devices = oneWire.FindAllDevices();

Debug.WriteLine($"Dispositivos encontrados: {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!

Esto nos sirve para comprobar que el cableado está bien y que el sensor responde. Si el listado sale vacío, casi siempre es pull-up mal puesto, pin equivocado o sensor alimentado incorrectamente.

Leer la temperatura de un DS18B20

El DS18B20 usa comandos definidos en su datasheet. Para un primer ejemplo, si solo tenemos un sensor en el bus, podemos usar Skip ROM (0xCC) para hablar con todos los dispositivos a la vez.

Después lanzamos una conversión de temperatura (0x44), esperamos a que termine y leemos el scratchpad (0xBE).

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

using OneWireHost oneWire = new OneWireHost();

// Iniciar conversión
oneWire.TouchReset();
oneWire.WriteByte(0xCC); // Skip ROM
oneWire.WriteByte(0x44); // Convert T

// Resolución máxima: hasta 750 ms
Thread.Sleep(750);

// Leer 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($"Temperatura: {temperature} ºC");
Copied!

Este ejemplo está pensado para entender el protocolo. En un proyecto real, es mejor usar un driver de alto nivel cuando exista, porque ya se encarga de detalles como CRC, resolución, errores de lectura y varios sensores en el mismo bus.

Cosas a vigilar

1-Wire es sencillo, pero tiene sus manías:

  • Resistencia pull-up: Sin ella, el bus no funciona de forma fiable.
  • Cables largos: Cuanto más largo el cable, más cuidado con ruido, capacidad y conexiones.
  • Varios sensores: Si conectas varios, deja de usar Skip ROM y selecciona cada ROM concreta.
  • Tiempo de conversión: El DS18B20 puede tardar hasta 750 ms a resolución máxima.

1-Wire es uno de esos protocolos que parecen antiguos, pero siguen siendo muy útiles. Con un cable de datos podemos tener varios sensores identificados individualmente, algo perfecto para temperatura distribuida, cámaras frigoríficas, acuarios o automatización casera.