Vous êtes sur la page 1sur 16

Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

Blog técnico sobre proyectos caseros de electrónica, informática y física.

Índice de artículos Página principal

El bus 1-Wire a bajo nivel - DS1820


Hoy os traigo una entrada sobre el bus 1-Wire y el sensor de temperatura DS1820, con bastante
contenido técnico y nivel de detalle, espero que la disfrutéis.

En la entrada anterior vimos cómo manejar de forma básica la conexión GPIO de una Raspberry
Suscribirse a
Pi 3. En esta nos comunicaremos con un sensor digital modelo DS1820, sin utilizar ningún driver
ni librería, es decir implementando a bajo nivel el protocolo 1-Wire empleado por el dispositivo. Entradas

Comentarios

Recomendar 0 Compartir

Entradas populares

Receptor coche RC de
dos canales
Alguien anónimo me
dejó un comentario en
esta entrada pidiendo
que, ya que había analizado el
transmisor, describiera también el
Los DS1820, DS18B20 o DS18S20 son sensores digitales de temperatura. Una especie de LM35 receptor. ...
digitales si lo preferís. Sus características principales son una resolución de 9 a 12bit, no
Conexión GPIO de
requieren componentes externos y se pueden alimentar desde el mismo bus de datos. Raspberry Pi 3
Este verano me
Lo he escogido para esta entrada porque necesitaba medir temperaturas con cierta precisión. compré una
Además me ha parecido un ejercicio digno de compartir, que entraña sutilezas técnicas de Raspberry Pi. ¿Es
extraño que alguien que escribe un
distinto tipo. blog de electrónica no tenga una
Raspberry? Tal vez. El caso...

Esquema de bloques Matamoscas


eléctrónico: flyback
Hace unas semanas
El sensor que vais a encontrar más fácilmente es el ds18s20. Es el sucesor del ds1820 ya pedí por correo un
descatalogado y es totalmente compatible en patillaje y protocolo. El segundo más habitual es el aparato poco común
ds18b20, un modelo ligeramente más avanzado que permite escoger la resolución entre 9 y 12 en España, o por lo menos yo no lo
he visto nunca. El caso es que lo
bits. Es compatible en patillaje pero algunos comandos son diferentes. pedí por curios...

Por último, también tenéis a la venta la versión más barata ds1822. Se trata de un modelo Utilizar un micrófono
económico con mayor margen de error. Si los anteriores tienen un error de más/menos 0.5ºC, en electret
este puede llegar hasta los 2ºC. Habíamos publicado
en esta entrada los
pasos a la hora de
registrar una señal, concretamente
una señal sonora. Habíamos
planteado más o men...

Multivibrador astable
a transistores:
explicación
El astable con dos
transistores NPN es
de los primeros circuitos que se
estudian cuando se habla de
transistores en conmutación. Como
su esq...
En la imagen superior está esquematizado el funcionamiento del sensor. Veamos primero cómo
Reparación de un cd-
funciona el bloque más a la derecha, el llamado Temperature Sensor. radio-casete
He pensado que
Los chips de la familia ds1820 tienen un oscilador cuya frecuencia no depende de la temperatura, podría empezar este

1 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

es fija. Dicho oscilador actúa como reloj interno y genera pulsos a un ritmo constante. Luego año publicando una entrada en el
blog, que lo tengo algo olvidado
tienen otro oscilador cuya frecuencia sí depende de la temperatura. Mientras el primero genera
desde el verano. Así que feliz año
pulsos a su ritmo, este último determina el tiempo de medición. nuev...

De esta forma contando cuantos pulsos ha generado el primero se puede saber durante cuanto Cómo funcionan las
etiquetas magneto-
tiempo ha estado abierto el segundo, así es como se calcula la temperatura.
acústicas (o
acustomagnéticas)
Bajo este bloque tenemos dos bloques más simbolizando las alarmas programables. Se puede En esta entrada
indicar un límite superior e inferior para los cuales el DS1820 responderá a un comando especial. quiero hablaros de un sistema anti
Esta característica se denomina alarma de temperatura. Es muy útil para buscar rápidamente hurtos que casi todos habréis visto.
Se utiliza desde hace unos años en
entre muchos sensores si alguno ha excedido los límites sin tener que leerlos todos uno por uno. muchos establecim...

Más abajo está el generador de CRC, hablaremos del CRC más adelante. La Distorsión
Armónica Total
(THD)
A su izquierda está el bloque llamado scratchpad. Es un registro que podemos leer y escribir
Cualquier aficionado a
por comandos. Lo usaremos para leer la temperatura. Este registro se comunica mediante la la música o a la
lógica de control con la ROM y el puerto 1-Wire. electrónica conoce lo que es la
distorsión. En este artículo
hablaremos de la importancia de la
La ROM es una memoria de sólo lectura donde está el número de serie del dispositivo. En no l...
cualquier bus donde hay más de un receptor conectado, se necesita una forma de identificar al
destinatario. En un bus SPI tenemos una línea dedicada Slave Select. En un I2C tenemos un Síntesis de cloroformo a partir de
código mitad fijo, mitad personalizado. Los dispositivos 1-Wire tienen un número de serie de productos de limpieza:
estequiometría
64bit que los identifica por si hubiera varios sensores conectados al mismo bus.
Hay multitud de productos
químicos en cualquier casa y las
El formato del número de serie es como sigue: reacciones entre ellos son múltiples
y variadas. Al mezclar, por ejemplo,
un álca...
Identificador de la familia: siempre será 10h para DS1820 y DS18S20. 28h para
DS18B20 y 22h para el DS1822. Este código nos dice el tipo de chip conectado, Obtener el esquema
podrían ser sensores, números de serie digitales, interruptores, memorias, etc. desde una placa de
circuito impreso
Número de serie propiamente dicho, 48 bit. Con 48 bits hay espacio para 1014 Pasar de una PCB al
identificadores diferentes por lo que la probabilidad de colisión es mínima. esquema es siempre
un coñazo, lo hagas como lo hagas.
Finalmente un byte de CRC. Cuando se transmiten datos a menudo algún bit se Además es fácil equivocarse y
pierde por el camino o se invierte. Un CRC es el resultado de una operación acabar liado con un circuito que no
matemática que se aplica en el emisor con todos los bits anteriores. Luego la ...
reproduce el receptor para comprobar si el mensaje ha llegado con alteraciones. Más
abajo lo explicaremos con detalle. Etiquetas

