Bus One Wire - Sensor de temperatura DS18B20



1. Introducción:

 Para desarrollar la comunicación, nos centraremos en la sonda de temperatura DS18B20 con un formato industrial:



Nota: Es una sonda económica y muy estable.


2. Características:


 Alimentación parasitaria:


 Alimentación directa:


Nota: Para que funcione bien en nuestra placa, sacaremos el jumper del array de resistencias de los led si usamos un pin de esos. Me daba problemas al pasar de 26ºC.


3. Funciones:

 Las funciones que aparecen en la tabla siguiente, son las necesarias para llevar a cabo la comunicación:




Nota: En verde se indica quién tiene el control del BUS.


4. Identificación de los esclavos:

 Para identificar un Esclavo, se hace a través del Rom Code:

 Si sólo tenemos un esclavo en el bus, podemos averiguar el Rom Code enviando el comando 0x33 (Read Rom Code).
Nuestra sonda nos devuelve la siguiente cadena: 0x61 / 0x01, 0x15, 0x52, 0x55, 0x56, 0xFF / 0x28

 Si hay más de un esclavo, debemos descubrirlos a través de un proceso de eliminación usando el comando 0xF0 (Search Rom).

Nota: Para no complicarnos, los conectaremos de uno en uno para averiguar con el comando anterior (Read Rom Code) el Rom Code y poder direccionar.
Una vez sepamos los Rom Code de cada elemento, direccionaremos usando el comando 0x55 (Match Rom).

Cuando tengamos varios elementos en el bus que necesiten un tiempo para preparar el dato, podemos indicarles que vayan realizando el trabajo direccionando a "todos" con el comando 0xCC (Skip Rom) y luego direccionaremos uno a uno para recoger el valor.



5. Detección de errores:

  Para asegurarnos que los datos recibidos están bien, se usa un sistema CRC. Si restamos al crc recibido, el crc calculado debería darnos 0.
El sistema se basa en polinomios de orden 8:
CRC = X8 + X5 + X4 + 1


Inicialmente, empezamos con el valor 0, luego, cuando pasemos al siguiente byte, se inicia con el resultado de la operación anterior.





6. Leyendo temperatura:

  La conversión se hace por defecto usando 12 bits de resolución; cuanta mayor precisión, más tiempo necesario en la conversión.
El siguiente registro, es el que nos permite seleccionar la resolución:




Nota: Una conversión de 12 bits, necesita cerca de un segundo para completarse.



6.1. Formato temperatura:

  Los valores S, del bit 15 al 11 indican si la temperatura es positiva (0) o negativa (1). Del bit 10 al 4 es el valor de la temperatura y del bit 3 al 0 los decimales.


 He encontrada esta fórmula para realizar el cálculo de forma sencilla:
float value = ((MS Byte & 0x0F) * 256) + MS Byte

- Si el bit 0x08 es 1 -> temperatura negativa
float Temperatura = Value / 16 - 256

- Si el bit 0x08 es 0 -> temperatura positiva
float Temperatura = Value / 16

Para cambiar la resolución, escribiremos el valor 0x1F (para 9 bits) o 0x7F (para 12 bits) por ejemplo.

Nota: Una vez modificado el registro, debemos indicarle que guarde los cambios en la Eeprom usando el siguiente comando: scratchpad command (48h)


6.2. Aplicación ejemplo y salida por terminal:

 Hacemos uso de la librería "OneWire.h" creada anteriormente.

				
				
				/*
 * File:   main.c
 * Author: Eduardo
 *
 * Created on 5 de junio de 2017, 17:16
 */


#include 
#include "config.h"
#include "typedefs.h"
#include "usart.h"
#include "stdio.h"
#include "OneWire.h"






//PROTOTIPO DE LAS FUNCIONES USADAS
void delay_ms(uint16_t);

void imprimirValorInt (int valor);
void imprimirValorFloat (float valor);

uint8_t crc8 (uint8_t *valores, size_t len); 
unsigned char read_OW_code ();
void read_OW_temp ();
void write_OW_conf (uint8_t conf);




