Arduino: sensor de temperatura y humedad de bajo coste

En esta primera entrega de Arduino, he decidido presentaros un pequeño proyecto, muy simple (podríamos decír que se trata de un proyecto para principiantes) en el que veremos cómo capturar la temperatura y el nivel de humedad del ambiente a través de un sensor de bajo coste.

El sensor que utilizaremos es el DHT22, también conocido por AM2302 (podéis encontrar su datasheet en este enlace). Se trata de un sensor de bajo coste, pero con unas capacidades mas que aceptables para proyectos con Arduino, gracias a su sencillez de uso y montaje. El precio aproximado es de unos 6€, gastos de envío incluidos, y podréis encontrarlo en eBay sin problemas. Existen otros sensores de la misma familia, como por ejemplo el hermano menor, el DHT11, que son algo mas baratos (quizá cueste la mitad), y también de menores prestaciones, como por ejemplo menos sensibilidad y precisión. Cuando buscaba un sensor para este proyecto, solo pensaba en la temperatura, pero se me cruzo ante los ojos el 11 y, poco a poco fui tirando del hilo, hasta llegar al 22. Sin duda puedo adelantaros que merece la pena invertir un poco mas y comprar el 22, aunque para el propósito de este proyecto, y si vuestra finalidad es la mera instrucción en este campo de los sensores, quizá el hermano pequeño cumpla mas que de sobra con vuestras expectativas.

Bien, no entraré en mas detalles sobre este estupendo sensor, podéis encontrar más información al respecto por la web sin mayor problema. Simplemente comentaremos los principios básicos de su funcionalidad.

DHT22

 

Según el esquema anterior, el patillaje del DHT22 se observa desde la parte frontal, de modo que la patilla 1 (izquierda) es la alimentación, de 3,3V a 6V DC, la 2 es la patilla de datos, y la 4 es tierra. La 3 no se utiliza, por lo que puede quedar al aire sin problemas. En algunas webs he podido leer que es posible conectar el 3 a GND también.

Internamente monta un sensor polímero capacitivo para la humedad y el transistor DS18B20 para la temperatura, capaces de ofrecer lecturas digitales en el pin 2. La lectura es bastante precisa y no necesita calibración. Pero aún mejor, está preparado para ser conectado directamente a la alimentación y para obtener la señal directamente en un solo hilo, puesto que incluye una resistencia pull-up conectada desde el DATA hasta VDD, con lo que el conexionado es directo. Esto favorece el echo de poder utilizarlo en proyectos con Arduino de manera directa y muy sencilla.

A continuación os muestro el detalle de sus características:

  • Alimentación: de 3,3 a 6V DC
  • Rango de medida: 0 – 100% HR, -40 a 125ºC
  • Sample rate: 0.5Hz (1 lectura cada 2s mínimo)

Lectura de datos

Vamos al lío. A continuación os muestro la conexión básica. En esta primera versión la lectura de los datos la mostraremos por el canal serie, de modo que es fácilmente explotable:

Como véis, no es necesario ningún componente electrónico extra. Para este montaje hemos utilizado el Arduino (puede servir cualquir versión, dada la sencillez del esquema), una protoboard y el DHT22.

Conexionado:

  • Cableado rojo: alimentación +5V, del Arduino a la pata 1 del DHT22
  • Cableado negro: GND, del Arduino a la pata 4 del DHT22
  • Cableado naranja: DATA, del pin 2 (entrada / salida digital, interrupción externa) a la pata 2 del DHT22

Bien, una vez tenemos realizado el conexionado, vamos a ver cómo leemos las medidas del DHT22. Vamos a por el código.

Lectura de datos, explotación vía serie

El primer montaje que vamos a hacer es el mas simple y el primero que piensa uno en probar: lectura del dato, envío hacia la salida serie de Arduino (así podremos visualizarla desde el IDE fácilmente).

Utilizaremos la libería DHTMaster: https://github.com/markruys/arduino-DHT

Y este es el código, basado en el propio ejemplo de la librería:

#include "DHT.h"

DHT dht;

void setup() {
  setupSensor();
  setupSerial();
}