A la hora de lanzar un comando podemos hacerlo indicando el identificador al que va dirigido.


circuitos programacion
También hay un comando especial que omite la dirección y selecciona todos los esclavos física Perl PC
conectados. Como a priori no sabemos los códigos, hay un algoritmo para que el maestro microcontroladores sonido
descubra los identificadores de los esclavos conectados al bus. Sin embargo, como para este amplificadores estadística
artículo emplearemos un sólo sensor no será necesario. osciladores gnuplot raspberrypi
reciclado óptica linux telemandos
El último bloque es la fuente de energía parásita. Cada chip 1-wire tiene un condensador que se
carga a través del positivo de alimentación si está conectado. Si no está conectado el positivo, Otros artículos

entonces se carga mediante la linea de datos cuando está en nivel alto. El bus 1wire es de colector Utilizar un micrófono
abierto con resistencias de pull-up, por tanto la línea de datos está a nivel alto la mayor parte del electret
tiempo. Cuando el bus pasa a nivel bajo el chip se alimenta de la carga almacenada por el
condensador.

Controlar un
En cierto modo me recuerda un poco a los chips RFID en esta forma de extraer energía del
servomotor con el PC
propio lector. Como consecuencia el positivo de alimentación es opcional. Junto a la masa
común, tan sólo necesitan un cable para alimentación y datos. De ahí el término 1-Wire.

Ahora quisiera contaros algo de su "lado oscuro". Gracias a su bajo coste, pequeño tamaño y Frecuencímetro para
número de serie propio, se utilizan muchísimo para la identificación de piezas originales. Por el PC
ejemplo en los adaptadores de tensión de portátiles.

Teardown and exploration of Apple's Magsafe connector. Dentro del conector MagSafe de un Criptoanálisis del
Mac hay un chip 1Wire modelo DS2413, un doble interruptor capaz de controlar hasta 20mA. Es cifrado XOR simple
barato y muy práctico para encender y apagar el LED del conector. Pero la misma tecnología
resulta igual de práctica para rechazar cargadores no originales.

Adaptador de USB a
Es el caso de los cargadores para portátiles Dell, Inside the DELL AC Power Adapter - A mystery Serie
revealed. Cada cargador Dell tiene un chip DS2501 (o DS2502). Se trata de memorias EPROM.
Es decir, memorias que se pueden escribir pero no se pueden borrar. El fabricante guarda ahí los
datos referidos al adaptador: la tensión, el tipo de cargador, o la potencia máxima sobre todo. El
portátil lee dichos datos y determina si es compatible o no. Si no es compatible interrumpe la Programación PIC
para decodificar RC5

2 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

carga por precaución. De ahí que sólo se puedan usar cargadores originales.

Y sucede lo mismo con las baterías. El integrado DS2438 es un monitor inteligente de baterías.
Controla el nivel de carga, la corriente consumida o la temperatura. Adicionalmente dispone de Reparación de un cd-
radio-casete
una EEPROM de 40 bytes donde el fabricante escribe el tipo de batería, fabricante, número de
serie, fecha de fabricación, etc. Por un lado es perfecto para controlar en todo momento el estado
de la batería y prevenir accidentes, pero por otro lado hace que el dispositivo sólo funcione con
baterías originales. Bromas de alta
tensión

El protocolo 1-Wire
Demodular AFSK,
Hay dos tipos de bus serie: los que tienen una linea de reloj dedicada y los que no. desde cero

Como ejemplo del primer tipo tenemos los buses SPI o I2C, con una linea de datos y otra
independiente para sincronización. La ventaja es que la transmisión es más simple, más rápida y
más fiable. Pero necesitamos un cable extra para el reloj. El bus I2C a bajo nivel

Necesitar un hilo más no parece un gran problema para la comunicación Entre Circuitos
Integrados (I2C), o para los Periféricos Serie (SPI). Pero... ¿y si sólo tuviéramos un canal y no
hubiera forma de tener una señal de reloj paralela? Tal es el caso de un mando a distancia Decodificacion del
infrarrojo, una antena, un telégrafo, un CDROM, un cable telefónico o una banda magnética. protocolo RC5 usando
un PIC

Imaginad que para transmitir un 1 damos tensión a la línea durante un tiempo y para el 0 la
quitamos. Ahora imaginad que transmitimos muchos 0 seguidos. El receptor no tiene forma de Síntesis de cloroformo
saber si le están transmitiendo 0 todo el rato, si han apagado el receptor, o si se ha cortado el a partir de productos
cable. de limpieza:
estequiometría

Para evitarlo, en lugar de "tensión para 1, no tensión para el cero" se puede recurrir a invertir el
Decodificar Aiken
voltaje. Por ejemplo 12V para 0 y -12V para el uno. Se llama codificación bipolar.
Biphase con Perl

Aún así queda otro problema. Cuando se transmite mucho tiempo el mismo estado. Como el reloj
del transmisor y del receptor no son perfectos cada uno tendrá una deriva diferente. Al cabo del
tiempo la desincronización habrá llegado a la duración de un bit y se habrá perdido la cuenta de Resonancia mecánica
cuántos van. Esta condición se llama bit-slipping y es propia de las codificaciones Non Return to con copas II
Zero.