void main(void) 
{
    USART_Initialize();     // Inicializamos el puerto Serie
    delay_ms(500);
    
    // Hacemos un reset y comprobamos si hay respuesta
    // Si nadie responde, esperamos 5 segundos y volvemos a preguntar
    while (!reset_OW ())
    {
        printf ("No se detectan esclavos \n");
        delay_ms(5000);
    }
    // Al salir del bucle anterior, preguntamos el Rom Code 
    printf ("Hay un esclavo \n");

    read_OW_code (); 
    
        
    while (true)
    {
      ////////////////////////////////////////////////////////////////////////// 
      // Cuando solo hay un esclavo en el bus, podemos omitir el Rom Code
      // El esclavo nos devuelve la temperatura
        
    /*   if (reset_OW ())
        {
            write_OW_byte (0xCC);   // No enviamos id, solo hay un esclavo en el bus
            write_OW_byte (0x44);   // Indicamos que inicie la conversion
            delay_ms(1000);         // Esperamos hasta que la conversion se realice
            
            reset_OW ();            //Provocamos otro reset
            write_OW_byte (0xCC);   //No enviamos id, solo hay un esclavo en el bus
            write_OW_byte (0xBE);   //Indicamos que queremos leer
            read_OW_temp ();        //Leemos temperatura y calculamos CRC          
        }
        else
             printf ("Error comunicacion \n");
        
        */
       
        
      //////////////////////////////////////////////////////////////////////////  
      // Cuando tenemos mas de un esclavo, debemos direccionar usando el Rom Code
      // Respondera el esclavo que corresponda
      // Como el tiempo de conversion usando 12 bits es de 750mS, podemos indicar
      // a todos los esclavos que realicen la conversion y luego vamos preguntando
      // uno a uno usando el direccionamiento
        
        if (reset_OW ())
        {
            write_OW_byte (0xCC);   // Nos dirigimos a todos los esclavos
            write_OW_byte (0x44);   // Indicamos que inicie la conversion
            delay_ms(1000);
            
            reset_OW ();            // Provocamos otro reset
            write_OW_byte (0x55);   // Ahora preguntamos al esclavo que nos interese
            write_OW_byte (0x28);
            write_OW_byte (0xFF);
            write_OW_byte (0x56);
            write_OW_byte (0x55);
            write_OW_byte (0x52);
            write_OW_byte (0x15);
            write_OW_byte (0x01);
            write_OW_byte (0x61);
            write_OW_byte (0xBE);   //Indicamos que queremos leer
            read_OW_temp ();        //Leemos temperatura y calculamos CRC 
        }
        else
             printf ("Error comunicacion \n");
        
        
      //////////////////////////////////////////////////////////////////////////  
      // Esta funcion cambia la resolucion de la conversion. Puede ser de
      // 9 bits, 10 bits, 11 bits o 12 bits.
      // Mayor resolucion implica mayor tiempo en la conversion
      // - 12 bits = 0x7F
      // - 11 bits = 0x2F
      // - 10 bits = 0x1F
      // - 9 bits = 0x0F
      //write_OW_conf (0x7F);
        
      delay_ms(1000);             // Retardo antes de volver a iniciar
  
    }
}




/******************************************************************************
*                       FUNCION IMPRIMIR INT 
* 
*   - Funcion que permite imprimir un int por la uart
 *****************************************************************************/
void imprimirValorInt (int valor)
{
    unsigned char intStringVal[4];
    itoa( intStringVal, valor,10);
    printf(intStringVal);
    printf("\n");
}


/******************************************************************************
*                       FUNCION IMPRIMIR HEX 
* 
*   - Funcion que permite imprimir un hex por la uart
 *****************************************************************************/
void imprimirValorHex (int valor)
{
    unsigned char intStringVal[4];
    itoa( intStringVal, valor,16);
    printf(intStringVal);
    printf("\n");
}


/******************************************************************************
*                       FUNCION IMPRIMIR FLOAT 
* 
*   - Funcion que permite imprimir un float por la uart
 *****************************************************************************/
void imprimirValorFloat (float valor)
{
    int bytesWritten; 
    char myString[50];

    bytesWritten = sprintf(myString, "%7.4f", valor); 
    UART_Write_Text(myString);   
    printf("\n");
}




/******************************************************************************
*                       FUNCION RETARDO DE mS
* 
*   - Funcion que realiza un retardo en mS segun el valor que recibe
 *****************************************************************************/
void delay_ms(uint16_t i)
{
    for ( uint16_t x=0; x 0; i--)  //El proceso se aplica a todos los bytes del array
 {
 uint8_t byte = valores[i];         //Cargamos en byte, el valor del array correspondiente
 
  for (uint8_t j = 0; j < 8; j++)   //Recorremos los 8 bits que componen el byte
  {

   uint8_t crc_carry = crc & 1;     //Almacenamos el bit de menor peso en crc_carry para compararlo
   crc >>= 1;                       //Desplazamos un bit a la derecha
 
   uint8_t byte_carry = byte & 1;   //Almacenamos el bit de menor peso en byte_carry para compararlo
   byte >>= 1;                      //Desplazamos un bit a la derecha
 
                                
   if (crc_carry ^ byte_carry)      //Si los bits de menor peso son diferentes, XOR = 1. 
    crc ^= div;                     //Realizamos la operación entre los valores
   
  }
 }
 
 return crc;        //Retorna el valor calculado crc que debemos restar del recibido.
}          
				






- Comunicación OneWire DS18B20:



7. Descargas:



www.microedu.es

Si chove, non orballa!