void loop() {
  // Tiempo de espera entre lecturas
  // El mínimo, 2 sgundos
  delay(dht.getMinimumSamplingPeriod());

  // Obtenemos los datos desde el sensor 
  // tras el tiempo de espera

  // Estado del sensor (OK/NOK)
  String estatus = dht.getStatusString();

  // Tanto por ciento de humedad
  float humidity = dht.getHumidity();

  // Temperatura en ºC
  float temperature = dht.getTemperature();

  // Temperatura en ºF
  float fTemperature = dht.toFahrenheit(temperature);

  // Escribimos a la salida serie
  writeToSerial(estatus,humidity,temperature,fTemperature);
}

void setupSensor() {
  // Inicializamos la lectura 
  // en el pin 2 de Arduino
  dht.setup(2);
}

void setupSerial() {
  // Inicializamos el canal serie
  // para escribir a 9600bps
  Serial.begin(9600);
  Serial.println("Estado\tHumedad (%)\tTemperatura (C)\t(F)");
}

void writeToSerial(String estatus, float humidity, float temperature, float fTemperature) {
  Serial.print(estatus);
  Serial.print("\t");
  Serial.print(humidity, 1);
  Serial.print("\t\t");
  Serial.print(temperature, 1);
  Serial.print("\t\t");
  Serial.print(fTemperature, 1);
  Serial.println();
}

A continuación os explico el programa. No voy a entrar en detalles de la librería, dado que podéis descargarla y consultarla. Desgraciadamente no es el objetivo de este post.

He intentado que el código sea autocontenido, pero a grandes rasgos, lo que hace es:

  • Inicializamos el pin de lectura del sensor, pin 2 del Arduino (la librería lo configura como trigger de interrupción y lectura digital) (línea 37)
  • Inicializamos la salida serie a 9600bps y escribimos una cabecera (líneas 43 y 44)
  • Una vez ya dentro del loop, realizamos una espera del mínimo de segundos posibles, 2, entre lectura y lectura (línea 13). Si lo deseáis, podéis indicar vosotros el tiempo que necesitéis, en milisegundos.
  • Obtenemos los datos enviados por el sensor cada 2 segundos, obteniendo en cada caso el dato deseado: estado de la lectura como OK/NOK (línea 19), % de humedad como float (línea 22), temperatura en ºC como float (línea 25) y finalmente la temperatura en ºF como float (línea 28)
  • A continuación, escribimos estos datos por el canal serie (línea 31)

Y con esto ya tenemos nuestra primera versión del sensor de humedad y temperatura.

Si compiláis el programa, y abrís el monitor serie del IDE, veréis que Arduino empieza a ponerse en marcha, y cada 2 segundos lanza los datos a la salida (notad que parpadea el led naranja de TX):

Esta es una captura de mi monitor serie. Como podéis observar, tengo una temperatura de 23ºC y una humedad de aproximadamente un 50%. ¿No está mal no? Tengo buena calefacción…

Antes de finalizar este apartado, quiero recordaros que estamos haciendo uso de esta estupenda librería que nos permite olvidarnos de configurar el sensor, ya que lo hace de manera automática. Eso es un gran logro, ya que nos desinhibe totalmente de la capa de comunicación. También quiero comentaros que, como os decía al principio, podréis hacer uso de este código tanto para el DTH22 como para el DTH11, pero os informo que el tiempo mínimo de lectura del 11 es 1 segundo, en contra de los 2 del 22.

Mejora: salida a pantalla

Bien, lo majo de estas cosas es tener un aparatito que nos indique en cada instante toda esta información de manera más llamativa, más gráfica, si cabe. Es lo que os propongo a continuación. Vamos a mejorar la salida, enviando los datos a una pantalla LCD de 128×64 px. En mi caso se trata de una pantalla con chipset ST7920 y controlador serie de 3 hilos (VDD, GND y SDATA).

Como podéis observar, el pinout de mi pantalla no está muy bien definido. Eso es porque no dispongo del diseño de mi controlador serie en el Fritzing para dibujarlo. Para los interesados, os puedo decir que la compré por eBay y que es una SainSmart con controlador serie. Es la mas barata que pude encontrar y que fuera con controlador serie. Venía con una shield de expansión para Arduino UNO. Salió por unos 16€ gastos de envío incluidos.

El pinout es el siguiente:

  • Cable morado: pin 16, TX2 de Arduino, SID de la pantalla
  • Cable amarillo: pin 17, RX2 de Arduino, CS de la pantalla
  • Cable verde: pin 18, TX1 de Arduino, SCK de la pantalla