La mejor forma de solucionarlo es haciendo que la linea cambie de cuando en cuando siguiendo Espectroscopía
un patrón para que el receptor pueda ajustar su reloj y no se pierda. Hay codificaciones que en mediante
cada bit, sea cual sea su valor, cambian una vez. Estas codificaciones reciben el nombre de Self Transformada de
Fourier
clocking porque reúnen los datos y el reloj en la misma señal.

El protocolo 1 Wire está diseñado teniendo en cuenta lo anterior, y además para que la linea de
datos se mantenga en nivel alto el mayor tiempo posible. Blogs que me gusta leer

absorptions
Consiste en una especie de código morse. En reposo la linea se mantiene a nivel alto mediante Capturing PAL video with an SDR
una resistencia de pull-up. El valor recomendado es 5k. Menos de lo habitual para las (and a few dead-ends)
resistencias de pull-up. Esta resistencia debe ser baja para cargar el condensador de Electrónica: teoría y
alimentación como vimos antes. Si la resistencia fuese muy alta, el condensador tardaría mucho práctica
en cargarse y sólo se podrían transmitir señales de forma muy lenta para no reiniciar los chips. Funcionamiento de un router 4G

Ken Shirriff's blog


De todas formas el tiempo que tarda la linea en recuperarse depende de varios factores; como la Risky line printer music on a
resistencia de pull-up, la longitud del cable, el número de dispositivos conectados y si utilizan el vintage IBM mainframe

positivo para alimentación o el mismo cable de datos. Pentester.es


Undo Five/Nine (Crypto 300,
1-Wire tiene cinco componentes básicos: Lisbon CTF)

Radioafición y radiotecnia
Presencia. El máster lleva el bus a nivel bajo durante entre 480 y 600us. El condensador se Radio definida por software (SDR)
descarga y como resultado todos los dispositivos conectados se reinician. Acto seguido el máster (II)

libera la linea, y esta vuelve a nivel alto. Los esclavos 1-Wire al iniciar esperan un momento y Security By Default
llevan el bus a nivel bajo. Así el máster determina que hay al menos un elemento 1Wire Microsoft Anti Ransomware
conectado. A esa secuencia se le llama presencia. bypass (not a vulnerability for
Microsoft)

Wardog y el Mundo
Crisis, capítulo 11: Voy a ser
sincero contigo.

3 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

Escribir 0 y escribir 1. Es parecido al código morse. Para escribir un dato el máster lleva a
cero el bus durante un breve periodo. Si es un poco más de 1us y hasta 15us el receptor interpreta
un 1. Si es más largo, 60us, el receptor interpreta un cero.

El mecanismo realmente es más sencillo. Cuando el receptor detecta que la tensión ha caído a 0,
espera entre 15 y 45us y vuelve a comprobar la linea. Si para entonces ha vuelto a nivel alto se
trata de un 1, si continúa en nivel bajo, entonces se trata de un 0. Tras escribir un bit hay que
esperar un tiempo de reposo. Dicho tiempo recibe el nombre de timeslot, y está entre 60 y 120us.

Leer 0 y leer 1. Según el diseño del bus 1-Wire, el máster es quien inicia la lectura. Cuando el
máster quiere leer transmite un pulso breve, como si fuera a enviar un 1. Espera unos instantes y
muestrea. Si el chip quiere transmitir un uno, no hará nada, dejará que la linea suba y el máster
al tomar el valor leerá un uno. Si el chip quería transmitir un 0 mantendrá la linea sujeta durante
unos 15us. En tal caso cuando el máster vuelva a mirar el valor, leerá cero.

El máster debe muestrear el estado del bus tras el tiempo de recuperación, siempre antes de los
15us, y anotar el valor leído.

Esperar microsegundos

Llevamos unos párrafos hablando de microsegundos. ¿Hasta qué punto es viable hacer esperas
tan cortas?

Aún en el PIC más básico, funcionando a 4MHz, tenemos una instrucción cada microsegundo.
Esperar 10 microsegundos en un microcontrolador es inmediato, serían 10 instrucciones.
Esperar 10 microsegundos en un sistema multitarea como una Raspberry es imposible. Porque
aún ejecutando muchas más instrucciones por segundo, no hay forma de saber cuándo se van a
ejecutar, ni si la ejecución va a ser continua o interrumpida.

Vas a acabar esperando 5, 12 o 7us pero no los 10us exactos.

Para eso están los sistemas de Tiempo Real. No os dejéis engañar por el nombre, la característica
principal de un sistema Tiempo Real no es su velocidad de respuesta, es que es predecible. Un
sistema Tiempo Real puede demorarse 20ms en dar una respuesta. Pero siempre se demorará
esos 20ms más o menos. Y no unas veces 10ms y otras veces 500.

Linux, como decíamos, no es así. Es un sistema multitarea donde una actividad tiene un tiempo
asignado de CPU. Dicho tiempo se interrumpe varios miles de veces por segundo para ejecutar
otras tareas con mayor o menor prioridad. Lo más que nos pueden garantizar las funciones de
espera es no continuar hasta haber transcurrido al menos el tiempo deseado. Pero puede ser
más, y casi siempre suele ser más.

El protocolo 1wire tiene unas especificaciones de tiempo concisas. Como el programa lo vamos a
hacer en C, apoyándonos en la librería WiringPi, nos fijamos en la función delayMicroseconds.
Esta función espera un determinado número de microsegundos antes de continuar la ejecución.

Como ya sabemos que siempre va a esperar más de la cuenta, vamos a hacer un pequeño
programa que haga miles de llamadas de espera y cronometre el tiempo transcurrido en realidad.
Hemos medido el tiempo de espera para valores entre 0 y 300us en 100000 iteraciones.

4 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

t min avg max var


0 0 0.88 69 0.41
50 0 1.92 298 10.79
100 38 68.83 9691 1605.88
150 32 68.55 3208 341.54
200 32 68.90 13989 3197.04
250 33 69.00 8561 1488.61
300 24 69.07 10294 1967.54

