La sonda de temperatura DS18B20 es una de las herederas de la DS1820 fabricada originalmente por Dallas Semiconductor (que ahora es Maxim Integrated) que utiliza el sistema de comunicaciones en bus 1-Wire, también desarrollado por la misma compañía.
El componente diseñado específicamente para sustituir a la DS1820 es la DS18S20, la DS18B20 que se analiza aquí añade más resolución a los 9 bits de la original.
Toda la familia de termómetros DS18X comparte un funcionamiento similar desde el punto de vista de la programación, que cabe generalizarse en buena medida al funcionamiento de los dispositivos 1-Wire.
La DS18B20 es una excelente sonda de temperatura para rangos «humanos» (entre -10°C y +85°C) por su precisión (hasta 12 bits) y sobre todo por su conversor analógico-digital que permite distancias de medida mayores que los termómetros similares pero analógicos, que son más sensibles a las interferencias electrónicas ya que entregan, por ejemplo, un nivel de tensión o una resistencia. En el caso de las DS18X la medida se presenta codificada como un valor digital que incluye la verificación de su integridad con un CRC. Una gran ventaja frente a las alternativas está ligada al protocolo de comunicaciones con el que trabaja, 1-Wire, que permite formar redes con varios dispositivos usando un único bus y por tanto un único pin genérico de entrada y salida (GPIO)
Como es muy económica y muy sencilla de usar desde el punto de vista de la programación, es un ejemplo muy adecuado para acercarse al funcionamiento del bus 1-Wire con Arduino.
Para usar rápidamente la sonda en la fase de producción, sin entrar en detalles de su funcionamiento o de las comunicaciones, existe una magnífica librería de lectura de temperatura desarrollada por Miles Burton, que puede utilizarse junto con la librería del bus 1-Wire para Arduino mantenida por Paul Stoffregen actualmente y derivada del código original de Derek Yerger. Aunque en realidad no hay una librería para la gestión del bus 1-Wire en el IDE de Arduino, se consideran éstas como un estándar de hecho.
Conexión del bus 1-Wire
El bus 1-Wire puede utilizarse conforme a dos modos de conexión. El más básico requiere tres hilos, dos de alimentación y uno de comunicaciones (que da nombre al protocolo) También es posible utilizar un modo de alimentación parásito que utiliza como alimentación la propia línea de datos manteniendo la estabilidad de la alimentación gracias a un condensador interno.
Tanto en el modo convencional como en el modo parásito debe conectarse una resistencia de 4,7 KΩ en paralelo entre la alimentación y la línea de datos. La resistencia debe disminuir de valor conforme aumente la longitud del cable. Dependiendo de la topología según la cual se conecte y el tipo de cable utilizado, se suele admitir que hasta unos 5 metros el valor anterior funciona bien, a unos 10 metros trabaja más estable si la resistencia es de 3,3 KΩ, a 20 metros con una resistencia de 2,2 KΩ y de 1,2 KΩ a 50 metros.
Cuando el trazado de la conexión (la topología de la red que se forma) distribuye de manera irregular los nodos del bus 1-Wire (en este caso las sondas de temperatura) es conveniente compensar la resistencia en diferentes puntos (nodos) del conexionado. Maxim publica una guía con directrices para conexiones 1-Wire fiables en distancias largas que es muy útil para dimensionar la red 1-Wire en distancias y condiciones poco convencionales o especialmente desfavorables.
Se supone que el bus puede alcanzar hasta 100 metros de longitud (dependiendo del tipo de cable) pero, si ya los anteriores valores de resistencias son variables y habrá que realizar pruebas de estabilidad, a grandes distancias lo más recomendable es asegurarse in-situ de que la instalación es siquiera viable y en su caso en qué márgenes funcionará, tanto desde el punto de vista estrictamente electrónico como de comunicaciones (velocidad)
En el modo parásito (sonda DS18B20-PAR) la alimentación se produce gracias al propio flujo de datos que, como decía antes, se estabiliza a nivel de tensión por el condensador interno. Puesto que la carga que el condensador es capaz de mantener es muy baja, debe mantenerse la alimentación en los periodos de inactividad de las comunicaciones para asegurar que el dispositivo no reinicie el funcionamiento en cada pausa.
Comunicaciones con el bus 1-Wire
El protocolo de comunicaciones del bus 1-Wire es bastante simple, consiste en iniciar la comunicación enviando una señal de reset durante 480 µs o más a nivel bajo, pulsos largos (60 µs) para enviar bits de valor cero y pulsos cortos (menos de 15 µs) para los bit con valor uno, formando paquetes de ocho bits. La velocidad estándar resultante está entorno a los 15 Kb/s pero se pueden llegar a conseguir velocidades superiores a los 100 Kb/s
Para identificar cada dispositivo conectado al bus se utilizan direcciones únicas de 8 bytes que incluyen uno como identificador del hardware, el más significativo, y otro para la verificación CRC, el menos significativo.
Como ocurre en otros protocolos similares, en el inicio de la comunicación se incluye la identificación del dispositivo y la operación que se desea realizar (como escribir en la memoria o leerla, por ejemplo)
Funcionamiento del termómetro DS18B20
Integrado dentro del encapsulado de la sonda se encuentra el circuito de alimentación del modo parásito basado en un condensador que se carga cuando hay señal a nivel alto y un sistema de detección de alimentación, una memoria ROM que almacena el número de serie del dispositivo (junto con el tipo y el CRC) una pequeña memoria de intercambio (scratchpad) en la que se almacena la configuración, la temperatura una vez convertida a formato digital, un generador de CRC para verificar la coherencia del valor digital de la temperatura y el sensor de temperatura. Además existen dos disparadores de alarma configurables a una temperatura mínima y a una máxima.
Para saber el número de serie (la «dirección» en el bus) de una sonda, cuando no hay otro dispositivo en el bus 1-Wire, se puede utilizar la operación de lectura de ROM (0x33) del DS18B20. Lógicamente, esto exige que sea la única sonda conectada al bus, o se produciría una colisión cuando varios dispositivos trataran de responder a la vez a la petición. El código de abajo es un ejemplo de cómo encontrar la dirección de un único dispositivo conectado al bus One-Wire.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
// Para trabajar con diferentes versiones he incluido en la carpeta de este programa OneWire.h y OneWire.cpp por eso se incluye con "OneWire.h" en lugar de <OneWire.h> #include "OneWire.h" // http://www.pjrc.com/teensy/td_libs_OneWire.html #define LEER_ROM 0x33 // Leer la dirección de la sonda (número de serie) cuando solamente hay una en el bus 1-Wire #define BYTES_DIRECCION 8 // Cantidad de bytes usados para definir la dirección de las sondas DS18B20 en el bus 1-Wire #define PIN_BUS_SONDA 8 // Número de pin de Arduino donde se conecta la entrada digital con la resistencia de 4,7 KΩ #define ESPERA_LECTURAS 1000 // Esperar 1 segundo entre lecturas consecutivas (>750ms) OneWire bus_sonda(PIN_BUS_SONDA); // Colocar una resistencia de 4,7 KΩ entre la alimentación y el pin de entrada al µC unsigned char direccion[BYTES_DIRECCION]; // Buffer para leer los datos de la dirección byte CRC; // Byte para almacenar el CRC calculado y mostrarlo en el error si no coincide con el cargado String texto_direccion; // Dirección mostrada en la consola void setup() { Serial.begin(9600); // Para mostrar por la consola los números de serie de los dispositivos encontrados while(!Serial); // Esperar a que el puerto serie esté preparado bus_sonda.reset(); bus_sonda.write(LEER_ROM,true); // Consultar la dirección de la sonda for(byte indice=0;indice<BYTES_DIRECCION;indice++) { direccion[indice]=bus_sonda.read(); // Almacenar en el buffer de la dirección los valores cargados del bus Serial.print(direccion[indice],DEC); Serial.print(" "); } Serial.println(); CRC=bus_sonda.crc8(direccion,BYTES_DIRECCION-1); // Para comparar el CRC del dispositivo if(CRC==direccion[BYTES_DIRECCION-1]) // Si el CRC no coincide mostrar un error en la consola { Serial.println("CRC correcto, la dirección es válida"); } else { Serial.println("Error de CRC. El Calculado ("+String(CRC,DEC)+") es diferente del leído ("+String(direccion[BYTES_DIRECCION-1],DEC)+")"); } } void loop() { } |
Para buscar las direcciones, también se pueden escanear todos los dispositivos conectados al bus e ir anotando los valores obtenidos. El siguiente programa permite identificar todos los nodos del bus asignado a un pin de Arduino leyéndolos uno tras otro. Como es lógico, para poder identificar cada termómetro individualmente, será necesario implementar algún sistema que lo identifique o conectarlo, almacenar el valor, desconectarlo y repetir el proceso para cada dispositivo, para lo que sería más rápido el sistema del ejemplo anterior.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
// Para trabajar con diferentes versiones he incluido en la carpeta de este programa OneWire.h y OneWire.cpp por eso se incluye con "OneWire.h" en lugar de <OneWire.h> #include "OneWire.h" // http://www.pjrc.com/teensy/td_libs_OneWire.html #define BYTES_DIRECCION 8 // Cantidad de bytes usados para definir la dirección de las sondas DS18B20 en el bus 1-Wire #define PIN_BUS_SONDAS 8 // Número de pin de Arduino donde se conecta la entrada digital con la resistencia de 4,7 KΩ #define ESPERA_LECTURAS 1000 // Esperar 1 segundo entre lecturas consecutivas (>750ms) #define LONGITUD_SEPARADOR_TEXTO 70 // Cantidad de veces que se escribe la letra que se usa para indicar que se han mostrado todos los dispositivos encontrados en el bus OneWire bus_sondas(PIN_BUS_SONDAS); // Colocar una resistencia de 4,7 KΩ entre la alimentación y el pin de entrada al µC unsigned char direccion[8]; // Buffer para leer los datos de la dirección byte CRC; // Byte para almacenar el CRC calculado y mostrarlo en el error si no coincide con el cargado String texto_direccion; // Dirección mostrada en la consola void setup() { Serial.begin(9600); // Para mostrar por la consola los números de serie de los dispositivos encontrados while(!Serial); // Esperar a que el puerto serie esté preparado } void loop() { if(!bus_sondas.search(direccion)) // Ya se han revisado todas las direcciones. Reiniciar la búsqueda en el bus. { for(byte contador=0;contador<LONGITUD_SEPARADOR_TEXTO;contador++) { Serial.print("-"); // Mostrar un separador en la consola para indicar que ya se han mostrado todos los dispositivos encontrados al escanear el bus } Serial.println(""); bus_sondas.reset_search(); // Reiniciar la búsqueda } else // Se ha encontrado un dispositivo (dirección) en el bus { texto_direccion=""; for(byte contador=0;contador<BYTES_DIRECCION;contador++) // El primer byte es el tipo de dispositivo y el último el CRC { texto_direccion+=String(direccion[contador],DEC)+" "; } CRC=bus_sondas.crc8(direccion,BYTES_DIRECCION-1); // Para comparar el CRC del dispositivo if(CRC!=direccion[BYTES_DIRECCION-1]) // Si el CRC no coincide mostrar un error en la consola { Serial.println("Error de CRC ("+String(CRC,DEC)+"!="+String(direccion[7],DEC)+")"); } else // La verificación de redundancia cíclica es correcta { Serial.println("Se ha encontrado un dispositivo en "+texto_direccion); } } delay(ESPERA_LECTURAS); } |
Una vez identificadas las sondas se pueden leer individualmente solicitando la conversión analógica-digital y cargando los datos del scratchpad. El siguiente programa de ejemplo muestra el proceso que puede seguirse para leer una lista de dispositivos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
#include "OneWire.h" // http://www.pjrc.com/teensy/td_libs_OneWire.html #define SELECCIONAR_SONDA 0x44 #define LEER_SCRATCHPAD 0xBE #define LONGITUD_SCRATCHPAD 9 #define REGISTRO_CONFIGURACION 4 #define REGISTRO_CRC 8 #define MASCARA_RESOLUCION 0B1100000 #define FRACCION_DS18B20 16.0 #define VALOR_MINIMO -10.0 #define VALOR_MAXIMO 85.0 #define VALOR_INCORRECTO 100.0 // Un valor mayor que el máximo o menor que el mínimo #define PIN_BUS_SONDAS 8 // Número de pin de Arduino donde se conecta la entrada digital con la resistencia de 4,7 KΩ #define ESPERA_LECTURAS 10000 // >750ms a 12 bits de resolución #define BYTES_DIRECCION 8 // Número de bytes (máximo) que tiene la dirección de cada dispositivo del bus #define BYTES_NOMBRE 32 // Número de bytes (máximo) que tiene el nombre que se asigna de cada dispositivo del bus #define DIGITOS_TEMPERATURA 9 #define TOTAL_DISPOSITIVOS 5 // Número de dispositivos conocidos conectados al bus OneWire bus_sondas(PIN_BUS_SONDAS); // Modo de alimentación parásito, colocar una resistencia de 4,7 KΩ entre la alimentación y el pin de entrada al µC unsigned char direccion[BYTES_DIRECCION]; unsigned char sonda[TOTAL_DISPOSITIVOS][BYTES_DIRECCION]={{40,203,133,221,6,0,0,45},{40,60,185,220,6,0,0,240},{40,234,188,221,6,0,0,219},{40,62,18,244,6,0,0,177},{40,21,59,221,6,0,0,23}}; unsigned char estancia[TOTAL_DISPOSITIVOS][BYTES_NOMBRE]={"Bodega","Oficina","Muelle","Acceso","Exterior"}; // Nombre de la estancia monitorizada char buffer_nombre[BYTES_NOMBRE+DIGITOS_TEMPERATURA]; // Para mostrar el nombre de la estancia del dispositivo encontrado float temperatura; unsigned long tiempo_transcurrido; unsigned long cronometro; boolean sondas_inactivas=true; void setup() { Serial.begin(9600); } void loop() { if(sondas_inactivas) // Las sondas están inactivas cuando ya se ha leído la temperatura convertida a digital { for(byte numero_dispositivo=0;numero_dispositivo<TOTAL_DISPOSITIVOS;numero_dispositivo++) // Recorrer todos los dispositivos conocidos { preparar_sonda(bus_sondas,sonda[numero_dispositivo]); // Enviar la señal de preparar dispositivo a cada sensor de temperatura conocido } cronometro=millis(); // Almacenar el momento en el que se prepararon las sondas sondas_inactivas=false; // Se está produciendo la conversión de temperatura analógica a digital, no volver a lanzarla } else // Ya se ha solicitado la conversión de temperatura { tiempo_transcurrido=millis()-cronometro; if(tiempo_transcurrido>ESPERA_LECTURAS) // Si ha transcurrido el tiempo necesario para que se complete la conversión analógica a digital (más un pequeño tiempo de seguridad) { for(byte numero_dispositivo=0;numero_dispositivo<TOTAL_DISPOSITIVOS;numero_dispositivo++) // Recorrer todos los dispositivos conocidos { temperatura=leer_sonda(bus_sondas,sonda[numero_dispositivo]); // Cargar el valor de temperatura del scratchpad if(temperatura<VALOR_MAXIMO&&temperatura>VALOR_MINIMO) // Si la temperatura es correcta { snprintf(buffer_nombre,BYTES_NOMBRE,"%s",estancia[numero_dispositivo]); Serial.print(buffer_nombre); Serial.print(": "); Serial.println(temperatura); } } Serial.println(""); sondas_inactivas=true; // Ya se han leído las temperaturas } } } void preparar_sonda(OneWire bus_sondas, unsigned char *direccion) { bus_sondas.reset(); bus_sondas.select(direccion); bus_sondas.write(SELECCIONAR_SONDA,true); // Iniciar la lectura sonda con alimentación en modo parásito } float leer_sonda(OneWire bus_sondas, unsigned char *direccion) { byte buffer_lectura[LONGITUD_SCRATCHPAD]; int lectura; //byte resolucion; //delay(ESPERA_LECTURAS); // >750 ms a 12 bits de resolución //bus_sondas.depower(); bus_sondas.reset(); bus_sondas.select(direccion); bus_sondas.write(LEER_SCRATCHPAD,false); // Leer datos for(byte indice=0;indice<LONGITUD_SCRATCHPAD;indice++) // Recorrer todo el scratchpad { buffer_lectura[indice]=bus_sondas.read(); // Almacenar en el buffer los valores del scratchpad } if(bus_sondas.crc8(buffer_lectura,LONGITUD_SCRATCHPAD-1)==buffer_lectura[REGISTRO_CRC]) // Si el CRC es correcto { /* // Si se trabaja con resoluciones diferentes a la máxima, que es lo habitual, se deben establecer a cero los bits no usados en cada resolución (que no serán válidos) resolucion=buffer_lectura[REGISTRO_CONFIGURACION]&MASCARA_RESOLUCION; Serial.print("Usando "); switch(resolucion) { case 0: // 9 bits, 0.5000 °C //Serial.print("9 bits"); buffer_lectura[0]&=0b11111000; break; case 32: // 10 bits, 0.2500 °C //Serial.print("10 bits"); buffer_lectura[0]&=0b11111100; break; case 64: // 11 bits, 0.1250 °C //Serial.print("11 bits"); buffer_lectura[0]&=0b11111110; break; default: // 12 bits, 0.0625 °C //Serial.print("12 bits"); break; } Serial.println(" de resolución"); */ lectura=(buffer_lectura[1]<<8)|buffer_lectura[0]; return (float)lectura/FRACCION_DS18B20; } else // Si el CRC no es correcto devolver un valor menor que el mínimo o mayor que el máximo para indicar que no es válido { return VALOR_INCORRECTO; } } |
Antes de comenzar a utilizar el bus 1-Wire, para evitar indeterminaciones propias del modo de comunicaciones con el que trabaja, la primera operación que debe realizarse es reiniciar (reset) todo el bus. Para leer cada dispositivo se activa seleccionándolo por su dirección. Una vez preparado el bus y elegido el dispositivo se puede enviar la orden que corresponda con la operación que se desea realizar.
En el caso de la sonda DS18B20 se utiliza la orden convertir temperatura [0x44] (Convert T, en la hoja de datos) que inicia el cálculo del valor de la misma expresado como un valor de 16 bits.
La precisión de la sonda DS18B20, como se indicaba la principio, es de 12 bits pero para mantener la compatibilidad con la original DS1820 es configurable a 9 bits (medio grado centígrado) así como a los valores intermedios comprendidos entre ellos.
Al solicitar a la sonda la conversión de la temperatura se inicia el proceso, como esta conversión necesita un tiempo para completarse, el termómetro avisa enviando el valor cero mientras está procesando y el valor uno cuando ya ha terminado. Dado que el modo de alimentación parásito no permite hacer uso de este método, para generalizar, se puede optar entre revisar la alimentación del termómetro o programar una espera fija entre 750ms y 94ms dependiendo de la resolución del dispositivo
resolución configurada | precisión obtenida | tiempo de lectura |
12 bits | 0,0625°C | 750,00 ms |
11 bits | 0,1250°C | 375,00 ms |
10 bits | 0,2500°C | 187,50 ms |
9 bits | 0,5000°C | 93,75 ms |
Para elegir la resolución se almacena en los bits 5 y 6 del byte 4 de la memoria, el «scratchpad» ya citado, un valor mayor cuanto mayor sea la resolución que se desea. Este valor podrá igualmente consultarse posteriormente para determinar la resolución que hay en curso conforme a la cual se están codificando las temperaturas.
La resolución por defecto de la DS18B20 (y la que con más frecuencia se utiliza) es la más alta, de 12 bits. Como en el arranque el registro de configuración contiene el valor correspondiente a esta resolución no será necesario realizar ninguna operación para trabajar en ese modo.
El byte menos significativo de los dos que se utilizan para codificar el valor de la temperatura siempre almacena información (en el orden correspondiente) y el más significativo almacena más o menos información dependiendo de la resolución (incluyendo el signo)
Una vez que la temperatura se ha convertido y la sonda ha avisado enviando un valor uno o se considera que el tiempo de conversión ya ha pasado (con un margen de seguridad, si se utiliza este método) se envía la orden de lectura de datos que sirve para que el dispositivo transmita el contenido de la memoria (scratchpad) Esta memoria contiene 9 registros de 8 bits que almacenan, en orden de envío
- el byte menos significativo de la temperatura que se ha calculado
- el byte más significativo que representa la temperatura
- un byte de alarma de temperatura alta
- un byte de alarma de temperatura baja
- el byte de configuración
- tres bytes reservados
- el byte de verificación de CRC
Tanto si el dispositivo devuelve como valor de temperatura 85°C (valor por defecto almacenado al encendido) como si el CRC no coincide con el calculado la temperatura no puede considerarse válida. Como el dispositivo no está preparado para medir valores de temperatura menores de -10°C pero sí puede almacenarlos por lo que también sería necesario descartarlos en caso de recibirse.
Juan Rios
Gracias por la excelente información.
Julio Marín
Muy bien explicado ! !
Buenos artículos, te sigo desde cerca, Almería.
😉
Víctor Ventura
¡¡Gracias, Julio!!
Querida Almería…
Un formidable observatorio el de Calar Alto, según tengo entendido 😉
Julio Marín
8-0
🙂
Leandro
Hola Victor, muchas gracias por la explicación.
En algunos diagramas (dejo referencia a continuación) el modo parásito difiere en lo que respecta a la conexión 3. Si entendí bien se indica que debe quedar conectada a GND también, lo mismo que la conexión 1. No estoy entendiendo si da lo mismo hacerlo o no 🙁
http://cetroniconline.blogspot.com.ar/2014/07/tutorial-arduino-iv-sensor-de.html
Por otra parte, si por ejemplo en vez de 2 tuviese 3 sensores de temperatura de este tipo, estará bien mantener el mismo valor para la resistencia o convendrá utilizar una resistencia más pequeña? El largo de cableado no será mayor a 2 metros.
Desde ya muchas gracias!
Saludos
Leandro, desde Argentina
Víctor Ventura
Hola, Leandro.
Muchas gracias por participar en el blog.
No me queda muy claro lo que preguntas, la edad debe estar mermando mi comprensión lectora, por favor, haced preguntas fáciles 🙂 De todas formas, voy a hacerlo lo mejor posible a ver si te puedo ayudar.
La resistencia de cada sonda debe ser la correspondiente a la longitud de su cable pero, entre la escasa diferencia de valor y el error tolerado de las resistencias comerciales no merece la pena que pongas diferentes resistencias en un bus de menos de dos metros para tres sondas.
Hasta donde yo sé (y mis pruebas confirman) la conexión del modo «completo» y «parásito» son tal como las describo en los correspondientes diagramas: con el pin DQ conectado a VDD con una resistencia de 4K7 (hasta cinco metros), con el pin 3 (VDD) al aire en el modo «parásito» o a VDD en el modo «completo». Dan ganas de usar solamente dos cables pero hay que recordar mantener la alimentación (por DQ) también cuando no hay transmisión de datos o el termómetro se reiniciará. Es un poco más difícil programar el modo «parásito», por eso, si no es terrible usar tres cables, prefiero el modo «completo».
Lo de «a mí me funciona» no es nada científico, lo sé, pero uso así el termómetro porque es lo que he entendido de la hoja de datos del DS18B20 y me ha funcionado como esperaba cuando lo he implementado. Si encuentras que hay algún error o que se puede hacer una mejora, por favor, avísanos y así podemos aprovecharnos todos del conocimiento, que en el fondo es el objetivo del blog.
Otra vez gracias por comentar en polaridad.es. ¡Vuelve pronto!
edwin
Muy interesante el articulo y sumamente esclarecedor. Estoy armando un dataloger para medir temperaturas y humedades a diferentes profundidades (15 y 30 cm) asi que espero cuando se aclare mi comprension lectora seguir tus indicaciones.
Un cordial saludo desde Corrientes/Argentina
Víctor Ventura
Gracias, Edwin, y mucha suerte con tu proyecto. Es poca profundidad, hasta con una limitada compresión lectora como la mía podría hacerse 😀
Saludos de vuelta. Me alegra que polaridad.es esté cada vez más cerca de Argentina 🙂
Julián
Hola Víctor, muchas gracias por la publicación, me fue de gran ayuda. Soy de Córdoba, Argentina y estoy desarrollando mi tesis de grado de la carrera de Geología. Estoy midiendo temperaturas del suelo con el ds18b20. Sinceramente no tengo idea de programación ni de electrónica así que estoy aprendiendo mucho de este campo. Pero así y todo me cuesta bastante, lo mío son las rocas jeje. He adquirido un datalogger arduino con este sensor y los resultados van muy bien.
Ahora, tengo una pequeña duda que es para mi trivial y quizás puedas ayudarme: cómo hace el sensor para registrar la temperatura? He estado investigando pero no encuentro información certera sobre si es un Resistor, un RTD o bien una termocupla. Desde ya muchas gracias por tu tiempo.
Saludos. Julián
Víctor Ventura
Hola, Julián.
Por desgracia, el fabricante no da muchos detalles de la construcción del DS18B20.
A juzgar por la clasificación que el fabricante, Maxim Integrated, hace de los sistemas de medida electrónica de la temperatura en su manual sobre la gestión de la temperatura, yo diría que el DS18B20 está basado en uno o varios transistores bipolares que aprovechan las características térmicas de las uniones PN (de silicio dopado) para determinar la temperatura. Como la salida DS18B20 es digital, está claro que también incluye un conversor AD a la salida de los transistores además de la lógica correspondiente a las comunicaciones 1-Wire.
A este tipo de dispositivos se les suele llamar «diodo de silicio» dentro de los dispositivos de medida de la temperatura, aunque la forma más correcta sería sensor de temperatura de banda prohibida (band gap) de semiconductor de silicio y su nombre viene de la unión base-emisor del transistor BJT.
Espero que esto te pueda servir por lo menos de punto de partida.
Gracias por participar en polaridad.es ¡Vuelve pronto!
P.D.
Saludos a tus rocas y recuerda que, si algún día decides serles infiel, la electrónica seguro que te recibe con los brazos abiertos 🙂
lalo
hola estoy trabajando con el mismo sensor y me muestra la temperatura den icrementos de 0.5 en 0.5 y necesito subir la precisión, a 12 bytes. me podrias explicar como hacer eso?
Víctor Ventura
Hola, Lalo.
La resolución de 12 bits (que, por cierto, es la configurada por defecto) se consigue activando los dos bits menos significativos del registro de configuración que está en el byte 4 de la memoria de intercambio (scratchpad).
Lo correcto es crear un nuevo valor con ese registro en el que los primeros 6 bits (más significativos) conserven su valor y los dos últimos (menos significativos) valgan uno (resolución de 12 bits).
Para leer la memoria intermedia se utiliza la orden 0xBE y para grabar 0x4E.
Si te fijas en el programa del ejemplo puedes ver que aparece comentado (líneas 85 a 103) el acceso a la resolución del termómetro DS18B20.
Espero que te resulte útil ¡Gracias por participar en el blog!
Marcelo
Hola, es muy interesante el articulo, pero necesitaria que alguien pueda ayudarme, ya que tengo conectado el sensore Ds18D20, y me tira siempre -127c, en el monitor serie del Arduino, alguien podrá ayudarme a solucionar el problema?
Saludos
Víctor Ventura
Hola, Marcelo.
Parece que no estás comunicando con el DS18B20 ¿Lo has encontrado al escanear el bus 1-Wire? ¿Accedes a él usando el identificador que has encontrado al escanear el bus?
Gracias por participar en polaridad.es
Robert Caro
Hola, necesito el DS18B20, lo quiero comunicar a un arduniono uno R3, como es la conexion?
De igual forma voy a conectar los datos a una pantalla led 16 x 12 con conversor I2C
Víctor Ventura
Hola, Robert.
La conexión del DS18B20 la tienes en los primeros esquemas del artículo. Dependiendo de que prefieras usar dos o tres hilos (alimentación parásita o completa, respectivamente) debes conectar GND del DS18B20 a GND de Arduino, DQ del DS18B20 a un pin de entrada de Arduino (el 8 en el ejemplo) y por medio de una resistencia de 4K7 a la alimentación (la salida 5V de Arduino), la alimentación puedes, opcionalmente, conectarla a VDD del DS18B20; en tal caso, sería el tercer hilo y estarías usando el modo de conexión de alimentación completa.
Saludos.
Miguel
Hola Víctor, gracias por todo lo que escribes.
Estoy usando este sensor y me funciona ok, el problema viene cuando le añado un lcd 2404 i2c que me da lecturas de -127.
Para el lcd utilizo: LiquidCrystal_I2C.h
¿Sabes si puede haber algún conflicto?
Gracias y un saludo.
Víctor Ventura
Hola, Miguel.
No me consta ningún conflicto entre el DS18B20 (1-Wire) y el PCF8574 (I2C).
Ahora mismo no tengo un display 20×04 pero acabo de probar juntas la librería LiquidCrystal I2C y la librería OneWire y puedo leer la temperatura del DS18B20 sin problemas.
Está claro que si la sonda te funciona si en el display pero no con él, hay algún conflicto entre el software que usas para uno y otro, pero creo que el problema no está en las librerías.
Suerte con tu proyecto y gracias por participar en polaridad.es.
Víctor
Hola;
He probado tu tutorial y al fin he hecho funcionar mi proyecto. Anteriormente utilizaba la libreria dallastemperature, pero debido a los delays que tiene, mi proyecto no funcionaba de manera correcta.
Estoy intentando cambiar la resolucion a 9 bits, pero no hay forma de hacer que me calcule la temperatura de forma correcta. ¿Que deberia de cambiar en el codigo que muestras?
Un saludo y muchas gracias de antemano
Víctor Ventura
¡Hola!
Para cambiar la resolución hay que escribir en el tercer bit de usuario (byte 4) del scratchpad el valor correspondiente en los bits 5 y 6: 00 para 9 bits, 10 para 10 bits, 01 para 11 bits y 11 para 12 bits.
Una vez cambiada, la resolución se mantiene en el DS18B20, así que se puede incluir el código en
setup
(no es necesario establecerla cada vez)Cuando la resolución es menor que 12 bits hay que «limpiar» los bits de datos que no se utilizan (el último a 11 bits, los dos últimos a 10 bits o los tres últimos a 9 bits)
Como normalmente se utiliza a 12 bits, no he descrito con mucho detalle el proceso de cambio de resolución en el artículo, así que incluyo ahora un programa de ejemplo con una función para cambiar la resolución por si a alguien más le puede resultar útil.
También he añadido la definición de las constantes relacionadas con la resolución (valores de resolución y máscaras, principalmente) para que la función sea más legible y más fácil utilizarla.
Víctor
Muchas gracias por tu nueva aportacion.
Pero ahora tengo otra duda.. Cuando hay saltos grandes de temperatura automaticamente me vuelve a los 12 bits…
Que estoy haciendo mal?
Un saludo y gracias de nuevo
Víctor Ventura
¿Con el código anterior cambia solo de resolución? En el contexto en el que puedo probar el código solo puedo variar entre dos y tres grados en el tiempo de integración y en esas circunstancias no me ha cambiado de resolución.
No sé qué puede ser lo que haga que se cambie sola la resolución (a lo peor encuentro un error en el código probando cambios extremos de temperatura, por ahora me parece que funciona bien) pero siempre puedes forzar una resolución concreta a cada lectura de temperatura. Si necesitas que realice las lecturas muy rápidas (supongo que es así, o no querrías usar menos resolución) forzando la resolución a cada lectura tardará un poco más pero al menos será funcional.
Víctor
Probando a calentar la sonda con el mechero salta a 12bits.. Incluso ahora estando en espera 3seg y dejandolo enfriar a veces salta a 12 bits…
Para forzarlo quieres decir que vaya al swich(resulucion=0)
no??
Un saludo
Víctor Ventura
Aquí lo que tengo es un integrado (no una sonda), si le acerco el mechero puedo liarla parda 😀
Lo que sí he conseguido es subir 12 °C con el soldador. Si ese cambio de temperatura es lo bastante drástico puedo confirmarte que el código funciona bien. Cuando tenga acceso a una sonda y a la estación de aire caliente lo verifico con un salto de temperatura brutal (más que eso no se me ocurre cómo) y así te lo aseguro.
Lo del cambio de resolución no es en el bloque
switch
(ten cuidado, lo que pones en tu comentario dentro deswitch
es una asignación). Si efectivamente la resolución cambiara con saltos grandes de temperatura, deberías establecer la resolución antes de pedir al DS18B20 que obtenga la temperatura (antes de usar la funciónleer_sonda
)Saludos.
Víctor Ventura
Ya he probado a calentarlo drásticamente y no hay ningún error en el cambio de resolución ¿Has descubierto por qué no te funciona?
Manuel
Acabo de hacer un programa con temporizacion sin delay, para hacer un intermitente de 10 ms. pero al incluir la lectura del ds18b20, esa temporizacion no me baja de aprox. 1 segundo. ¿Es posible hacer que se lea el sensor de temperatura sin que se produzcan delays? ¿Es por el tiempo de lectura o por que la libreria dallas temperature tiene algun delay?
A ver si me puedes ayudar, ya que si no tendre que utilizar un sensor distinto de temperatura del tipo analogico,, y seria una pena con lo bien que va este (el ds18b20)
Víctor Ventura
Hola, Manuel.
El tiempo mínimo de lectura del DS18B20 es de algo menos de 100 ms, pero eso no quiere decir que el el MCU no pueda estar haciendo otras cosas mientras. Ahora bien, si necesitas la lectura de la temperatura para realizar cada tarea de la temporización, me temo que tendrás que buscar algo más rápido, 10 ms es muy poco tiempo de integración para un DS18B20.
No me termina de quedar muy claro qué «temporizas» (¿haces algo cuando pasa cierto tiempo? ¿solamente 10 ms?). Tampoco entiendo muy bien lo de la intermitencia, pero sospecho que no será algo como el parpadeo de un LED si es tan rápida ¿Es un PWM o algo así? Lo mismo con más datos podemos ayudarte mejor.
Gracias por participar en polaridad.es y suerte con tu proyecto.
Manuel
Lo primero agradecerte la pronta respuesta.
El programa que estoy haciendo es el siguiente, esta aun bastante verde, pero en el estoy intentando que la temporizacion trabaje al tiempo que la lectura de sensores.
Es para una caldera de biomasa, en la cual tengo que sacar una intermitencia fija de aprox. 100, 200, 300 ms. no 10 como te dije, y una espera de aprox. 10 segundos, para manejar el sinfin de alimentacion.
La lectura del sensor no es necesaria para el funcionamiento de la intermitencia, es decir esta lectura solo controlaria la bomba del agua de circulación, pero si que veo que el tiempo de intermitencia es imposible bajarlo del segundo.
Creo que tu no usas la libreria Dallas temperature, ¿seriá necesario no usarla para que el MC pudiera pasar al ciclo de temporizacion sin entretenerse leyendo el sensor?
La lectura del sensor de temperatura de humos es para controlar el momento del encendido
Víctor Ventura
Hola, Manuel.
Si te sirven tiempos de 100 ms o mayores, no tendrías problema en utilizar el DS18B20 (a una resolución de 9 bits) pero si la temporización no depende de la integración de la temperatura ni siquiera ese sería un límite.
No utilizo la librería Dallas de Miles Burton (es la más conocida, supongo que te refieres a esa) porque la idea, como la de la mayoría de los artículos, es presentar el funcionamiento del dispositivo y de las comunicaciones que utiliza, 1-Wire, en este caso. Ciertamente hay algunos comentarios (no solo en polaridad.es) de usuarios de esa librería que hablan de retrasos al trabajar con ella ¿No te animas a usar el método que propongo en el artículo solo con las comunicaciones 1-Wire de PJRC? Creo que no tendrías problema con tu proyecto.
Saludos.
Manuel
De nuevo agradecerte tu atención,
la verdad es que supongo que tendré que hacerlo así como tu dices. Creo que eso implica saber la dirección del termómetro, ¿no? En caso de tener que cambiar la sonda por avería habría que averiguar la dirección de la nueva e introducirla en el programa, o en su caso ¿se podría incluir la parte de detección de la dirección en el propio programa para que la averigüe siempre?
Un saludo
Víctor Ventura
Hola, Manuel.
Sí, se puede detectar la sonda (o sondas) conectadas al bus 1-Wire, en el código de ejemplo del artículo puedes encontrar cómo hacerlo.
También es posible ignorar el identificador (la dirección) usando primero la operación
SKIP ROM
(0xCC) y luego la operación de integración de la temperaturaCONVERT T
(0x44), lógicamente, la lectura conREAD SCRATCHPAD
(0xBE) solo tendrá sentido si hay una única sonda en el bus 1-Wire.Es posible (re)configurar el programa al cambiar la sonda o, si prevés que puede ocurrir con frecuencia o que quien la debe cambiar no está al tanto, puedes incluir en el código la detección de la sonda. El único inconveniente que se me ocurre para este segundo caso es que, diferentes sondas, tomen datos de diferentes puntos; en tal circunstancia no sé cómo podría hacerse sin conocer el identificador (la dirección) de la sonda; la única solución pasaría por usar varios bus 1-Wire, uno por sonda.
Saludos.
Manuel
Hola Victor, de momento creo que no voy a dedicar mas tiempo a este sensor, me voy a decantar por el LM35 que ya lo tengo implementado, me sobra con ese, es que si no pierdo el norte del tema y tampoco tengo mucho tiempo, prefiero desarrollar la aplicación sin que me afecten cosas que no son al final tan importantes.
Me alegro de tu gran atención y me parece que te voy a seguir dando guerra con este y otros temas del arduino, por cierto para preguntarte algo sobre temas no expuestos en el blog, ¿hay alguna posibilidad?
Un saludo y muchisimas gracias.
Víctor Ventura
Hola, Manuel.
No tengas problema en preguntar cualquier cosa… tema diferente es que sea capaz de responderte 😀 Creo que es preferible que lo hagas en el blog, aunque quede un poco fuera de contexto, porque así hacemos una humilde contribución a la inteligencia colectiva, y quién sabe si no me das ideas para nuevos artículos 🙂
¡Suerte con el LM35 en tu proyecto!
marcos
Hola Victor. Muchas gracias por el tutorial. Aunque no entiendo todas las partes del código me ha funcionado a la perfección con tres sondas. Ahora estoy intentando que me imprima en una LCD 20X4 lo mismo que me imprime en el monitor serie. Lo único que consigo es que me imprime en la lcd a intervalos. Primero una temperatura, después otra, pero no las tres a la vez con su con su correspondiente zona.
Dos horas después de empezar a escribir este correo lo he logrado pero con otro código que incluye la librería Dallas. Si puede darme una pista de como escribir las instrucciones a la lcd dentro de su código, volveré a intentarlo. De todos modos gracias de antemano.
Víctor Ventura
Hola, Marcos.
Si te fijas en los comentarios anteriores verás que hace un par de meses ya probé juntas las librerías LiquidCrystal I2C y OneWire (aunque con un 16×02, no con un 20×04) y no encontré ningún problema.
No se me ocurre ninguna razón por la que te aparezcan unas temperaturas y no otras sino por un error en el código ¿Pasas el cursor a la siguiente línea a cada temperatura? Si no lo haces, escribir una temperatura (sin más) borrará la anterior.
Gracias por visitar polaridad.es
bertin juarez lasso
hola victor
estoy empezando a luchar con arduino y tengo pensado desarrollar un sistema de control de temperatura mediante un arduino y dos sensores 1820 de modo que se puedan activar dos reles de manera independiente.
he leido tu blog y me parece muy claro y sobretodo interesante
podrias echarme una mano
con gracias anticipadas
bertin
Víctor Ventura
Hola, Bertin.
Cuéntanos tus dudas, seguro que algo de ayuda podremos darte por aquí 🙂
Gracias por visitar polaridad.es
Eliezer
Hola estoy usando 3 DS18B20, primero ejecuto el programa para adquirir las dirección y me reconoce los 3, y después utilizo el programa para adquirir la temperatura de los 3 sensores y solo me muestra 2 sensores, puedes ayudarme por favor.
Víctor Ventura
Hola, Eliezer.
Seguro que podemos ayudarte pero va a hacer falta que des más información. En principio, si detecta tres sensores (y funcionan correctamente) deberías obtener tres medidas 🙁
Un saludo.
Pablo
Buenos días Victor, muy esclarecedor el trabajo, tengo una consulta acerca de los ds1820. Resulta que tengo que reparar unos equipos que llevan el ds1820 original, pero en el mercado actualmente estoy encontrando solo 18b20, lo cual no me sirve porque estos equipos no le hacen inicializacion a las sondas y, como estas arrancan trabajando con resolucion de 12 bits, las lecturas no son correctas.
Mi pregunta es, si yo consigo (mediante una placa) cambiarle la resolucion a la sonda, ¿esta resolucion queda guardada definitivamente en la sonda, o debo hacerlo cada vez que el dispositivo se inicie?,
en resumen, que si la configuracion queda guardada, puedo hacer un «inicializador», cambiarle la resolucion, y despues colocarlo en los equipos a reparar.
sera esto posible, o el scratchpad es volatil?,
Víctor Ventura
Hola, Pablo.
Sí, la configuración (la resolución) se queda almacenada y no se borra hasta que no la sustituyes por otra, así que tu idea de un «inicializador» parece viable.
¡Suerte con con esos DS18B30 y gracias por visitar polaridad.es
gonzalo
hola victor sabes cual es la cantidad maxima de ds18b20 que puedo conectar en un mismo bus?
Jorge Cabrera
Saludos, Gracias por el tutorial me aclaro algunas ideas, Tengo una pregunta ojala me puedas ayudar:: Tengo 4 sensores conectados en una Topologia tipo Estrella, los probé a una distancia corta (2 metros) y me funcionan perfectamente, luego los conecte a una distancia de 24 metros con un cable apantallado UTP CAT 6 cada sensor igualmente en topologia tipo Estrella y ya no me lee los sensores. ¿Como puedo mejorar la comunicación?
NOTA:
– Uso la topologia estrella por las necesidades de la aplicación (medir temperatura en diferentes áreas)
– He jugado con varios tipos de resistencias que mencionas en tu tutorial.
– EL cable que uso para conectar los sensores es UTP CAT 6 de la mejor calidad posible.
– La temperatura a sensar es de -8 °C a -2 °C
– La conexión del sensor es del MODO BÁSICO (tres hilos)
Agradezco algún concejo al respecto.
Mac
Hola Muy buenas!!
Me parerece muy interesante tu blog. Haber si me puedes ayudar en mi proyecto. Estoy utilizando un Arduino como esclavo. Ya existe pero para componenetes de DALLAS… A mi lo que me gustaria es recibir datos en Serial (TX/RX) y transmitirlos en 1-wire. Por esto necesito un codigo que me adapte el Arduino esclavo.
Muchiiisimas gracias de antemano!!
Ricardo Alegret Llorens
Muy buen día, interesante y completo artículo sobre la sonda DS18B20.
Tengo un problema 2 termometros con esta sonda usando 3 cables funcionaban bien, ahora marcan siempre 85 grados. Hice soldaduras con la placa conectada y recompilado pequeños cambios. ¿Se ha averiado la sonda. ¿Como saberlo?. Si alguien puede orientarme lo agradeceré. Saludos y gracias.
PabloA.
Muy buen articulo!.
Les consulto si alguien sabe cuánto se tarda aprox. en la comunicación con el DS18B20 hasta mandarlo a convertir y luego el tiempo para leer la temperatura?.
Mas que nada el tiempo total insumido en cada etapa.
Como para tramitir/leer son tiempos cortos, la idea es usar «tiempo de main» y quiero ver si no es mucho, para bloquear otros procesos.
Por las dudas aclaro, no estoy hablando del tiempo que hay que darle para que pueda convertir, sería los tiempos de antes y después de eso.
Gracias.
Frank Phorlakis
Estimado Señor Victor. Me gustaria hacerle una consulta sobre OneWire sobre un proyecto en el que trabajo que en vez de utilizar la conexión con sensores de temperatura estoy utilizando ibutton, el problema consiste que realizar esta conexion OneWire la tiene predispuesta un equipo con el que estoy trabajando, que esta funcionando con un ibutton. La idea es eliminar el ibutton y colocar un lector de tarjetas RFID, sabemos que hay ciertos protocolos o forma de conectarse pero no hemos podido lograr realizar esta conexion para eliminar la funcion del ibutton reemplazado por las tarjetas RFID, podria ayudarnos con este proyecto? al menos una idea o ayuda para continuar, podria contactarnos via skype y le explicaria mejor la problematica, muchas gracias de antemano.
Diego Ramos
Buen día Víctor, muchísimas gracias por compartir tanta info, excelente tu blog, solo me queda una inquietud, yo necesito cablear el sensor mínimo 20 metros, hay que usar un cable especial para grandes distancias o que cable me recomendarías para unos 50 metros de longitud. Desde ya muchas gracias. Diego de argentina