ds3231

Midiendo la temperatura con DS3231 (y extras)

En esta ocación, les dejo 2 funciones extras que éste módulo les ofrece, al menos en la versión que estoy probando yo. Estas son la función de medir la termperatura con DS3231, y el acceso a la memoria EEPROM que trae, que es una AT24C32 en mi caso, de 32kbits o 4KBytes.

Midiendo la temperatura con DS3231

El módulo RTC DS3231 posee una funcionalidad que no solo mide la temperatura, sino que la reporta como parte de sus sistema de registros. La temperatura que podrán medir es la temperatura ambiente, es decir, la temperatura a la que es sometido el módulo RTC, y este definitivamente no es un método apropiado para proyectos donde la medición de la temperatura juegue un papel central. Sin embargo, para aquellos proyectos en donde la temperatura sea un dato complementario, como por ejemplo en proyectos de automatización, parece interesante disponer de este recurso por el mismo precio de un RTC simple.

Antes de ir a los registros, algunos datos interesantes. Según las especificaciones, los registros de temperatura con DS3231 se actualizan cada 64 segundos, o cada vez que usted lo pida (ya veremos más adelante como), pero en mi experiencia personal eso es diferente, no sé si porque las especificaciones son del chip DS3231 y no de mi módulo en específico, y tal vez mi módulo implemente una actualización más periódica, pero en mis pruebas la temperatura se actualizaba cada segundo. Igualmente en el Sketch les dejaré una línea comentada que pueden implementar para forzar dicha actualización y conseguir un efecto de reacción más inmediata.

Los registros involucrados son los últimos 2, es decir 11h y 12h (18 y 19 decimal) y acá les dejo la tabla de los mismos según el datasheet del DS3231:

DIRECCIONBIT 7BIT 6BIT 5BIT 4BIT 3BIT 2BIT 1BIT 0
11hSignoDatoDatoDatoDatoDatoDatoDato
12hDatoDato000000

Entendiendo mejor los registros de temperatura con DS3231

Como se puede apreciar, el bit 7 del registro 11h dice “Signo” y significa que cuando está en 1 marca un número negativo, por lo tanto la temperatura deberá considerarse bajo cero. Los registros deben procesarse y su interpretación es como sigue:

El registro 11h refiere a los grados enteros, es decir que marca la temperatura en grados centígrados con precisión matemática de 1 grado, con el bit más significativo marcando el signo con un cero para positivo y 1 para negativo. El registro 12h es dedicado a los decimales, es decir que agrega mayor precisión al registro 11h si la desean, aunque para muchas aplicaciones les bastará con solo leer el registro 11h que es fácil de interpretar. Para los que desean incorporar el registro 12h, hay que tener en cuenta que solo se usan 2 bits, por lo que su precisión va de 0 a 3 (00 a 11 en binario), y que dichos 4 valores representan 1/4 de grado.

Es decir:

0d = 00b = 0.00C
1d = 01b = 0.25C
2d = 10b = 0.50C
3d = 11b = 0.75C

Debe observarse que los bits usados son los 2 más significativos por lo que deberá moverlos 6 lugares a la derecha si quiere usar todo el registro para procesar los decimales con aritmética simple. Un dato extra es que segun la hoja de datos, la precisión de temperatura con DS3231 es de +/- 3C lo que da más razones aun para desestimar la parte decimal en la generalidad de las aplicaciones.

El Sketch de prueba para leer la temperatura con DS3231

// Incluimos la librería del proyecto Arduino para I2C
#include "Wire.h"

// Esta es la dirección de nuestro módulo
#define DS3231_I2C_ADDRESS 0x68

void setup() {
  // Inicializamos el Monitor Serial para nuestras pruebas
  Serial.begin(9600);

  // Inicializamos la librería I2C
  Wire.begin();
}