Aquí t es el tiempo de espera solicitado en us, el argumento de la función si queréis. Los demás
valores se refieren al exceso de tiempo esperado respecto a t. O sea, si pido esperar 100 y acabo
esperando 138, el error es 38us.

min es el error más pequeño de todas las iteraciones para un tiempo dado. avg la media de los
errores. max es el máximo exceso que hemos medido y var, como podéis intuir, la desviación
típica.

Volviendo a leer la tabla, un momento... si pido esperar 200us, podría esperar 232 como poco y
hasta más de 14ms en algún caso. ¡Es una incertidumbre altísima! Podríamos resumirlo como
"tú pide lo que quieras, y yo esperaré lo que me apetezca".

¿Y si le damos mayor prioridad al programa? Cuando varios programas reclaman el uso de la


CPU, el que tiene mayor prioridad recibe una rodaja de tiempo más grande, o más rodajas de
tiempo en promedio. Con el comando nice podemos especificar una prioridad mayor.

Pero aquí no hablamos de consumo de CPU, sino de tiempo de espera. Los mayores errores se
producen cuando está a punto de terminar el contador pero la tarea se aparca para atender otros
programas ligados a la misma CPU. Para cuando la CPU retoma la tarea, el tiempo ya se ha
excedido.

Desde aproximadamente el año 2008 Linux incorpora ciertas características imitando a un


sistema Real-Time. En concreto, la programación de tareas llamada FIFO consiste en que una
tarea no abandona la CPU mientras siga usándola. Este comportamiento puede volver el sistema
inestable si un programa adquiere la CPU con prioridad máxima, ya que impedirá que se
ejecuten otros programas asignados a la misma CPU. Por eso sólo el administrador puede
asignar tal prioridad.

El comando chrt nos permite modificar el programador de tareas, así con chrt -f 99 estamos
indicando que queremos el programador Real-Time FIFO con prioridad 99.

Este es el efecto sobre el programa anterior:

t min avg max var


0 0 0.85 45 0.16
50 0 1.73 55 2.19
100 6 15.46 154 7.45
150 6 15.43 96 7.13
200 6 15.42 101 7.39
250 6 15.45 74 6.94
300 6 15.47 122 7.78

La incertidumbre ahora es mucho más baja; y el error máximo al menos es del mismo orden de
magnitud. Además, ahora el mejor caso se aproxima mucho más a tiempo de espera real.

La librería WiringPi tiene una función llamada piHiPri (). Funciona igual que si ejecutáramos el
comando sudo chrt -r 99. Asigna a la tarea la máxima prioridad asignable por el usuario sólo
que, en lugar el programador FIFO, emplea el programador de Tiempo Real RoundRobin, pero el
resultado es el mismo.

Aún así hay dos casos bien diferenciados: por encima y por debajo de 100us, fijaos en la media.
Para valores por debajo de 100us, en algún caso el error ha sido 0 y el error medio anda entre 1 y
2us de margen. Para valores superiores, en cambio, el mínimo error que podemos esperar es 6us.
Es decir, jamás esperaremos exactamente el tiempo previsto, siempre esperaremos como poco
6us más y, en general, 15 o 16us más.

Encontramos la razón mirando el código de WiringPi. Cuando el tiempo de espera es inferior a


100us delayMicroseconds utiliza un bucle para esperar. Esta técnica se llama busy waiting y

5 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

mantiene el procesador al 100% mientras espera. Para no mantener el procesador al 100%


durante más tiempo del necesario, para tiempos mayores de 100us hace uso de la función
nanosleep. La cual, como vemos, nos hace esperar en promedio 15us más.

En la siguiente imagen se aprecia mucho mejor el salto. En el eje horizontal están los tiempos de
espera solicitados hasta 500us. En el eje vertical el exceso de espera. En color azul los casos
comprendidos entre el mínimo y el máximo error. Y en gradiente una distribución normal con la
media y la varianza obtenidas. Si bien no tenemos garantía de que la distribución de los errores
siga una normal, con una varianza pequeña nos sirve para hacernos una idea.

Podemos forzar la espera en bucle llamando a la función delayMicrosecondsHard. Este es el


resultado:

t min avg max var


0 0 0.87 19 0.14
50 0 0.01 17 0.03
100 0 0.01 35 0.04
150 0 0.01 18 0.06
200 0 0.01 22 0.05
250 0 0.01 40 0.05
300 0 0.01 26 0.08

Ya lo veis, un error promedio menor de 1us en todos los casos y un máximo de 40us. Con estos
márgenes sí funcionará la comunicación 1-Wire.

Primitivas de 1-Wire

Ahora vamos a usar el bus para transmitir y recibir.

Aunque nosotros lo vamos a hacer desde cero, hay un módulo del kernel que sirve para
comunicarse con el ds1820. El procedimiento lo tenéis en multitud de páginas, por ejemplo
DS18B20+ One Wire Digital Temperature Sensor and the Raspberry Pi o también Adafruit's
Raspberry Pi Lesson 11. DS18B20 Temperature Sensing.

Para elaborar el programa seguiremos un esquema de desarrollo bottom-up, empezando por las
funciones más básicas y terminando en la función main.

En esta sección no vamos a entrar en los comandos del protocolo. Nos limitaremos al control
eléctrico del bus de datos y a leer y escribir bits.

La primera función se llamará low y sirve para llevar el bus a cero durante un periodo de tiempo
dado. Recordad que la linea de datos se encuentra por defecto en nivel alto debido a la resistencia
de pull-up.

Para eso definimos la patilla como salida, hasta ahora en estado de alta impedancia (entrada), y
escribimos un 0 lógico. A continuación esperamos el tiempo especificado y la volvemos a poner
como entrada.

1 /* Pulls down the bus for given us then releases it */ ?


2 void low(int pin, int us) {
3 pinMode (pin, OUTPUT);
4 digitalWrite (pin, LOW);
5 delayMicrosecondsHard (us);
6 pinMode (pin, INPUT);
7 delayMicrosecondsHard (TREC);

6 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

8 }

