jueves, 4 de junio de 2020

1-WIRE Lectura de temperatura con DS18B20

Sensor DS18B20 con PIC16F




Un gran saludo a los visitantes de este blog, creado para compartir el mutuo interés en la electrónica y en especial la programación de microcontroladores PIC, hoy les quiero mostrar como realizar una medición de temperatura utilizando el conocido sensor digital DS18B.

El objetivo de esta sección es leer la temperatura del sensor DS18B conectado al microcontrolador PIC16F887, y enviar su valor en grados centígrados por el puerto serie UART.

La programación se realizara utilizando el compilador XC8 y el entorno MPLABX disponibles en la pagina de microchip de forma gratuita, ademas también necesitara de los siguientes archivos peripheral.h y peripheral.c que contienen procedimientos y funciones básicas para el PIC16F887, puede prescindir de ellos o incluso modificarlos a su criterio si posee conocimientos sobre los registros SFR y sus respectivo bits.

1. El protocolo 1-Wire.

1-Wire es un protocolo de comunicaciones en serie que implementa un bus maestro esclavo con una sola linea o señal de comunicación, la linea requiere una resistencia pull-up para que todos los dispositivos conectados utilicen el tercer estado como mecanismo para liberar el bus. 1-Wire puede implementarse en una topologia lineal, fraccionada o estrella.



Las limitaciones con respecto a la distancia máxima de transmisión se dan por las reflexiones de onda, el retardo, y la degradación producida por la resistencia del cable, siendo unos 200 metros el valor aproximado de un cable convencional.
En cuanto a la velocidad se tiene dos modos de operación: el modo standard con una tasa de 16.3kbit/s y el modo overdrive que eleva la transferencias hasta diez veces mas.

Con respecto a la señalización tome como referencia los documentos SPMA057C y AN1119 para distinguir los siguientes modos:

Secuencia de reinicio: Permite reiniciar el bus en cada dispositivo esclavo preparándolos para iniciar la comunicación.


El dispositivo maestro coloca el bus en nivel bajo por 480us, luego lo libera y espera una respuesta durante los siguientes 240us. En caso de no existir un dispositivo esclavo conectado al bus, la linea permanecerá en nivel alto.

Escritura del bit 0: Permite enviar un bit 0 a los dispositivos esclavos

El dispositivo maestro coloca el bus en nivel bajo por 60us para que el dispositivo esclavo realice la lectura del nivel bajo(bit 0).

Escritura del bit 1: Permite enviar un bit 1 a los dispositivos esclavos


El dispositivo maestro coloca el bus en nivel bajo por un tiempo entre 5 a 15us y luego lo libera hasta completar 60us, durante este tiempo el esclavo deberá realizar la lectura del nivel alto(bit 1).
Lectura del bit 0: Permite recibir un bit 0 del dispositivo esclavo

El dispositivo maestro coloca el bus en nivel bajo por un tiempo entre 5 a 15us y luego lo libera, entonces el dispositivo esclavo coloca nuevamente el bus en nivel bajo(bit 0) para que el maestro realice la lectura, el nivel bajo se mantendrá hasta completar un tiempo total de 60us.

Lectura del bit 1: Permite recibir un bit 1 del dispositivo esclavo


El dispositivo maestro coloca el bus en nivel bajo por un tiempo entre 5 a 15us y luego lo libera, entonces el dispositivo esclavo coloca el bus en nivel alto(bit 1) para que el maestro realice la lectura, el nivel alto se mantendrá hasta completar un tiempo total de 60us.

Para todos los casos el bus deberá permanecer en nivel alto por al menos 10us antes iniciar la escritura o lectura de un siguiente bit.


2. Sensor de temperatura DS18B

Describiré un breve resumen acerca de este sensor tomando como referencia la hoja de datos DS18B20 del fabricante Maxim Integrated.

