Introducción
El DHT11 es un sensor bastante económico que permite realizar mediciones de temperatura y humedad. En esta entrada te presentamos nuestro código en C para leer este sensor y un ejemplo práctico con un PIC16F88 que también debería adaptarse sin problemas al PIC16F628A y a otros micros similares de 8 bits como el PIC18F4550.
Nuestro programa se comunica con el sensor y muestra las mediciones en una pantalla LCD. Cabe aclarar que usaremos MPLAB X y el compilador XC8 como plataforma de desarrollo en este ejemplo.
En la foto de portada vemos un sensor DHT11 conectado a un PIC16F88 que muestra la lectura de temperatura y humedad en una pantalla LCD de 16×2.
Comunicación con el sensor DHT11
La trama del DHT11 se ve así en el osciloscopio, recordemos que cada “cuadrito” en la pantalla del instrumento equivale a 100 uS.
De izquierda a derecha se observa lo siguiente:
- Fin de la señal de inicio seguida de un “glitch” a nivel alto que ocurre mientras el microcontrolador libera el bus y el DHT11 toma el control de la linea.
- Pulso de respuesta bajo del DHT11 de alrededor de 80 uS.
- Pulso de respuesta alto del DHT11 de alrededor de 80 uS.
- Primer bit “0” compuesto de un pulso bajo de 50 uS y otro alto de alrededor de 25 uS
- Segundo bit “0”
- Tercer bit “1” compuesto de un pulso bajo de 50 uS y otro alto de alrededor de 70 uS
- La secuencia continua (0 0 0 1 … etc. )


Hemos hablado un poco de los detalles del protocolo de comunicación del sensor DHT11 en la página del producto, por lo que en esta podrás encontrar información de cómo funciona este sensor que hemos usado como base para escribir el código de la librería para PIC.
Librería para el DHT11
Descarga e instalación
Nuestra librería para el DHT11 se encuentra alojada en Github, como siempre, agradeceremos cualquier contribución, corrección o ejemplo que quieras aportar. Puedes obtener la librería con los ultimos cambios y novedades desde nuestra página en github.com:

Para obtener la ultima versión de la librería podemos usar git con el siguiente comando:
git clone --recursive https://github.com/geekfactory/DHTLib.git
La librería básica para el DHT11 consiste en 3 archivos de código fuente:
- DHTLib.h – Contiene la declaración y documentación de las funciones (prototipos).
- DHTLib.c – Implementación de las funciones para la lectura de los sensores de humedad y temperatura
- DHTLibPort.h – Contiene los macros de preprocesador de C que permiten acceder a los puertos de entrada / salida
- Config.h – Este archivo es incluido por todas las liberías que requieren ajustes en tiempo de compilación, aqui se definen los pines de entrada / salida a utilizar con el DHT11 y la velocidad del reloj.
Si no tienes instalado Git o no deseas utilizar esta herramienta, aquí esta el paquete de MPLAB X con el proyecto completo, listo para compilarse.
[wpdm_file id=1 title=”true” desc=”true” template=”facebook drop-shadow curved curved-hz-2″ ]
Configuración de pines en la librería
Para cambiar los pines asociados al DHT11 o la velocidad de reloj editamos el contenido del archivo Config.h que se encuentra en la carpeta “project_conf” dentro del proyecto de MPLAB X. El contenido del archivo en nuestro ejemplo es el siguiente:
#ifndef CONFIG_H #define CONFIG_H /** * Configures here the processor speed */ #define CONFIG_TIMING_MAIN_CLOCK 2000000 /** * Configure here the registers and pins associated with the DHT11 sensor */ #define CONFIG_DHTLIB_OUTPIN PORTBbits.RB2 #define CONFIG_DHTLIB_PORTPIN PORTBbits.RB2 #define CONFIG_DHTLIB_TRIS TRISBbits.TRISB2 #endif // End of Header file
Uso básico para leer el sensor
Usar la librería para el DHT11 es bastante sencillo: Solamente debemos incluir el archivo DHTLib.h y luego, en alguna parte del comienzo de nuestro programa debemos llamar a la función dhtlib_init(). Posteriormente cuando deseemos obtener el valor de la temperatura deberemos llamar a la función dhtlib_read(). Esta ultima acepta como parámetro dos apuntadores a variables de tipo “uint8_t” donde se guardarán las medidas de humedad y temperatura. La función retorna un valor de tipo enumeración que nos informa si la comunicación con el sensor se pudo llevar a cabo de forma exitosa.
Dejamos aquí el código de la función principal de nuestro programa para el PIC que ilustra el uso de la librería para el DHT11. Hemos destacado las partes que todo programa que use la librería DHTLib debe tener:
#include <xc.h>
#include <stdio.h>
#include "../Tick/Tick.h"
#include "../LCD/LCD.h"
#include "../DHTLib.h"
// Configuración del dispositivo
// CONFIG1
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB0 // CCP1 Pin Selection bit (CCP1 function on RB0)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// CONFIG2
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode disabled)
// Buffer para trabajar sobre el texto que se envía a la pantalla LCD
char buf[20];
// Prototipos de las funciones definidas en este archivo
void dht11_task(); // Actualiza la pantalla con la temperatura y humedad
void led_task(); // Hace parpadear el led de estado en el pin 4 del puerto A
/**
* Implementación de la funcionalidad principal del programa
*/
void main()
{
//OSCCON = 0x6C; // Para usar el oscilador interno PIC16F88 4 Mhz
OSCCON = 0x7C; // Para usar el oscilador interno PIC16F88 8 Mhz
ANSEL = 0x00; // Configuracion de pines analogicos y digitales
TRISA = 0xE0;
TRISB = 0xFF;
// Preparamos las librerías para su uso
lcd_init(0, 16, 2); // Iniciar el controlador de pantalla
tick_init(); // Iniciar el contador / temporizador del sistema
dhtlib_init(); // Preparar la comunicación con el sensor DHT11
// Encendemos la pantalla LCD y escribimos titulo
lcd_on();
lcd_puts(" PRUEBA DHT11 ");
// Ciclo principal de nuestra aplicación
for (;;) {
led_task();
dht11_task();
}
}
/**
* Código para leer el sensor de temperatura y mostrar en pantalla
*/
void dht11_task()
{
// Variables locales
static uint32_t ltick = 0;
uint8_t tb = 0, hb = 0;
// La lectura de la temperatura y la humedad se realiza cada 5 segundos
if (tick_get() - ltick >= TICK_SECOND * 5) {
// Recordar el tiempo en el que se toma la lectura
ltick = tick_get();
// Colocar el cursor en la segunda linea
lcd_goto(0, 1);
// EN ESTA LINEA REALIZAMOS LA LECTURA DEL SENSOR
enum dht_status result = dhtlib_read11(&tb, &hb);
// Preparamos la cadena a mostrar
if (result == E_DHTLIB_OK)
sprintf(buf, "T: %02d C H: %02d%% ", tb, hb);
else
sprintf(buf, "Sensor error: %02d ", result);
// Escribimos la cadena a la pantalla
lcd_puts(buf);
}
}
/**
* Esta funcion alterna el estado del led cada 1/2 segundo
*/
void led_task()
{
// Guarda el valor del tick en el que se alterno el pin del led
static uint32_t ltime = 0;
if (tick_get() - ltime >= TICK_SECOND / 2) {
ltime = tick_get();
PORTA ^= 0x10;
}
}
/**
* Implementación del vector de interrupción (único)
*/
void interrupt isr(void)
{
// Actualizar el conteo del tiempo
tick_update();
// Otras interrupciones deben manejarse aqui
}Conexiones para el programa de prueba
El programa permite medir y desplegar la temperatura y humedad en una pantalla LCD de 16 x 2. Utilizamos la pantalla en modo de 4 bits y realizamos las conexiones como sigue:
- RA0 – RA3 – Bus de datos para el display LCD (4 bits)
- RA4 – Luz led indicadora de actividad del micro (parpadea una vez por segundo).
- RB0 – Enable del chip controlador del LCD.
- RB1 – RS (Register Select) del chip controlador del LCD.
- RB2 – Conexión al pin de datos del sensor DHT11

Conclusión
A fin de cuentas observamos que implementar la comunicación con el DHT11 es bastante sencillo y nuestra pequeña librería nos puede servir para varios microcontroladores más. Por ejemplo, nosotros ya la probamos en un ATMEGA8 y un PIC24HJ128GP504. Para migrar nuestra librería a otro microcontrolador, basta con escribir de nueva cuenta los macros de preprocesador que se encuentran en el archivo DHT11Port.h y definir los pines correctos en el archivo Config.h.
En la ultima versión de nuestra librería hemos incluido soporte para el sensor DHT22, que es similar al DHT11 pero ofrece mejor desempeño que este. Las funciones para leer datos desde el DHT22 se encuentran documentadas en el archivo DHTLib.h y pueden ser usadas de manera similar a las presentadas en este artículo.









