¿Qué es un sensor DS18B20?
El DS18B20 es un sensor de temperaturas fabricado por la compañía Maxim Integrated. Proporciona la salida mediante un bus de comunicación digital que puede ser leído con las entradas digitales de Arduino.
Originalmente el sensor DS18B20 era fabricado por la empresa Dallas Semiconductor, que fue comprada por Maxim Integrated en 2001. Por ese motivo aún encontraréis referirse a este dispositivo como Dallas DS18B20, así como en Sketch y librerías.
El sensor DS18B20 es un sensor barato y, sin embargo, bastante avanzado. Dispone de un rango amplio de medición de -55ºC a +125ºC y una precisión superior a ±0.5°C en el rango –10°C de +85°C.
Una de las ventajas del DS18B20 es que se comercializa tanto en un integrado TO-92 como en forma de sonda impermeable, lo que permite realizar mediciones de temperatura en líquidos y gases.
El DS18B20 emplea un bus de comunicación denominado 1-Wire propietario de la empresa Maxim Integrated, aunque podemos usarlo sin tener que pagar por ninguna tasa (es parte del precio del dispositivo).
La principal ventaja del bus 1-Wire es que necesita un único conductor para realizar la comunicación (sin contar el conductor de tierra). Los dispositivos pueden ser alimentados directamente por la línea de datos, o mediante una línea adicional con una tensión de 3.0 a 5.5V.
Dentro del mismo bus 1-Wire podemos instalar tantos sensores como deseemos. Además, el bus 1-Wire permite emplear cables más largos que otros sistemas antes de que se deteriore la comunicación.
El DS18B20 también dispone de un sistema de alarma que permite grabar en la memoria no volátil del DS18B20 los limites inferiores y superiores. El bus 1-Wire permite consultar si algún dispositivo conectado ha activado una alarma.
El DS18B20 es un gran sensor para la medición de temperatura, tanto en ambientes domésticos como industriales. Sus características permiten crear redes con gran número de sensores para controlar, por ejemplo, la climatización o el sistema HVAC de un edificio comercial.
Precio
El DS18B20 es un sensor barato y excelente en calidad / precio. Podemos encontrarlo en su versión integrado TO-92 por 0.45€, y por 1€ en la versión sumergible, buscando en vendedores internacionales en eBay y AliExpress.
¿Cómo funciona el DS18B20?
Como hemos dicho, internamente el sensor DS18B20 es más complicado de lo que en principio podríamos creer. Está formado por un procesador con múltiples módulos, que se encargan de controlar la comunicación, medir la temperatura, y gestionar el sistema de alarmas.
Una de las principales ventajas de DS18B20 es su bus de comunicación 1-Wire que le permite realizar la transmisión empleando únicamente un cable de datos. Para ello, 1-Wire está basado en un complejo sistema de timings en la señal, entre el dispositivo emisor y el receptor.
La señal de comunicación empleada en 1-Wire, así como sus timings, son realmente largas y complejas. Para más información, consultar el Datasheet del dispositivo.
La mayor desventaja del sistema 1-Wire es que requiere un código complejo, lo que a su vez supone una alta carga del procesador para consultar el estado de los sensores. El tiempo de adquisición total de una medición de 750ms.
El dispositivo 1-Wire permite que todos los dispositivos conectados al bus se alimenten a través de la línea de datos. Para ello, disponen de un condensador que almacena energía mientras la línea de datos está en HIGH. Este modo se denomina “modo parásito”. En caso de no usar el modo parásito, los dispositivos deberán ser alimentados a una tensión entre 3.0V y 5.5V.
En cualquier caso, el bus 1-Wire requiere una resistencia de pull-up de 4k7 entre Vcc y Vq para que funcione correctamente.
Para poder dispone de múltiples dispositivos en un bus 1-Wire cada sensor dispone de una memoria ROM que es grabada de fábrica con un número de 64 bits. Los 8 primeros bits corresponden a la familia (0x28 para el DS18B20). Los siguiente 48 bits son el número de serie único. Los últimos 8 bits son un código CRC.
Esto significa que potencialmente podríamos llegar a tener 2^48 (más de 218 billones) de DS18B20 conectados en una misma red 1-Wire, además de otros tantos dispositivos de otras familias (2^28, unos 268 millones de familias de dispositivos posibles). A efectos prácticos, esto supone infinitos dispositivos.
La resolución del DS18B20 es configurable a 9, 10, 11 o 12 bits, siendo 12 bits el modo por defecto. Esto equivale a una resolución en temperatura de 0.5°C, 0.25°C, 0.125°C, o 0.0625°C, respectivamente.
Que el DS18B20 disponga de una resolución por defecto de 0.0625ºC, no significa que esa sea su precisión. Sin embargo, el DS18B20 es considerablemente preciso en todo el rango –10°C de +85°C. Podéis consultar las desviaciones medias a 3 sigma en la siguiente gráfica.
Esquema de montaje
Los dispositivos 1-Wire disponen de tres terminales
- Vq, la línea de datos
- Vdd, línea de alimentación
- GND, línea de tierra
En la siguiente imagen figura la posición de estos pines en ambos formatos del sensor, como integrado y como sonda impermeable.
Hemos comentado que el bus 1-Wire necesita una resistencia de pull-up de 4K7, y que podemos alimentar el sensor directamente a través del pin Vdd o usar el modo “parásito” y alimentarlo con la propia línea de datos.
Por tanto, el esquema más simple de conexión se muestra en la siguiente imagen, donde podemos conectar el sensor a cualquier entrada digital de Arduino.
Si representamos el mismo montaje, añadiendo la disposición que ocuparían los sensores adicionales (en caso de necesitarlos) observamos más claramente la estructura del bus 1-Wire.
Finalmente, si quisiéramos emplear el modo parásito, simplemente tenemos que conectar Vdd de todos los dispositivos a GND. De esta forma, los sensores tomarán su alimentación de la línea de datos Vq. El montaje con el modo parásito quedaría así.
Ejemplos de código
Para poder leer las temperaturas del DS18B20, necesitamos usar la librería 1-Wire y la librería Dallas Temperature.
En el primer ejemplo, leeremos un único sensor ubicado en el pin digital 5.
#include <OneWire.h>
#include <DallasTemperature.h>
const int oneWirePin = 5;
OneWire oneWireBus(oneWirePin);
DallasTemperature sensor(&oneWireBus);
void setup() {
Serial.begin(9600);
sensor.begin();
}
void loop() {
Serial.println("Leyendo temperaturas: ");
sensor.requestTemperatures();
Serial.print("Temperatura en sensor 0: ");
Serial.print(sensor.getTempCByIndex(0));
Serial.println(" ºC");
delay(1000);
}
Al usar la función getTempCByIndex, el indice es el número del sensor. Con esta función podemos leer más de un sensor instalado en un bus, pero tendríamos problemas para saber qué sensor es qué índice.
Por tanto, en caso de tener múltiples sensores lo normal es que accedamos directamente por la dirección de 64 bits del dispositivo. Para saber esta dirección, tenemos que usar el siguiente sketch, que escanea el bus 1-Wire y muestra en la pantalla su dirección en hexadecimal (agrupada en 8 números de dos dígitos).
#include <OneWire.h>
const int oneWirePin = 5;
OneWire oneWireBus(oneWirePin);
void setup(void) {
Serial.begin(9600);
discoverOneWireDevices();
}
void discoverOneWireDevices(void) {
byte i;
byte present = 0;
byte data[12];
byte addr[8];
Serial.println("Buscando dispositivos 1-Wire");
while(oneWireBus.search(addr)) {
Serial.println("Encontrado dispositivo 1-Wire en direccion");
for( i = 0; i < 8; i++) {
Serial.print("0x");
if (addr[i] < 16) {
Serial.print('0');
}
Serial.print(addr[i], HEX);
if (i < 7) {
Serial.print(", ");
}
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.print("Error en dispositivo, CRC invalido!\n");
return;
}
}
Serial.println("Búsqueda finalizada");
oneWireBus.reset_search();
return;
}
void loop(void) {
// nada que hacer aqui
}
Una vez que tengamos las direcciones de los dispositivos, podríamos realizar la lectura de múltiples sensores en el mismo bus 1-Wire.
En el siguiente ejemplo realizamos la lectura de dos sensores de los cuales ya hemos obtenido su dirección, uno en el interior y otro en el exterior de una vivienda, accediendo a través de su dirección.
#include <OneWire.h>
#include <DallasTemperature.h>
const int oneWirePin = 5;
OneWire oneWireBus(oneWirePin);
DallasTemperature sensors(&oneWireBus);
DeviceAddress insideThermometer = { 0x28, 0x94, 0xE2, 0xDF, 0x02, 0x00, 0x00, 0xFE };
DeviceAddress outsideThermometer = { 0x28, 0x6B, 0xDF, 0xDF, 0x02, 0x00, 0x00, 0xC0 };
void setup(void)
{
Serial.begin(9600);
sensors.begin();
sensors.setResolution(insideThermometer, 10);
sensors.setResolution(outsideThermometer, 10);
}
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print(tempC);
Serial.println(" ºC");
}
}
void loop(void)
{
Serial.println("Leyendo temperaturas");
sensors.requestTemperatures();
Serial.print("Temperatura interior: ");
printTemperature(insideThermometer);
Serial.print("Temperatura exterior: ");
printTemperature(outsideThermometer);
Serial.println("-------");
delay(2000);
}
Descarga el código
Todo el código de esta entrada está disponible para su descarga en Github.