Aquí entra en juego un parámetro al que hemos llamado TREC. Significa Tiempo de
Recuperación y quiere decir cuánto tarda nuestro bus en recuperarse.

Los dispositivos 1-wire incorporan un condensador cuya capacidad depende del modelo. El
tiempo de recuperación va a depender de multitud de factores, como por ejemplo cuántos
esclavos hay conectados al mismo bus, la longitud de este, su resistencia y capacitancia, el valor
de la resistencia de pull-up o de si empleamos alimentación externa o parásita.

En nuestro caso, el tiempo de recuperación es bajo porque conectamos la alimentación externa.


Las resistencias de pullup incorporadas en la Raspberry son de 50kOhm, y lo recomendado es
5kOhm. Por tanto, si no queremos usar componentes externos debemos conectar el pin de
alimentación. Hemos definido TREC igual a 2us, por ejemplo.

Lo más fácil de escribir a continuación es la secuencia de presencia. Si recordáis, consiste en


retener la linea a 0V durante más de 480us. Según dice el datasheet los dispositivos pueden
aguantar sin corriente entre 480 y 960us. Luego 960us es el tiempo que debemos esperar para
garantizar que todos los dispositivos se han reiniciado.

A continuación, según vemos en la imagen, los esclavos esperan entre 15 y 60us y ellos mismos
llevan la línea a 0V durante un breve tiempo. Suficiente para medirlo sin dificultad.

Así pues, bajamos el bus durante 960us, esperamos 60 y leemos. Si hemos leído un nivel bajo
significa que hay algo conectado (devolveremos 1). De lo contrario no hay nada en el bus
(devolveremos 0). En otras palabras, devolvemos lo contrario al valor leído.

Por último damos un tiempo prudencial para que los dispositivos se inicien correctamente según
sugiere la imagen. 300us será suficiente.

1 /* Sends a reset pulse and waits for a presence response */ ?


2 int reset (int pin) {
3 int v;
4
5 low (pin, 960);
6 delayMicrosecondsHard (60);
7 v = digitalRead(pin);
8 delayMicroseconds(300);
9
10 return !v;
11 }

Lo siguiente será una función para transmitir un bit 0 o 1, la llamaremos send_bit. Tal como
habíamos visto, para enviar un cero el máster debe llevar la línea a nivel bajo durante el tiempo
que dura un timeslot, entre 60 y 120us.

Para enviar un uno, el máster debe bajar la linea durante un tiempo minúsculo de entre 1 y 5us y
luego liberarla hasta el siguiente timeslot, o dejarla así si no va a enviar más datos. En el
datasheet recomiendan más de 1us y menos de 15. Como las rutinas de espera siempre esperan
más de lo necesario, programamos 2us por ejemplo.

7 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

Así es como funciona en la práctica: el chip 1-Wire detecta la bajada de la linea, espera entre 15 y
60us y lee el estado del bus. Si es positivo entiende un 1 y si es negativo entiende 0. Ya está. No
olvidéis que si la dejamos en 0 durante mucho tiempo, más de 480us, a los chips se les agota el
condensador y se reinician.

TIMESLOT es una variable del programa. No es crítica, en la práctica funciona desde 25us en
adelante. El datasheet recomienda un mínimo de 60us y un máximo de 120, nosotros hemos
decidido fijarla en 90us.

1 /* Sends a 0 by pulling the bus for a whole time slot ?


2 * Sends a 1 by pulling just a bit 5ms,
3 * and then releasing it for the rest of time slot */
4 void send_bit(int pin, int bit) {
5 if (bit) {
6 low(pin,2);
7 delayMicrosecondsHard(TIMESLOT-5);
8 }
9 else {
10 low(pin,TIMESLOT);
11 }
12 }

Lo siguiente es leer un bit. Para leer un bit el máster debe llevar la línea a nivel bajo durante más
de un microsegundo. El dispositivo detecta la bajada. Cuando el máster libera la línea pueden
pasar dos cosas: si el esclavo quiere escribir un 1 libera la línea y vuelve a nivel alto, pero si quiere
escribir 0 la retiene en nivel bajo hasta 15us.

Así pues, en esta rutina bajamos el bus durante dos microsegundos, e inmediatamente leemos el
valor. Devolvemos el valor leído. La rutina low ya esperaba el tiempo necesario para la
recuperación del nivel.

1 /* Sends a brief pulse and then read for the response */ ?


2 int read_bit(pin) {
3 int s;
4
5 low(pin, 2);
6 s = digitalRead(pin);
7 delayMicrosecondsHard(TIMESLOT);
8
9 return s;
10 }

Una vez que escribimos y leemos bits, es sencillo escribir o leer un byte. Únicamente hay que
escribir o leer 8 bits seguidos.

Pero eso sí, prestad atención al orden en que enviamos los bits. Los dispositivos 1-Wire siempre
empiezan enviando el bit menos significativo primero. La siguiente función send_byte llama
varias veces a send_bit con el valor que tenga el bit menos significativo del byte. Tras haber
enviado un bit, desplaza hacia la derecha el valor y repite.

1 /* Sends 8 bit in a row, LSB first */ ?


2 void send_byte(int pin, char byte) {
3 int i;
4
5 for (i = 0; i < 8; i++) {
6 send_bit(pin, byte & 1);
7 byte = byte >> 1;
8 }
9 }

8 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

Para leer es algo más complicado, ya que tenemos que empezar a leer por el bit menos
significativo. El primer bit leído irá a la derecha del todo. El siguiente irá a su izquierda, y así
iremos rellenando los 8 bits hasta componer un byte.

1 /* Reads a byte, LSB first */ ?


2 char read_byte(pin) {
3 int byte = 0;
4 int i;
5
6 for (i=0; i < 8; i++) {
7 int b;
8 b = read_bit(pin);
9 b = b << i;
10 byte = byte | b;
11 }
12
13 return byte;
14 }