void loop() {
  byte buffer[2];
  
  // Leemos los registros de temperatura
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11); // La direccion de los registros de temperatura
  Wire.endTransmission();
  
  // Leemos 2 registros que son los unicos de temperatura
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2); 
  
  // Leemos de a un byte a la vez
  buffer[0] = Wire.read();
  buffer[1] = Wire.read();

  // Mostramos la temperatura con DS3231 por el Monitor Serial
  if (buffer[0] < 0xFF) {  // Para evitar una falsa lectura que usualmente viene en 0xFF = -127C lo que es imposible
    Serial.println(String("La temperatura actual es de: ") + buffer[0] + "." + (buffer[1]/64*25) + "C");
  }    

  // Leeremos la temperatura cada 1 segundo
  delay(1000);  
}

Otro dato extra es que como medir la temperatura no es la función principal del chip, y el mismo tiene un conversor interno, a veces está “ocupado” actualizando los registros y la lectura de los mismos es incorrecta. Lo que me sirvió a mi es descartar las lecturas que son todos unos en el registro 11h, y con eso solo ya pude obtener muy buenos resultados. Otra técnica sería la de usar 2 o 3 lecturas y verificar que no difieran en más de 2 o 3 grados lo que sería imposible.

Finalmente, para probar el programa haga como de costumbre, inicie el Monitor Serial y observe las mediciones. Si desea ver la reacción del modulo a cambios de temperaturas, puede probar apoyando su dedo sobre el chip (detras de la pila, es el más grande en mi caso pero sino pueden leerlo con ayuda de una lupa), y si la temperatura ambiente es más baja que 30C, entonces comenzará a subir hasta aprox. esa temperatura. Quiero decirles que según las especificaciones de temperatura con DS3231, el rango de operación es de -40C a +85C, por lo que esperaría poder tener lecturas de temperatura también dentro de dichos rangos. Ojo con las altas temperaturas que otros componentes del módulo pueden no tener tanta tolerancia.

Accediendo a la memoria EEPROM del módulo

Mi módulo (y la mayoría de los módulos que implementan el DS3231 por lo que he podido investigar), viene con una memoria incorporada de 32K que debe leerse 32 kilobits lo que es igual a 4Kbytes. Para los que están acostumbrados al Arduino Mega 2560, es la misma cantidad de EEPROM que el Arduino posee, lo que no es despreciable, y 4 veces la cantidad que un Arduino UNO posee (que es 1Kbyte).

Dicha memoria no es parte del DS3231, pero viene con casi todos los módulos y está integrada de manera de que se accede mediante las mismas conexiones. En mi caso, y en la mayoría de los casos, se trata de una Atmel AT24C32, que dicho sea de paso es el mismo fabricante de los microcontroladores que usan los Arduino. No entraremos en demasiados detalles con esta memoria, algo que posiblemente hagamos en otro momento en otra página.

La memoria se accede mediante I2C al igual que el reloj, y de similar manera excepto que la dirección I2C para la memoria en este caso es 57h (en lugar de 68h que es la del reloj), y las direcciones dentro de la EEPROM son de 2 bytes en lugar de 1 byte, ya que tenemos 4096 bytes y no nos alcanza con 1 solo byte.

El Sketch y algunas aclaraciones

Primero que nada les dejo el Sketch para que lo vayan viendo, lo carguen, prueben y, si se animan, ya comiencen a jugar con él:

// Incluimos la librería del proyecto Arduino para I2C
#include "Wire.h"

// Informacion de la EEPROM del módulo
#define DS3231_I2C_MEM 0x57
#define BUFFER_SIZE 32 

void setup() {
  // Inicializamos el Monitor Serial para nuestras pruebas
  Serial.begin(9600);

  // Inicializamos nuestra librería
  Wire.begin();
  
  // Mostramos lo que hay ahora en la direccion 0
  readAndPrint();

  /* <-- Elimine esta linea para probar escribir en la memoria
  // Escribimos los numeros del 1 al 9 en los primeros 9 lugares de la memoria
  Wire.beginTransmission(DS3231_I2C_MEM);
  
  Wire.write(0x00); 
  Wire.write(0x00); 
  
  for (int x=0; x<9; x++) {
    Wire.write(x); 
  }
  
  Wire.endTransmission();
  
  delay(10);
  
  // Mostramos lo que hay ahora luego de escribir en la memoria
  readAndPrint();  
  */ // <-- Elimine esta linea para probar escribir en la memoria
}