Se puede hacer en PIC18F452?
Hola me podrías ayudar con las conexiones enviándome fotos del prototipo y/o indicando cuales son los materiales, me ayudarías mucho… Gracias ;)
Hola, se puede usar para una tarjeta LCP1769, cortex M3?
Hola.
Si se debe de poder usar, solamente habría que realizar las adaptaciones correspondientes. El artículo muestra el funcionamiento del sensor, por lo que seria cuestión de que revisaras como hacer la adaptación.
Saludos.
Al compilar con mi pic 16f887 me saltan un monton de errores en la “libreria DHTlib.c” les agradeceria su ayuda
Muchas gracias! desde MPLab 3.3 and Proteus 8.2 va muy bien. Solo tuve que hacer un pequeño cambio con las carpetas (soy nuevo en esto y me resultaba un desafio como acomodar el proyecto en las carpetas), inicialmente me salio un cartel de error en MLlab diciendo que el target “LCD/Delay/Delay.h” no estaba, pues busqué en todos los archivos donde se encontraba dicho path, no lo encontré, Total: desconprimí dhtlib-demo-pic16.rar donde entontre el delay.h, pues lo lleve con su carpeta a la carpeta LCD, que tambien se encuentra en una parte mas abajo del path. Espero haber sido claro, obligado a hacer prueba y error, le di. Muchas gracias una vez mas ruben, me has dejado un un muy buen comienzo!
buenas noches alguien me puede ayudar ya descargue las librerías pero tengo problemas con el compilador ya que yo uso c18 no xc8 si alguien me puede ayudar agradezco uso un pic18f47j53 mplabx y c18 compilador
Buena Noche, si quisiera enviar la información obtenida por el sensor de manera inalámbrica mediante el uso de modulos de Radiofrecuencia (433Mhz) como habilito el puerto USART del PIC16F88. Gracias
hola, soy novato con mplab x, ya descargue las librerías de Github, pero no se donde y como guardarlas para que en el momento que las necesite pueda invocarlas con el #include en mi programa… yo uso el MplabX con el compilador XC8, agradecería una ayuda!
De verdad no se donde guardar ningunas de las 3 librerias…Ayuda por favor!
Buenas tardes!! me pregunto si esas librerías sirven para el mikroC, ya que este es el software que uso para programar con el PIC18F4550 saludos
Buenas, alguien sabe como puedo implementarlo para un micro (LPCXpresso 1769), el hard q tendria que implementar.
Buenas tengo un problema al implementar esta librería a mi pic24f32ka304 me da un error en la libreria DHTLibPort.h en la linea q hace refencia a typedef uint8_t PORTBASE si alguien tiene idea de porque puede ser me ayudaria muchisimo. Un saludo y gracias por adalentado
Hola!
¿Será que en los otros archivos que tienes en el proyecto tienes otra definición que entra en conflicto con la de nuestra librería?
¿Cual es el mensaje especifico que te manda?
Saludos.
Hola @GeekFactoryMx:disqus necesito saber como pasar libreria a compilador C18 mplab utilizo PIC18f2550. Me ayudarias por favor. Un consejo. Saludos
Hola Antonio:
Intenta cambiar la ruta por ../Delay/Delay.h y nos cuentas como te fue.
Saludos.
Hola, tengo una nueva pregunta, que pasa si quiero usar 2 DHT22 con el mismo PIC? como se haría? es necesario añadir otra librería (osea la misma pero con otro nombre y otro nombre para todas las rutinas) donde se defina un nuevo PIN de datos? o como se haría?
Hola.
Es posible compiando el código y creando funciones alternativas completamente diferentes. Por ejemplo dhtlib_read22_a() y dhtlib_read22_b(). Yo ya había pensado en esta posibilidad (usar más de 1 sensor) y comecé a desarrollar una librería con esta capacidad, sin embargo hemos tenido problemas con la velocidad de ejecución de las funciones de entrada/salida.
Puedes encontrar el codigo en el branch “Experimental_IO” en github. Como verás, ahora las funciones reciben un argumento adicional (tipo dht_t) que indica el pin al que está conectado el sensor. Por ejemplo el prototipo de la función de lectura nuevo es:
enum dht_status dhtlib_read11(dht_t sensor, uint8_t * temp, uint8_t * hum)
La rama la encuentras en esta URL:
https://github.com/geekfactory/DHTLib/blob/Experimental_IO/DHTLib.c
La implementación de las funciones para manejar pines de IO las puedes encontrar acá, toma en cuenta que su ejecución me resultó problemática debido a los (algo) estrictos requisitos de tiempo del DHT11:
https://github.com/geekfactory/PID/blob/master/pid-demo-pic18.X/io.c
Si pudieras probarlo en el PIC18 a más velocidad, sería de ayuda :).
Estoy trabajando a 20MHZ no se si a eso te refieras o a la velocidad de respuesta de los pines en los PIC18, probaré el código que me has facilitado, apenas tenga resultados te comento, gracias.
Si me refiero a que las funciones como están escritas tardan mucho tiempo en ejecutarse y puede afectar en la comunicación. De hecho son mucho más lentas que escribir directamente al puerto a través de las estructuras (bitfields) definidos en el encabezado del compilador. Te recomiendo que si tienes problemas de tiempo, reduzcas las funciones de IO a un switch-case que realice operaciones sobre pines específicos.
Agradecería cualquier comentario sobre tu experiencia. Saludos.
Hola, he probado mudar la librería a un PIC16F877A para simular en proteus, el proyecto compila, la simulación inicia pero imprime en la pantalla que hay el error 01, de hecho no veo actividad en el PIN de datos… agradecería cualquier apoyo.
Lo he resuelto poniendo el CONFIG_TIMING_MAIN_CLOCK a 1/4 de la velocidad del reloj del MU, sin embargo por que debe ser 1/4?
Hola Alejandro,
Normalmente los PIC funcionan a 1/4 de la velocidad de reloj. Es decir, si se coloca un determinado cristal, internamente se divide entre 4 y esta señal es la que se usa para ejecutar las instrucciones y también es la que va a los timers y otros periféricos del MCU. Por ejemplo si al PIC le ponemos un cristal de 4 Mhz, la frecuencia real de ejecución de instrucciones es de 1 Mhz. Toma en cuenta que según nuestras pruebas y con la versión “lite” del compilador XC8, es necesaria una velocidad de reloj de al menos 8 Mhz para que el DHT11 funcione correctamente.
Si el tiempo esta configurado correctamente, el PIC debería alternar el estado del pin RA4 cada 1/2 segundo, es decir, debes tener una señal de 1 hz en este pin.
Saludos.
Gracias por tu respuesta, acabo de mudar la librería a un PIC18F46K22 que es con el que realmente necesito trabajar, solo lo he estado modificando guiandome por los errores de compilación, manualmente deje solamente las opciones que aparecían para “PLIB_PIC18” ya que el compilador no dejaba de reconocer el “PLIB_PIC16” (no entiendo por que, mis conocimientos son muy vagos en cuanto a XC8 y el nuevo mplabx, sin embargo cambié el proyecto a la familia 18 pero sigué sin reconocer el “PLIB_PIC18”) definí “_XTAL_FREQ” a 8Mhz (aunque en realidad voy a trabajar a 20Mhz pero ya verifiqué que funciona), configuré ANSELA, PBADEN, etc… compiló, simulé y está funcionando, pero… no hice las correcciones de LAT en “Config.h” hasta probar en el circuito no se que problemas me podría traer, agradeceré tus comentarios
Hola Alejandro.
Los macros para PLIB_PIC18 o PLIB_PIC16 las puedes definir dentro de la ventana propiedades del proyecto (click derecho sobre el proyecto > Properties. Con esto pretendemos lograr que puedas compilar varias de nuestras librerías dentro de un proyecto con solo cambiar esta definición (te dejo captura de pantalla de donde se hace el cambio).
En los PIC18 y PIC24 se recomienda utilizar el registro LAT para escritura y el PORT para lectura, hay varias razones por las que se incorporó LAT, pero es algo extenso explicarlo aquí, por lo que te recomiendo que investigues un poco en internet, incluso en la hoja de datos. No deberías tener problemas al escribir a PORT ya que según la hoja de datos, las instrucciones de escritura en PORT van a parar al registro LAT del puerto. Citando la hoja de datos de un PIC18:
“Reading the PORTA register reads the status of the pins; writing to it will write to the port latch.”
Sin embargo, a mi me gusta ser explícito, por aquello de las dudas :D
Oooo vaya excelente muchas gracias Ruben, voy aprendiendo un poco más, he agregado la macro PLIB_PIC18 y usado los registros LAT ya con eso he mudado ahora mi proyecto con el PIC18F46K22 a una pantalla de 20×4, un DHT22 (usando la rutina de flotante de la librería y sprintf la cual es genial por hacerme las conversiones directamente de flotante a cadena de caracteres con exactamente los decimales que yo quiera, mientras que recuerdo anteriormente tenía que crear una rutina ftoa para hacerlo y luego imprimir) y un par de DS18B20, ahora solo estoy trabajando con los PWMs para terminar, todo a sido en simulación así que espero no toparme con muchos problemas cuando arme el circuito quedo muy agradecido por tu atención, saludos.
hola buen dia soy nuevo en esto de la programacion de pic y quiero saber si es posible compilar este archivo c en un asm asi como esta escrito o es necesario modificar algo y con que programa seria la major opcion utilizare un pic 16f628a de antemano gracias y saludos
excelente aporte!!!!!
Gracias por el proyecto, hay alguna forma de hacerlo trabajar sobre el PIC 18F4550 el mismo sensor, no entiendo como modificar los macros
Si hay forma de trabajarlo con ese PIC, la librería del DHT11 es fácil de llevar a otros micros.
Te explico: Para configurar el puerto en el que se conectará el sensor debes abrir el archivo dhtlibconf.h y cambiar el macro “#define CONFIG_DHT11_OUTPIN” y “#define CONFIG_DHT11_PORTPIN” y “#define CONFIG_DHT11_TRIS” el primero deberás colocarle un bit del registro LATX del PIC18, en el segundo un bit del registro PORTX y en el ultimo un bit del registro TRISX. La diferencia aquí es que los PIC18 tienen registros LAT mientras que el PIC16F88 no. También deberás verificar el archivo DHTLibPort.h para que los macros que activan y desactivan interrupciones sean correctos (creo que los registros se llaman igual en el PIC18F4550, pero en este momento no estoy seguro). Estos son necesarios por que el proceso de leer el sensor involucra periodos de tiempo que estan “muy justos” para pics de gama media como el que usamos en esta prueba (PIC16F88).
Te comento que el proyecto lleva varias otras librerías además del DHT11 y si necesitarás algo de conocimiento para llevarlas a otro micro, por ejemplo, lleva la librería de pantalla LCD (LCD.h y LCD.c) y la de control de tiempos (Tick.h y Tick.c). La del LCD debe ser fácil de llevar al PIC18F4550, mientras que la de tiempos puede llevar un poco más de trabajo y conocimiento de los timers. La librería de tiempos es la que te permite leer el sensor cada 5 segundos sin bloquear el microcontrolador con un “delay”, por ejemplo:
if( xTickGet() - ulLastTick >= TICK_SECOND * 5 )
{
ulLastTick = xTickGet();
//hacer algo cada 5 segundos aqui
}
Aunque te puedo asegurar que ya debe existir en la red un proyecto para el PIC18F4550 utilizando este sensor, te recomiendo que hagas el intento de pasar este código, te garantizo que aprendes bastante y además te quedan unas librerías bien documentadas que puedes usar en otros proyectos.
Saludos.
buenas noches un favor me podrias enviar el paquete q falta y ademas otra pregunta me puedes enviar la imagen del circuito
Hola Fabian.
El paquete esta completo,lo puedes descargar arriba. Te comento que no elaboré el esquemático por que como ves en la foto usé una placa entrenadora, revisa la sección que dice “Conexiones para el programa de prueba” ahi puedes armar fácil el circuito de la pantalla LCD.
Si te falla algo al compilar ¿Serías tan amable de informarnos que es?
Saludos.
buenas, me ha parecido un buen tutorial para comenzar con el dht11, sin embargo tengo un pequeño problema, a la hora de compilar el ejemplo que proporcionas mplab dice que falta el header “compiler.h”, ¿sabes como puedo resolver eso?
Lo estamos verificando, al parecer faltó agregar este archivo al proyecto y no va incluido en el paquete. En este caso subiríamos el archvio ZIP con el header faltante.
Acabamos de subir otro paquete con el archivo faltante. Ojalá pudiera probarlo y decirnos como le fue.
Este sensor puede ser utilizado para medir la humedad del suelo por ejemplo en una planta??? gracias por la respuesta.
Hola John.
Este sensor solo mide la humedad del ambiente. Hay sensores diseñados para medir la humedad del suelo basados en la conductividad del mismo. Estos tienen dos electrodos entre los cuales se hace circular una corriente eléctrica.
Saludos.
Excelente aporte!!!!! Gracias estaba buscando esto.
Una pregunta tengo el sensor DHT21 (casi igual que este) Se puede acoplar este código sin problemas para la lectura.
Hola:
No se puede usar directamente, ya que retornaría siempre un error de checksum, ya que se ignoran los bytes correspondientes a la fracción de temperatura y humedad. Sin embargo, es fácil de solucionar.
Quedamos a sus ordenes.
Super bien!