El ds18b20 esta disponible en los encapsulados TO-92, SOIC y SOP, opera con un voltaje de alimentación de 3.3 - 5.5V y un consumo de 1.5mA en modo activo.
Se trata de un sensor digital de temperatura con una resolución ajustable desde los 9-bit hasta los 12-bit con las que podemos medir temperaturas en el rango de -55°C a 125°C. Ademas tiene la ventaja de ser un dispositivo direccional gracias a que implementa una comunicación utilizando el protocolo 1-Wire, y donde cada sensor tiene almacenado en su memoria ROM un código de 64-bit para la identificación.
Se sugiere revisar la hoja de datos que muestra los tiempos mínimos y máximos establecidos para la señalización del bus, para así enfocarnos unicamente en describir los comandos y registros necesarios para realizar la lectura con el PIC.
La conexión del sensor como se observa en la siguiente figura es muy simple, el único requerimiento adicional sera agregar una resistencia pull-up(recomendado 4.7k) para mantener un nivel alto en el bus en modo inactivo, incluso puede emplear un pin del PIC activando la resistencia pull-up interna(aprox. 10k).


Establecido el bus y considerando que existe al menos un dispositivo esclavo(sensor ds18b20) conectado podemos efectuar la comunicación en una secuencia de tres pasos descritos a continuación.
Inicializacion: El maestro establece una secuencia de reinicio para detectar la presencia de uno o mas dispositivos conectados al bus.
Direccionamiento: El maestro enviá un comando ROM para identificar a cada dispositivo esclavo o detectar si algún sensor se encuentra en condición de alarma(no se abordara este punto en el blog), el ds18b20 reconoce los siguientes comandos ROM:
  • Search ROM[0xF0]: Este comando permite al maestro leer los códigos  de identificación de todos los esclavos conectados al bus, esto se lleva a cabo mediante una secuencia de discriminación que no se explicara en este blog, el tiempo total necesario para llevar a cabo todo el proceso dependerá de la cantidad de dispositivos que tenga el bus.
  • Read ROM[0x33]: Cuando solo existe un dispositivo esclavo en el bus, este comando permite al maestro leer su código de identificación.
  • Match ROM[0x55]: Cuando se conoce el código de identificación de un dispositivo esclavo, este comando permite seleccionar o preparar al dispositivo en particular para realizar una operación, el resto de dispositivos conectados quedaran a la espera de un reinicio en el bus.
  • Skip ROM[0xCC]: Este comando permite al maestro seleccionar a todos los dispositivos cuando se requiere realizar una operación en común, por ejemplo es posible dar una sola orden a todos los sensores para que inicien el proceso de conversión que tiene una demora de hasta 750ms y de esta manera se tengan los datos listos para su lectura.
  • Alarm Search[0xEC]: Permite al maestro detectar si existe un sensor en estado de alarma.
Función: Una vez seleccionado(Direccionamiento) el o los dispositivos esclavos,  el maestro enviá un comando de función para realizar una operación especifica, el ds18b20 reconoce los siguientes comando de función.
  • ConverT[0x44]: Esta orden permite a los sensores conectados al bus iniciar el proceso de conversión, luego finaliza la comunicación. los datos de temperatura estarán listos para su lectura en un tiempo mínimo de: 94ms(9-bit), 188ms(10-bit), 375ms(11-bit) y 750ms(12-bit).
  • Read Scratchpad[0xBE]: El scratchpad es la información compuesta por un grupo de 8 registros mas un byte de verificación CRC, tal como se observa en la siguiente imagen:

El comando de función Read Scratchpad sirve para que el maestro pueda leer los 64-bits de información que contiene el Scractchpad de un determinado sensor y de esta manera conocer los valores de temperatura y configuración actual. Mas adelante explicaremos en detalle el formato de los registros y los valores establecidos por defecto
  • Write Scratchpad[0x4E]: El comando permite que el maestro escriba tres bytes de información correspondientes a los registros 2, 3 y 4 del Scratchpad. En la comunicación se enviá primero el bit LSB.
  • Copy Sractchpad[0x48]: Este comando sirve para que el contenido de los 2, 3 y 4 del Scratchpad se guarden en una memoria EEPROM.
  • Recall E2[0xB8]: El uso de este comando no se detalla en el blog, pero esta relacionado con el uso de las alarmas del sensor
  • Read Power Supply[0xB4]: El uso de este comando no se detalla en el blog, pero esta relacionado con el uso de energía parásita en el bus.
Ahora detallaremos el formato de los registros que contiene el Scratchpad, solo haremos mención a los que aplicaremos en el programa presentado en blog.

Registro 0(byte de menor peso) y 1(byte de mayor peso) conforman la información de temperatura que tiene el sensor luego de haber finalizado el proceso de conversión el par de registros forman un dato entero con signo de 16-bits de los cuales 12-bits corresponden a la magnitud y los bit S indican el signo.