CRC-8 Maxim/Dallas

Como ya hemos visto el protocolo es crítico en tiempos. ¿Qué pasa si falla? Pues que podemos
enviar o recibir datos erróneos. ¿Forma de detectarlo? Hay varias.

La más sencilla, que no se usa aquí, es el bit de paridad. En el caso de una transmisión serie, por
ejemplo se usa un bit de paridad para detectar errores. Por si no os habéis parado a pensar cómo
funciona, se fuerza a que el número de unos sea par o impar añadiendo un bit a 1 o a 0 según
haga falta. Cuando se recibe el byte, se comprueba que el número de unos corresponde a lo
acordado y si no, pues ha habido un error.

El bit de paridad, siendo tan básico, sólo permite detectar un número impar de errores. En
cuanto se cambien dos bits, ya lo da como correcto. De hecho en transmisión serie es habitual
que fallen varios bits seguidos debido alguna interferencia.

En otros ámbitos, sobre todo cuando el mensaje es numérico, se recurre a calcular el resto
módulo algún valor. Por ejemplo en el cálculo de la letra del DNI se utiliza el resto módulo 23.

El CRC es una forma de calcular el resto un tanto especial. No voy a explicar el fundamento
matemático porque daría para un artículo entero. Pero básicamente funciona con un registro de
desplazamiento por el que pasan todos los bits. A medida que se desplazan de un lugar a otro,
pueden invertirse o no dependiendo del nuevo bit y del resultado del bit anterior.

¿Un lío? Sí, precisamente. Se trata de hacer una operación enrevesada con la intención de hacer
improbable que una cascada de errores aleatorios dé casualmente el mismo resultado.

La idea es esa, sí. Realmente hay un fundamento matemático muy robusto detrás basado en el
álgebra de polinomios. Lo importante aquí son dos cosas:
Es fácil de implementar. Para el hardware actual, desplazar bits y hacer xor son de
las operaciones más baratas y más rápidas.
Es fácil de comprobar, de hecho no hace falta. Me explico. Por la naturaleza
matemática de un CRC, si concatenamos el valor al mensaje original, cuando
calculemos el CRC de todo junto va a dar cero. O sea, al recibir un mensaje
incluyendo el CRC tan sólo hemos de pasarlo por la misma rutina que calcula CRC y
mirar el resultado. Si es cero, entonces el mensaje no tiene ningún error.

Ejemplo. Tenemos un programa que calcula el CRC8 del argumento que se le pase. Y nos da el
resultado en hexadecimal y su carácter correspondiente.

./crc ElectronicaYciencia
25h '%'

9 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

El CRC correspondiente al mensaje "ElectronicaYciencia" es el 25h, equivalente al carácter '%'. Si


ahora calculamos el CRC de ElectronicaYciencia añadiendo el caracter "%" este es el nuevo
resultado:

./crc ElectronicaYciencia%
00h ''

Cero. Significa que el mensaje está íntegro. Probamos de nuevo:

./crc "Esto es un mensaje de prueba. ¿Llega bien?"


53h 'S'

Ahora añadiendo la letra "S" al final:

./crc "Esto es un mensaje de prueba. ¿Llega bien?S"


00h ''

El resultado es cero. El mensaje está bien. Probemos a introducir algún error. Por ejemplo
cambiando cualquiera de las letras.

./crc "Esto es un mensa)e de prueba. ¿Llega bien?S"


E9h '�'

El CRC deja de ser 0 y sabemos que hay algún fallo. Ciertos CRC tienen la capacidad de detectar
el error y corregirlo. No es el caso.

Hay múltiples parámetros al implementar el algoritmo, cada fabricante usa el suyo. Se


distinguen por el tamaño (8bit, 16bit, 32bit, etc) y también por lo que se llama polinomio
generador. Que viene a ser la forma de intercalar los XOR en el registro de desplazamiento que
veíamos antes.

Este es el código para generar y validar el CRC usado en los dispositivos 1Wire de Maxim/Dallas:

1 /* Calculates CRC8-Maxim according datasheet ?


2 * If CRC is appended at the end of string, correct array gives result 00 */
3 unsigned char crc8 (char *str, size_t len) {
4 char div = 0b10001100; // Rotated poly
5 unsigned char crc = 0;
6
7 size_t i;
8 for (i = 0; i < len; i++) {
9 unsigned char byte = str[i];
10
11 int j;
12 for (j = 0; j < 8; j++) {
13
14 // Shift CRC
15 char crc_carry = crc & 1;
16 crc >>= 1;
17
18 // Shift Byte
19 char byte_carry = byte & 1;
20 byte >>= 1;
21
22 // If crc_carry XOR byte_carry we make crc XOR div
23 if (crc_carry ^ byte_carry)
24 crc ^= div;
25 }
26 }
27
28 return crc;
29 }

El código anterior no es evidente ni mucho menos. En esta página tenéis el descrito proceso, os
ayudará a comprenderlo: Eric's Maxim/Dallas 1-Wire Online CRC Calculator.

Leer la ROM

Ya podemos escribir comandos y leer los resultados, comprobando que están bien. Como
primera prueba leeremos su número de ROM. Hay dos formas de hacerlo:
la fácil, cuando tan solo hay un dispositivo en el bus. Se le envía el comando 33h y el

10 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

chip devuelve 8 bytes seguidos con su identificación.


Y luego está la difícil, cuando hay más de un esclavo. Si pedimos la ROM igual que
antes, todos los esclavos contestarán a la vez y así no hay forma de entender nada.
En el segundo caso hay un algoritmo que puede usar el máster. Sirve para "descubrir" la
identificación de todos los dispositivos conectados. Es algo difícil de captar la primera vez, pero
si tenéis interés está muy bien explicado en el datasheet. Además es muy ingenioso. Yo creo que
vale la pena echarle un vistazo.