La librería de control de pantalla es la estupenda u8glib (http://code.google.com/p/u8glib) que nos permite controlar infinidad de modelos de pantallas y chipsets, a demás de tener un gran juego de fuentes disponibles. Una vez mas, y debido a que no quiero extenderme demasiado, no puedo entrar en detalles, pero si la descargáis veréis que es muy fácil de importar en vuestro proyecto.

Este es el código:

 

#include "DHT.h"
#include "U8glib.h"

DHT dht;
U8GLIB_ST7920_128X64_4X u8g(18, 16, 17);

float maxTemperature;
float minTemperature;
float maxHumidity;
float minHumidity;

void setup() {
  setupVariables();
  setupSensor();
}

void loop() {
  delay(dht.getMinimumSamplingPeriod());

  String sensStatus = dht.getStatusString();
  float temperature = dht.getTemperature();
  float humidity = dht.getHumidity();

  calcMinMax(sensStatus, temperature, humidity);

  // picture loop
  u8g.firstPage();
  do {
    writeToLDCD(sensStatus, temperature, humidity);
  } while ( u8g.nextPage() );
}

void setupVariables(void) {
  maxTemperature = 0.0;
  minTemperature = 0.0;
  maxHumidity = 0.0;
  minHumidity = 0.0;
}

void setupSensor(void) {
  dht.setup(2); // data pin 2
}

void calcMinMax(String sensStatus, float temperature, float humidity) {
  if (maxTemperature < temperature) {
    maxTemperature = temperature;
  }

  if (minTemperature == 0.0) {
    minTemperature = temperature;  
  }

  if (minTemperature > temperature) {
    minTemperature = temperature;
  }

  if (maxHumidity < humidity) {
    maxHumidity = humidity;
  }

  if (minHumidity == 0) {
    minHumidity = humidity;  
  }

  if (minHumidity > humidity) {
    minHumidity = humidity;
  }
}

void writeToLDCD(String sensStatus, float temperature, float humidity) {
  // Parte superior
  u8g.setFont(u8g_font_fub20);
  u8g.setPrintPos(34, 25);
  u8g.print(temperature);

  u8g.setFont(u8g_font_helvR08);
  u8g.setPrintPos(107, 11);
  u8g.print("o");

  u8g.setFont(u8g_font_helvB12);
  u8g.setPrintPos(113, 17);
  u8g.print("C");

  // Humedad
  u8g.setFont(u8g_font_6x12);
  u8g.setPrintPos(66, 38);
  u8g.print(humidity);
  u8g.setPrintPos(98, 38);
  u8g.print("%");

  // Parte inferior
  u8g.setFont(u8g_font_baby);

  // Temp. máxima
  u8g.setPrintPos(5, 52);
  u8g.print("T. max: ");
  u8g.setPrintPos(35, 52);
  u8g.print(maxTemperature);

  // Temp. mínima
  u8g.setPrintPos(5, 62);
  u8g.print("T. min: ");
  u8g.setPrintPos(35, 62);
  u8g.print(minTemperature);

  // Humedad máxima
  u8g.setPrintPos(70, 52);
  u8g.print("H. max: ");
  u8g.setPrintPos(100, 52);
  u8g.print(maxHumidity);

  // Humedad mínima
  u8g.setPrintPos(70, 62);
  u8g.print("H. min: ");
  u8g.setPrintPos(100, 62);
  u8g.print(minHumidity);
}

El código, una vez mas, es bastante sencillo. La base es la misma que en el caso anterior: inicializamos el sensor y obtenemos los datos. Esta vez, en vez de llamar a la escritura por serie en el loop, lo que hacemos es llamar a una rutina que va rellenando el contenido de la pantalla. Lo mas difícil en esta mejora fue la de manipular las posiciones de las cadenas de texto a la hora de escribir por pantalla. Es un tanto tosco, pero con unas cuantas horas se pudo hacer y obtener unos resultados bastante llamativos.

También se han añadido 4 variables mas que nos permiten almacenar las temperaturas máxima y mínima de histórico, así como los porcentajes de humedad, máximos y mínimos. A cada paso de loop, escribimos por pantalla y actualizamos dichos valores.

Os dejo una imagen del proyecto final, en pleno funcionamiento:

IMG_20131201_212631

IMG_20131201_214341

IMG_20131201_214351

Espero que os haya parecido interesante.

Jordi

Share Button

2 comentarios

Responder a Fernando Cancelar la respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.