Si el sensor esta configurado a una resolución de 11-bits, el bit 0 de este numero se descarta, si la resolución es de 10-bits se descartan los bits 0 y 1, y en caso de que la resolución sea 9-bits se descartan los bits 0,1 y 2. por esta razón la precisión de la temperatura va desde los 0.5°C(9-bit) hasta los 0.0625°C(12-bit).

El registro 4 corresponde al byte de configuración donde se encuentran los bits R1 y R0, estos permiten ajustar la resolución siendo la combinación del par R[1:0]=11 para 12-bit, R[1:0]=10 para 11-bit, R[1:0]=01 para 10-bit y [R1:0]=00 para 9-bit.



Por defecto el valor de los bits son R1=1 y R0=1(12-bit).

3. Diagrama de circuito
La propuesta como ejemplo de uso para el sensor ds18b se detalla en el siguiente diagrama de circuito, mismo que no incluye detalles de la alimentación y elementos relacionados con el circuito de reinicio.


4. Procedimiento de lectura
El procedimiento a seguir para una correcta lectura del sensor se ilustra en el siguiente diagrama, resaltando que el cuarto paso es dependiente del comando de función enviado por el maestro; por ejemplo si el comando de dirección es Read ROM[0x33], el maestro debe recibir los 64-bit de identificación enviados por el sensor sin necesidad de enviar un comando de función. En cambio una vez seleccionado el sensor, si el maestro enviá un comando Read Scratchpad[0xBE], el maestro recibe los ocho registros de información relacionada con la temperatura y configuración, en este punto también es posible obviar el cuarto paso en caso de un comando de función ConvertT[0x44].


Utilizaremos un par de ficheros que contienen tres funciones básicas para emular la operación del protocolo 1-wire con el sensor DS18B, estos ficheros se encuentran en el siguiente enlace ds18b20.h y ds18b20.c. Te recomiendo puedas  revisar su contenido para conocer como las instrucciones se acomodan a los requerimientos de tiempo que necesita el bus, y porque el uso de estas funciones en en nuestro programa nos abstrae de tocar los aspectos relativos a la señalización. 
A continuación se describe el programa principal que contiene la definición de los pines utilizados y la inclusión del fichero ds18b20.h, así mismo se activara la resistencia pull-up para cumplir el requerimiento del bus con la resistencia adicional, la secuencia principal del código es llamar al procedimiento taskDS18 de forma continua.

#pragma config FOSC=INTRC_NOCLKOUT, WDTE=OFF, LVP=OFF
#define _XTAL_FREQ 8000000
#include "peripheral.h"
#define DS18pin PORTBbits.RB2 //Define el pin donde se conecta el sensor
#define DS18tris TRISBbits.TRISB2
#include "ds18b20.h"
char romcode[8];
char value;
int rawdata;
void main()
{
    OSCSetup(); //Ajusta el oscilador interno a la definición _XTAL_FREQ
    ANSEL = 0; //Desactiva los pines analógicos AN0-AN7
    ANSELH = 0; //Desactiva los pines analógicos AN8-AN13
    USARTSetup(9600);
    TRISEbits.TRISE2 = 0; //Salida para el LED1
    EnablePU(); //Activas las resistencias pull-up del PORTB
    while(1)
    {
        taskDS18();
    }
}

Ahora abordaremos el procedimiento taskDS18 y para ello vamos a considerar dos posibles situaciones al momento de implementar el circuito.
Situación #1: Si solo va utilizar un sensor, entonces no sera necesario conocer su código de identificación, utilizando el comando Skip ROM[0xCC] se enviá directamente el comando de función deseado.

taskDS18()
{
    DS18Reset())
    DS18Write(SKIPROM);
    DS18Write(CONVERT); //Iniciar la conversion
    __delay_ms(800); //Espera minima de la conversion
    DS18Reset();
    DS18Write(SKIPROM);
    DS18Write(READSC); //Lectura del Scratchpad
    value = DS18Read(); //Lectura Registro 0 Byte LSB
    rawdata = DS18Read(); //Lectura Registro 1 Byte MSB
    rawdata <<= 8; //Se desplaza el byte MSB en la variable
    rawdata |= value; //Se conforman ambos bytes MSB+LSB
    printf("RAW:%04X ", rawdata); //Se imprime el valor de 16-bits
    value = rawdata & 0x000f; //Enmascara los bits de precision
    rawdata = rawdata >> 4; //Desplaza el registro de temperatura
    printf("T:%3d.%u\r\n", rawdata, value * 6); //Muestra la temperatura
    __delay_ms(200);
}