De momento vamos al primer caso. Un sólo DS1820 conectado. Enviamos el comando 33h
READ ROM COMMAND y a continuación leemos los 8 bytes que devuelve:

1 /* Reads ROM, void function just for testing */ ?


2 void read_rom(int pin) {
3 char rom_data[8];
4
5 puts ("Reading ROM data (Cmd 33h)");
6 send_byte(pin, 0x33);
7
8 int i;
9 for (i = 0; i < 8; i++) {
10 rom_data[i] = read_byte(pin);
11 printf("%02x ", rom_data[i]);
12 }
13
14 if (crc8(rom_data, 8)) {
15 puts("\tROM data read ERROR.");
16 exit(0);
17 }
18 else {
19 puts("\tOK");
20 }
21
22 reset(pin);
23 }

Observad cómo tras leer 8 bytes e imprimirlos hemos llamado a la función crc. Así
determinamos si ha habido algún error en la recepción. Finalmente llamamos a la función reset.
Siempre se debe reiniciar el bus entre una orden y la siguiente.

El resultado es este:

Reading ROM data (Cmd 33h)


10 8c 67 e3 01 08 00 30 OK

Desglosado de esta manera:


Código de la familia, 1 byte. 10h es el indicador de DS1820 o DS18S20.
Código de identificación, 6 bytes (64bit). 8c67e3010800.
CRC del mensaje, 1 byte. 30 es el CRC correcto, por eso pone OK.

En ocasiones por unas causas o por otras el mensaje puede llegar mal, por ejemplo así:

Reading ROM data (Cmd 33h)


10 8c 67 e3 01 0a 00 30 ROM data read ERROR.

El byte 08h anterior (0000 1000 en binario) lo hemos leído como 0ah (0000 1010). Al haber
cambiado uno de los bits del mensaje, el crc ya no coincide y el error se detecta.

Leer la temperatura

Al igual que antes, asumiremos un sólo DS1820 conectado. La lectura de la temperatura se lleva
a cabo en dos pasos. Primero se lanza la conversión y a continuación se lee el resultado.

El primero consiste en lanzar la secuencia CCh 44h. El byte CC, también llamado SKIP ROM
COMMAND indica que no nos dirigimos a un dispositivo concreto, sino a cualquier esclavo en el
bus.

El byte 44h significa CONVERT TEMPERATURE. Tal como sugiere el nombre, el DS1820
seleccionado (en este caso todos) inicia la conversión a temperatura. Mientras efectúa la medida,
el dispositivo indica que está ocupado devolviendo 0 a cualquier operación de lectura. Una vez
termina, el DS1820 pasa a devolver 1.

11 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

1 /* Starts a temperature convertion and waits until it finish */ ?


2 void convert_t (int pin) {
3 send_byte(pin, 0xCC);
4 send_byte(pin, 0x44);
5
6 while (read_byte(pin) != 0xFF)
7 delayMicroseconds(20000);
8
9 reset(pin);
10 }

La lectura puede llevar hasta 500ms. En la rutina anterior lanzamos la conversión y esperamos,
consultando la línea periódicamente hasta leer todo unos. Si estuviésemos usando la
alimentación parásita, durante este tiempo no deberíamos lanzar comandos a otros dispositivos
porque se interrumpiría la alimentación. Finalmente, como siempre, reiniciamos el bus.

Tras la conversión, la temperatura queda guardada en el scratchpad y hemos de leerla de ahí.


Si recordáis, el scratchpad es una especie de pizarra donde escribimos las alertas de temperatura
y de donde leemos el resultado de la conversión. El comando BE se llama READ SCRATCHPAD y
devuelve los 8 bytes del scratchpad más el correspondiente crc, 9 bytes en total.

Lanzamos la secuencia CC BE. El comando CC, igual que antes, selecciona todos los esclavos
conectados al bus. A diferencia del comando 44h CONVERT TEMPERATURE, con el que no
había problema al invocar a todos los esclavos al mismo tiempo, si pedimos a todos los esclavos
que vuelquen al bus el contenido de la memoria, el resultado va a ser desastroso. En nuestro caso
podemos hacerlo así porque sólo hay uno.

El siguiente código lanza la secuencia CC BE, lee nueve bytes, comprueba el CRC y finalmente
reinicia el bus.

1 /* Reads the whole scratchpad to the buffer (9 bytes) */ ?


2 int read_scratchpad(int pin, char *buff) {
3 send_byte(PIN, 0xCC);
4 send_byte(PIN, 0xBE);
5
6 int i;
7 for (i = 0; i < 9; i++) {
8 buff[i] = read_byte(PIN);
9 printf("%02x ", buff[i]);
10 }
11
12 if (crc8(buff, 9)) {
13 puts("\tScratchpad data read ERROR, try again.");
14 }
15 else {
16 puts("\tOK");
17 }
18
19 reset(PIN);
20 }

El resultado leído es este:


22 00 4b 46 ff ff 09 10 c0 OK

Aquí vemos el significado de cada byte según viene descrito en el datasheet:

12 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

Los bytes 1º y 2º (numerados 0 y 1) indican la temperatura de un modo directo en grados


centígrados. Para temperaturas positivas es muy sencillo interpretarlo: el primero da la
temperatura con resolución de medio grado, y el segundo es cero. Para temperaturas negativas
hay que interpretarlo de otra manera. El datasheet proporciona una tabla de conversión.

Y por fin, ahora, en este momento, después de una hora leyendo, podemos decir que el byte 0 es
22h, que equivale a 34 decimal y que 34 medios grados son finalmente... 17.0ºC. ¡Sí!
¡Aleluya!.

Hay una forma de obtener más precisión. Fijaos en los últimos bytes, COUNT REMAIN y
COUNT PER °C. ¿Os acordáis de cómo leía la temperatura el DS1820? ¿El oscilador que abría y
cerraba la puerta? Bueno pues este último byte indica cuántos pulsos por grado centígrado se
contabilizan a esta temperatura. En nuestro caso son 10h (16 en decimal). Cada 16 pulsos se
suma un grado. El otro byte, indica el remanente, en otras palabras, cuántos pulsos quedaban
para llegar al grado al término del periodo de medición. Nos ha dado 09h, equivalente a 9 en
decimal.