void loop() {  
}

// Esta funcion lee e imprime por el Monitor Serial los primeros 32 bytes de la memoria EEPROM
void readAndPrint() {
  int x;
  byte bufferMem[BUFFER_SIZE];
  
  // Solicitamos la lectura de la EEPROM del DS3231 desde el principio, direccion 0x0000
  Wire.beginTransmission(DS3231_I2C_MEM);
  Wire.write(0x00); 
  Wire.write(0x00); 
  Wire.endTransmission();
  
  // Pedimos nos envien los primeros 32 bytes
  Wire.requestFrom(DS3231_I2C_MEM, BUFFER_SIZE); 
  
  // Leemos de a un byte a la vez
  for (x=0; x<BUFFER_SIZE; x++) {
    bufferMem[x] = Wire.read();
  
    // Para mostrar ls informacion siempre en hexadecimal de 2 digitos
    if (bufferMem[x] < 0x10) {
      Serial.print("0");
    }
    
    Serial.print(bufferMem[x], HEX);
    Serial.print(" ");
    
    // Mostramos 16 bytes por linea
    if ((x+1)%16 == 0) {
      Serial.println("");
    }
  }  
}

Observen que el Sketch posee un area de código comentada. Esta area tiene el código para escribir en la memoria EEPROM en los primeros 9 bytes, pero se los dejo comentado para que prueben su memoria primero que nada como está, y luego puedan compararla con lo que verán luego de escribir en ella. Otra aclaración es que la EEPROM no se borra cuando desconectamos el módulo, por lo que es sumamente util para guardar información que queremos leer en cada reinicio, como parámetros de configuración de un proyecto.

 

 

8 comentarios en “Midiendo la temperatura con DS3231 (y extras)”

    • Hola Fernando, gracias por tu comentario. Los programas que compartimos son todos funcionales y están completos. Los copias, los pegas en un Sketch y funcionan. En el caso de los proyectos, incluimos un programa grande que integra muchas cosas, pero en el caso de los instructivos de módulos y Shields solo incluimos programas de prueba para enseñar como controlar los elementos mencionados y cada funcionalidad la explicamos por separado con un programa por separado. En este caso, sobre el módulo DS3231, cada capacidad del módulo se explica con un programa de ejemplo. No sé bien a que te referís con un programa completo…

      Responder
  1. Hola buenas noches
    Tengo un proyecto donde utilizo un DS3231 para programar los eventos con alarmas pero quisiera saber si se podría activar unos ventiladores tomando la temperatura del RTC

    Responder
    • Si, no veo por que no. Deberias integrar algun módulo de relays para el control del ventilador, y programar el codigo para que controle la temperatura periodicamente, una vez cada 10 mins por ejemplo o cada minuto.

      Responder
      • Hola amigo que tal, gracias ya pude hacer lo que queria activar unos ventiladores obteniendo la temperatura del reloj agregando a tu segundo ejemplo este codigo en el void loop

        if (buffer[0] >= 36)
        digitalWrite(Fan1, HIGH);
        else
        digitalWrite(Fan1, LOW);
        if (buffer[0] >= 34)
        digitalWrite(Fan2, HIGH);
        else
        digitalWrite(Fan2, LOW);
        if (buffer[0] >= 36)
        digitalWrite(Fan3, HIGH);
        else
        digitalWrite(Fan3, LOW);

  2. Hola buenas tardes
    Buena explicación pero una pregunta
    Estoy realizando un reloj con varias alarmas que se programan por medio de botones y tengo diferentes variables que son las horas y minutos que tengo que guardar y al aplicar la manera que usted explica ahí no me resulta y no tengo idea pues estoy aprendiendo a utilizar eso. No tendría un ejemplo de la ds3231 donde se guarden varias variables
    Por favor

    Responder

Deja un comentario