Situación #2: Si hay mas de un sensor conectado al bus, entonces es necesario conocer el código de identificación de cada uno, en este caso el comando Search ROM[0xF0] tiene por finalidad registrar la identificación de cada sensor, pero no describiré su uso en este momento, pero si podríamos conectar un sensor a la vez y mediante el comando Read ROM[0x33] leer los códigos de cada uno para luego trabajarlos con su debida identificación.

Procedimiento para lectura del código de identificación de un sensor


taskDS18()
{
    DS18Reset(); DS18Write(READROM);
    romcode[0] = DS18Read(); //Get Family Code 0x28
    romcode[1] = DS18Read(); //48-bit LSB code
    romcode[2] = DS18Read();
    romcode[3] = DS18Read();
    romcode[4] = DS18Read();
    romcode[5] = DS18Read(); //48-bit MSB code
    romcode[6] = DS18Read();
    romcode[7] = DS18Read(); //CRC
    printf("ROM CODE:");
    for(value = 0; value < 9; value++)
    printf("%02X ", romcode[value]);
    printf("\r\n");
}


Procedimiento de lectura de un sensor a través de su identificación ejemplo: 28 FF 5C 8A 61 16 03 94.

taskDS18()
{
    DS18Reset();
    DS18Write(MATCHROM);
    DS18Write(0x28);
    DS18Write(0xFF);
    DS18Write(0x5C);
    DS18Write(0x8A);
    DS18Write(0x61);
    DS18Write(0x16);
    DS18Write(0x03);
    DS18Write(0x94);
    DS18Write(CONVERT);
    __delay_ms(800); //Espera de conversion
    DS18Reset();
    DS18Write(MATCHROM);
    DS18Write(0x28);
    DS18Write(0xFF);
    DS18Write(0x5C);
    DS18Write(0x8A);
    DS18Write(0x61);
    DS18Write(0x16);
    DS18Write(0x03);
    DS18Write(0x94);
    DS18Write(READSC);
    value = DS18Read();
    rawdata = DS18Read();
    rawdata <<= 8;
    rawdata |= value;
    printf("RAW:%04X ", rawdata);
    value = rawdata & 0x000f;
    rawdata = rawdata >> 4;
    printf("T:%3d.%u\r\n", rawdata, value * 6);
    __delay_ms(200);

}


5. Conclusiones

Las pruebas efectuadas en nuestro programa nos muestran un adecuado funcionamiento del sensor, las buenas prestaciones junto a lo accesible que resulta adquirir este dispositivo en las electrónicas locales, lo convierten en una excelente opción para muchas aplicaciones de control.

Los tiempos de requerimiento utilizan retardos provisto por el compilador que fueron levemente ajustados a la frecuencias de 8MHz, en caso de frecuencias menores a 4MHz podría ser necesario efectuar cambios debido a que el ciclo de maquina se incrementa a mas de 1uS, una solución mas eficiente podría pasar por utilizar unos de los temporizadores TMRx del PIC para generar los retardos, pero esto claramente va depender de la disponibilidad del recurso.  
 
Debido a que los requerimientos de temporalización para validar los datos son fijos, es conveniente evitar cualquier interrupción una vez iniciada la comunicación, si el programa hace uso de interrupciones deberá considerar una correcta aplicación de las funciones descritas en este blog agregando la gestión interrupciones por cambio y/o temporizadores.

El estado inactivo del bus siempre sera un nivel alto, si por alguna razón la comunicación es suspendida, se debe asegurar que el bus permanezca en su estado inactivo, porque de otra forma un nivel bajo mayor a 120us provocara el reinicio del bus en los dispositivos esclavos.

Puede reducir el tiempo de espera en la conversión si su aplicación no requiere de la precisión establecida por defecto de 12-bit(0.0625°C) lo que representa un mínimo de 750ms, entonces configurando a 9-bit(0.5°C) se podría reducir a tan solo 94ms. para realizar este cambio debe enviar el comando de función Write_Scratchpad[0x4E] seguido de 3 bytes en la que el tercer byte representa el registro de configuración con los bits R1 y R0 según el requerimiento deseado.

Pablo Zarate Arancibia
Ingeniero Electrónico

pablinzte@gmail.com
pablinza@me.com