Si han quedado 9 pulsos hasta llegar a los 16, eso significa que habían entrado ya 7 pulsos. De ahí
se puede deducir la temperatura con una precisión mayor. Para empezar olvidemos el medio
grado de resolución quedándonos sólo con la parte entera. Y a continuación debemos aplicar la
siguiente formula:

En nuestro caso arroja un resultado de 17.1875ºC, lo redondearemos a 17.19ºC.

Nunca confundáis precisión con exactitud. La precisión es de 1/16 grados o 0.0625ºC. Pero
los DS1820 tienen un error de hasta 0.5ºC. Más precisión nos puede servir para medir
incrementos de temperatura menores, pero no nos dará una temperatura más exacta.

Función main y conclusiones

Para terminar, estas son las cabeceras de nuestro programa:

1 #define PIN 7 /* Pin number */ ?


2 #define TIMESLOT 90 /* 1-Wire time slot in us 60-120 */
3 #define TREC 2 /* Line pull up recovery time us */

Y a seguidamente la función main:

1. Inicializa la librería WiringPi. Fija la prioridad máxima y configura los pines y las

13 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

resistencias de pullup.
2. Reinicia el bus y espera confirmación por parte de algún esclavo. Si no hay nada
escuchando termina el programa.
3. Lee la ROM e imprime por pantalla el resultado.
4. A continuación entra en el bucle principal. Donde ordena la conversión de temperatura, lee
el scratchpad e imprime la temperatura leída. Usa la conversión de baja resolución y la de
alta. Recordad, esta conversión sencilla sólo es válida para temperaturas positivas.

1 int main (void) ?


2 {
3 puts ("DS1820 Test Program for Raspberry Pi");
4
5 if (wiringPiSetup () == -1)
6 return 1;
7
8 piHiPri (99); /* us timing requires near real-time */
9 pinMode (PIN, INPUT);
10 pullUpDnControl (PIN, PUD_UP);
11
12 if (reset(PIN)) {
13 puts ("Device present!");
14 }
15 else {
16 puts ("Device not present, no response :(");
17 return 1;
18 }
19
20 read_rom(PIN);
21
22 puts("Reading temperature:");
23 for (;;) {
24 convert_t(PIN);
25
26 char scratchpad[9];
27 read_scratchpad(PIN, scratchpad);
28
29 short int temp_read = scratchpad[0];
30 short int count_remain = scratchpad[6];
31 short int count_per_c = scratchpad[7];
32
33 /* Low res temp */
34 printf("Temperature (low res) is %.1fºC\n", (float)temp_read/2);
35
36 /* High res temp */
37 float temp_hr = (int) temp_read / 2;
38 temp_hr = temp_hr - 0.25 + ((float)count_per_c - (float)count_remain) / (
39
40 printf("COUNT_PER_C: %d, COUNT_REMAIN: %d\n", count_per_c, count_remain);
41 printf("Temperature (hi res) is %.2fºC\n", temp_hr);
42 }
43
44 return 0;
45 }

Aquí podemos ver el resultado de la ejecución:

$ sudo ./ds1820
DS1820 Test Program for Raspberry Pi
Device present!

Reading ROM data (Cmd 33h)


10 8c 67 e3 01 08 00 30 OK

Reading temperature:
22 00 4b 46 ff ff 0a 10 95 OK

Temperature (low res) is 17.0ºC

COUNT_PER_C: 16, COUNT_REMAIN: 10


Temperature (hi res) is 17.12ºC

Es todo por ahora. En este enlace podéis encontrar los programas y archivos utilizados durante la

14 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

elaboración del artículo, incluyendo:


El programa principal ds1820.c
Los programas utilizados para los ejemplos de crc, benchmarks de funciones de
espera, etc.
Imágenes. Datasheet del ds1820.

Etiquetas: linux, programacion, raspberrypi

4 comentarios:

Vicente 8 de diciembre de 2016, 12:24


Artículo muy extenso y completo, ideal para tomarlo de referencia.

Aprovecho para comentarte que el enlace de Electrónica: teoría y práctica lo tienes desactualizado.

Un saludo
Responder

Respuestas

ele y ciencia 8 de diciembre de 2016, 14:49


Gracias. Actualizo el enlace.

Responder

Alex 1961 (LU5HER) 6 de abril de 2019, 4:26


Muchas gracias, fabuloso, explicativo y dicdactico me ayudo muchisimo
Estoy trabajando con un micro de NXP y queria controlar temperatura con una sonda arduino.
estoy emulando las rutinas a lenguaje assembler
si interesan a alguien puedo publicarlas
Responder

Respuestas

iAntony 12 de abril de 2019, 22:47


Usando esta guía, suponiendo que trabajo con un micro de 32 bits, simplemente cambio
el 8 por 32?

Responder

Comentar como:

Publicar Avisarme

Por favor, usa mayúsculas, minúsculas, puntos, comas, interrogaciones y todo eso. Muchas gracias.

Enlaces a esta entrada


Crear un enlace

Entrada más reciente Página principal Entrada antigua

Suscribirse a: Enviar comentarios (Atom)

15 de 16 17/09/2019 16:31
Electrónica y ciencia: El bus 1-Wire a bajo nivel - DS1820 http://electronicayciencia.blogspot.com/2016/12/el-bus-1-wire-bajo-nivel...

Tema Sencillo. Imágenes del tema: Dizzo. Con la tecnología de Blogger.

To the extent possible under law, Reinoso Guzmán has waived all copyright and related or neighboring rights to Electronicayciencia.

16 de 16 17/09/2019 16:31

Vous aimerez peut-être aussi