jueves, 6 de junio de 2019

1-WIRE Lectura de Temperatura y Humedad con DHT-11/22

Sensor Humedad/Temperatura DHT con PIC


Muchas gracias por tu visita a este blog relacionado con la programación de micro-controladores PIC, en esta entrada quiero mostrarles como utilizar los sensores de humedad y temperatura DHT que nos sera de gran utilidad en aplicaciones que requieran medir información ambiental o meteorología.

 El objetivo de esta entrada es realizar la lectura adecuada del sensor DHT con un microcontrolador PIC16F, para lo cual se implementara la comunicación con el protocolo 1-Wire respetando las especificaciones técnicas del sensor.

La programación se realizara utilizando el compilador XC8 y el entorno de desarrollo MPLABX, ambos disponibles de forma gratuita en la pagina de microchip.
Paso 1.Sobre el Sensor DHT

Es un sensor que mide Humedad y Temperatura de forma simultanea, cuenta con un procesador interno que realiza la medición al elemento capacitivo y termistor integrado, proporcionando el resultado a través de una señal digital. El proceso de comunicación con el PIC utiliza un único pin gracias al protocolo 1-Wire. Describiremos dos modelos identificados como DHT11 y DHT22 que poseen un encapsulado y disposición similar pero con las siguientes diferencias  técnicas:

  • DHT11: Trabaja con un rango de medición de temperatura de 0 a 50 °C con precisión de ±2.0 y un rango de humedad de 20% a 90% RH con precisión de 4%. Los ciclos de lectura debe ser como mínimo 1 o 2 segundos.
  • DHT22: El rango de  medición de temperatura es de  -40°C a 80 °C con precisión de ±0.5 y rango de humedad de 0 a 100% RH con precisión de 2%, el tiempo entre lecturas debe ser de 2 segundos.
A simple vista se puede observar que la diferencia con respecto a la medición esta en el rango y la precisión, pero revisando con mas detalle las especificaciones el pulso de inicio 1-Wire utiliza diferentes tiempos y el resultado se representa en un formato diferente, además el DHT11 soportar ciclos mas rápidos de lectura.


Paso 2. Conectar el Modulo al PIC16F.

El voltaje de operación nominal es 5V, la salida requiere utilizar una resistencia pull-up(entre 1-5k) para asegurar los niveles lógicos con el Microcontrolador, el manual también recomienda agregar un capacitor de 100nF entre VDD y GND para un mejor filtrado de la señal.


Es posible utilizar cualquier pin digital del PIC, eso si debe asegurarse de que sea bidireccional, algo que también debemos considerar es la distancia a la que puede estar el sensor del cual no tengo un dato exacto del limite máximo, pero he realizado pruebas sin inconvenientes hasta una distancia de 30mts, y considero que a mayores distancias se deberá utilizar un resistencia pull-up mínima(1k) considerando la perdida de voltaje en las lineas y posibles interferencias que puedan afectar a la señal de los datos.

Paso 3. Programación y lectura del sensor.

A fin de facilitar la rápida implementación del modulo, se crearon procedimientos en el archivo dht.c incluidos en la carpeta del proyecto MPLABX, en la ultima sección veras el enlace de descarga. 
El programa principal debe incluir las siguientes lineas que permiten definir el tipo y los pines utilizados con este sensor.
 
#define _XTAL_FREQ 4000000
#define DHTTYPE 11 // Modelo de sensor
#define DHTpin PORTBbits.RB0  //Pin de comunicación DTH
#define DHTtris TRISBbits.TRISB0 //Bit de control
#include "dht.h"

Para establecer la comunicación bidireccional utilizando solo un conductor, el sensor utiliza una variante del protocolo 1-Wire que establece reglas de temporización para las señales lógicas del microcontrolador.
 
En cada señal de lectura(Start signal) que realiza el microcontrolador, el sensor envía una señal de respuesta(Response signal) seguidos de una trama de 40bits, la duración de esta trama es variable en función de los niveles lógicos de cada bit recibido. 
Normalmente el pin del bus se encuentra en estado alto, entonces el (Start signal) que establece el microcontrolador es un pulso a nivel bajo con una duración de al menos 1ms(DHT22) o 18ms(DHT11) antes de normalizar el bus(nivel alto). Observe el diagrama de tiempos.
 
El sensor como respuesta(Response signal) colocara el bus en nivel bajo por 80us para luego normalizar esperando otros 80us, partir de este momento el sensor empezara a enviar una trama de 40 bits con la siguiente regla de tiempos:
(Bit 0) Nivel bajo por 50us y normalizar por un tiempo entre 25-28us.
(Bit 1) Nivel bajo por 50us y normalizar por un tiempo de 70us.
 
El siguiente código muestra un ejemplo simple para dar inicio al proceso de lectura en el sensor, siguiendo el diagrama de señal que se muestra en la parte superior.

    DHTtris = 0;    //Modo salida
    DHTpin = 0;     //Inicia el pulso bajo
    if(DHTTYPE == 22)
      __delay_ms(4); //Mantiene mínimo 1ms
    if(DHTTYPE == 11)
      __delay_ms(18);//Mantiene mínimo 18ms
    DHTpin = 1;     //Coloca el bus en nivel alto
    __delay_us(20); //Espera mínimo 20uS
    DHTtris = 1;    //Modo entrada
    while(DHTpin);  //Espera pulso bajo(hasta 40uS)
    while(!DHTpin); //Espera pulso alto(hasta 80uS)
    while(DHTpin);  //Espera pulso bajo(hasta 80uS)

 
Para mejorar este procedimiento inicial se deberá considerar limitar el tiempo de espera dentro de cada bucle indefinido, para esto se puede crear un procedimiento que utilice una variable de control que permita determinar la cantidad de tiempo transcurrido durante la espera.

De los 40 bits recibidos del sensor los dos bytes mas significativos representan la medición de humedad, los siguientes dos bytes corresponden a la medición de temperatura, finalmente un ultimo byte se utiliza para la comprobación de errores que se calcula con la suma de todos los bytes recibidos.


El sensor DHT22 representa la medición como un dato entero de 16-bits y como puede medir temperaturas negativas se utiliza el bit mas significativo del tercer byte para indicar el signo.

Ahora mostraremos la lista de los procedimientos que podemos utilizar para hacer uso de este sensor:
  • DHTSetup(): Es un procedimiento simple que coloca el pin de datos como entrada manteniendo un nivel lógico alto en el bus 1-Wire
  • DHTUpdate(dhtstruct *dht): Esta función realiza la lectura de las mediciones que posee el sensor y retorna un valor del tipo char para indicar si el proceso se realizo correctamente(1) o se produjo un error(0), ademas puesto que la lectura contiene información de humedad y temperatura se utiliza como parámetro un puntero a una estructura ya definida en el encabezado.
         typedef struct
         {
           unsigned int rawhum; //16bits para la humedad
           unsigned int rawtem; //16bits para la Temperatura
         } dhtstruct;




Paso 4. Prueba y Simulación.

Ahora escribiremos un pequeño programa para poner en practica y demostrar el uso de este sensor utilizando los procedimientos previamente descritos.

El siguiente código describe un programa que realiza la lectura de un sensor DHT11, muestra el resultado por el puerto USART en su formato de bits original y su conversión final.
  
#pragma config FOSC = INTRC_NOCLKOUT, WDTE = OFF, LVP = OFF
#include <xc.h>
#include <stdio.h>
#define _XTAL_FREQ 4000000
#define DHTTYPE 11  //Modelo DHT11
#define DHTpin PORTBbits.RB0 //Pin de datos RB0
#define DHTtris TRISBbits.TRISB0
#include "dht.h"
dhtstruct dht; //instancia a la estructura dht
unsigned int humedad, temperatura;
void main(void)
{
    char res;
    ANSEL = 0;  //Desactiva las entradas analógicas AN0-AN7
    ANSELH = 0; //Desactiva las entradas analógicas AN7-AN13
    OSCCONbits.IRCF = 6; //Configura el intosc a 4MHz Tcy = 0.5uS
    while(!OSCCONbits.HTS); //Espera estabilidad del oscilador
    DHTSetup();//Configura el pin de lectura para el DHT
   
    //CONFIGURAICON DEL MODULO USART 9600 BAUDIOS
    TXSTAbits.BRGH = 1; //UART en modo alta velocidad
    BAUDCTLbits.BRG16 = 1; //Generador de baudios en modo 16-bits
    SPBRG = 0x67; //X = _XTAL_FREQ/(4*BAUD) - 1;
    SPBRGH = 0x00;//X=[4000000/(4*9600)]-1 = 103 = 0x0067
    TXSTAbits.TXEN = 1; //Habilita la transmisión
    RCSTAbits.CREN = 1; //Habilita la recepción
    RCSTAbits.SPEN = 1; //Habilita el modulo USART
    while(1)
    {
        res = DHTUpdate(&dht); //Inicia la lectura del sensor
        if(res) //Verifica si se realizo correctamente
        {
            humedad = dht.rawhum >> 8; //Lectura la parte entera de la humedad
            temperatura = dht.rawtem >> 8; //Lectura la parte entera de la temp
            printf("Raw Hu=%04X Te=%04X\r\n", dht.rawhum, dht.rawtem);
            printf("Final Hu=%02u Te=%02u\r\n", humedad, temperatura);
        }
        __delay_ms(3000);
    }
}


1. Valores recibidos por la terminal USART


2. Ensayo del programa con un PIC16F886



Paso 5. Conclusiones y Recomendaciones.


Luego de hacer la demostración del programa podemos concluir que podemos implementar fácilmente cualquiera de estos dos sensores.

Para la conversión de lectura del sensor DHT22 deberá hacer una división entre 10, para conseguir el valor entero y si desea precisión con decimales debe guardar el resultado en variables del tipo float.
  float humedad, temperatura;
  humedad = dht.rawhum / 10.0F;
  temperatura = dht.rawtem / 10.0F;
  printf("Raw Hu=%f Te=%f\r\n", humedad, temperatura);
 
Los procedimientos descritos han sido probados a frecuencias igual o superiores a 4MHz en las versiones Free y Pro del compilador XC8; si requiere trabajar con frecuencias menores a 4MHz sera necesario modificar la función DHTReadbyte del archivo dht.c.

Una desventaja con estos sensores es la velocidad de las lecturas y el tiempo de espera para realizar una lectura nueva(2 segundos), aunque en muchos casos no es un factor negativo si consideramos que la Temperatura y Humedad son variables que no cambian de forma rápida.
 
Aquí dejo el enlace para que puedas descargar el proyecto creado en MPLABX para este blog, 
 
Enlace para Descarga -> DHTPIC16F 

Esperando que este ejemplo pueda servirte de ayuda agradezco tu visita al blog, atentamente Pablo Zárate
contacto:pablinza@me.com / pablinzte@gmail.com @pablinzar
Santa Cruz de la Sierra - Bolivia

 

miércoles, 5 de junio de 2019

I2C Utilizar un LCD con PCF8574

Modulo PCF8574x con el PIC16F
Fig1. Modulo PCF8574 y LCD

Antes que nada quiero agradecer tu visita a este blog relacionado con la programación de micro-controladores PIC, En esta ocasión veremos como utilizar un circuito integrado (CI) de expansión bastante practico y económico para conectar un modulo LCD con nuestro microcontrolador (MCU), utilizando únicamente dos lineas de comunicación gracias al protocolo serial I2C y el CI PCF8574x. El objetivo de esta sección es enviar mensajes a la pantalla LCD utilizando el protocolo de comunicación I2C entre el PIC16F887 y el PCF8574x.
 
La programación se realizara utilizando MPLABX y el compilador XC8 ambos disponibles en la pagina de microchip. Aquí dejo los enlaces de las versiones utilizadas para nuestro ejemplo:  <MPLABX v6.20>   <XC8 v2.45>
Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16. Al finalizar la sección les dejare el enlace para descargar la carpeta del proyecto que contiene todos los archivos citados en la presente publicación, también te recomiendo revisar los siguientes enlaces donde se explicar con mayor detalle el <Uso del TMRO> y la <Comunicación I2C>

Modulo PCF8574x con el PIC16F
 
El PC8574x es básicamente un modulo de conversion serie a paralelo, utilizado con el objetivo de expandir los puertos de entrada y salida de un sistema electrónico, como es el caso de un MCU que no dispone de puertos suficientes.
La comunicación con el PCF8574x se establece utilizando el conocido protocolo I2C, el caso de los microcontroladores PIC de gama media, estos disponen de un modulo de comunicación serial síncrono denominado SSP/MSSP,  que facilitan la implementación los protocolos SPI(Serial Peripheral Interface) e I2C(Inter-Integrated Circuit). En la codificación de nuestro programa utilizaremos la librería pcflcd donde se incluyen los procedimientos I2C necesarios para comunicarnos con el chip PCF8754x.

Paso 1. Sobre el Módulo PCF8574x.
I2C es un protocolo serial desarrollado por Phillips Semiconductors en la década de los 80, y fue concebido principalmente para comunicar dispositivos que están montados en un mismo sistema o circuito impreso.

Fig2. Pinout del PC8574x

El chip PCF8574 fabricado por Texas Instrument es un expansor paralelo de 8 bits controlado por I2C que opera a una velocidad estándar de 100KHz, diseñados para proveer monitoreo y control serial de forma fácil y económica. Existen dos variantes de este chip que son el PCF8574 y PCF8574A que se diferencian únicamente por el rango o mapa de dirección que pueden utilizar conforme a los valores lógicos en sus pines A2:A0.
 
Fig3. Tabla de direccionamiento PCF8574

Una gran ventaja de este protocolo es que establece una interfaz bidireccional maestro esclavo de hasta 128 dispositivos, aunque en la practica cada dispositivo limita su rango de asignación a un determinado mapa que puede ser configurado de forma externa o mediante instrucciones sobre el mismo protocolo.

Fig4. Conexión del Bus I2C
 
Implementar el bus I2C con el chip PCF es bastante simple, si observa la figura 4, solo se requiere utilizar resistencias pull-up por cada pin del microcontrolador, establecer la dirección de cada dispositivo conectado y su respectiva alimentación.

La figura 5, muestra el esquema de circuito necesario para la conexión del PCF8574A con las ocho lineas requeridas por el modulo LCD y las dos lineas de comunicación I2C del MCU.
 
Fig5. Esquema de conexión PCF8574A
Algo interesante es que este circuito esta disponible como un modulo genérico producido para aplicaciones de prototipo rápido, y que goza de bastante popularidad por su bajo costo económico($us. 3), incluso planteando comprar los elementos por separados no se justifica el precio por el trabajo y tiempo necesario para el montaje. Salvo que se trate de un producto final.

Fig6. Modulo PCF8574x
 
Por defecto este modulo tiene las lineas A2:A0 con nivel lógico alto que define una dirección de 27h (PCF8574) y 3Fh(PCF8574A); Si requiere agregar mas dispositivos o modificar la dirección necesitara soldar o conectar las siguientes lineas o pads en la parte posterior del modulo, de acuerdo a la figura 7.

Fig7. Pads para direccionamiento

Otro detalle es que el modulo ya cuenta con las resistencias pull-up requeridas por la interfaz y no sera necesario agregar estas resistencias incluso si utiliza otros dispositivos o sensores I2C.


Paso 2. Conectar el Modulo al PIC16F.
Fig8. Conexión al PIC16F

Solo necesitara identificar y conectar las cuatro lineas que posee el modulo, dos corresponden a la alimentación(5V/GND), y dos para la comunicación SDA(datos) y SCL(reloj). Muchas pantallas LCD cuentan con una luz de retroiluminacion(Backlight) que puede ser controlador a través de la interfaz siempre que coloque un puente(jumper) en el conector J2. 
 
El modulo también posee un potenciómetro que permite ajustar el contraste que la pantalla, deberá establecer un valor adecuado al momento de ensayar el programa.


Paso 3. Programación y envió de mensajes.

A fin de facilitar la rápida implementación del modulo en nuestra aplicación, se crearon los siguientes procedimientos y funciones incluidas en la cabecera pcdlcd.h. Debe revisar este archivo para efectuar algunas configuraciones necesarias antes de proceder a llamar cualquier procedimiento o función de esta librería.

Recuerde que el campo de dirección definido en el programa como PCFADDR dependerá de los valores lógicos que tienen los pines A2:A0 del chip PCF8574, estos pines por defecto tiene nivel logico 1, por lo tanto la dirección resultando sera de acuerdo al siguiente formato I2C.
 1. Para un Modulo PCF8574A PCFADDR=7Eh
 

 2. Para un Modulo PCF8574 PCFADDR=4Eh

Ahora mostraremos la lista de los procedimientos que podemos utilizar para enviar mensajes a nuestra pantalla LCD.
  • PCFSetupLCD(): Este procedimiento lleva a cabo la inicialización del modulo LCD, siendo por defecto la siguiente configuracion:
    1) Bus de datos en modo 4-bit y multi-linea;
    2) Incremento de posición automático;
    3) Muestra el cursor sin destellar;
    4) Limpia la pantalla e inicializa el cursor.
    La definición del puerto asociado a los pines del LCD y los valores de temporización se lleva a cabo modificando las siguientes lineas de código en la cabecera pcflcd.h.

    /* USER PORT DEFINITION */
    #define PCFADDR 0x7E //PCF8574A
    #define _XTAL_FREQ 8000000

    /* END USER PORT DEFINITIONS */

  • PCF_WriteCmd(): Este procedimiento permite enviar un comando al LCD, siendo algunos ejemplos de uso, los siguientes:
PCF_WriteCmd(LCD_CLEAR); //Limpia la pantalla LCD
PCF_WriteCmd(LCD_DISPLAY & LCD_DCURSOROFF); //Sin cursor
PCF_WriteCmd(LCD_DISPLAY & LCD_DBLINKOFF); //Sin destello
PCF_WriteCmd(LCD_FUNCTIONSET & LCD_FSET4BIT & FSETLINE1); //Una linea
PCF_WriteCmd(LCD_HOME); //Iniciliza el cursor

  • PCF_WriteMsg(*p): Este procedimiento sirve mostrar un mensaje en la pantalla LCD, se entiende que el mensaje iniciara en la posición actual que tiene el cursor. 
  • PCF_WriteChar(val): El procedimiento muestra en la pantalla LCD, el carácter val, se debe considerar la posición que tiene el cursor antes de llamar a este procedimiento.
  • PCF_GotoXY(x,y): El procedimiento permite posicionar el cursor en la pantalla, siendo x,y la combinación fila, columna de la pantalla.
  • PCFSetLED(): Permite encender la luz de fondo de la pantalla.
  • PCFClearLED(): Permite apagar la luz de fondo de la pantalla
Paso 4. Prueba y Simulación.
Ahora escribiremos un pequeño programa para poner en practica y demostrar el uso de una pantalla LCD donde utilizaremos los procedimientos previamente descritos, el programa se codifica considerando que la frecuencia del oscilador interno del PIC es de 8MHz.

El siguiente código es parte del programa que muestra un mensaje inicial en la primera linea y el valor de un contador de segundos en la segunda linea, adicionalmente se tiene un LED conectado al pin RE2 con el fin de generar un destello cada segundo, el destello es indicador de que el programa esta corriendo de manera regular. Aclarar que el código que se muestra solo corresponde con la funcionalidad básica del programa, por lo tanto te recomiendo que descargues el proyecto MPLABx y revises los archivos donde se encuentra el código completo.

#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#define LEDpin PORTEbits.RE2
volatile uint8_t tick1ms = 0;
uint16_t cntms = 0;
#include "i2c.h"
#include "pcflcd.h"
char msg[8];
//Char array

void main(void)
{
    setupMCU();
//Inicializa el Microcontrolador
    PCFSetupLCD();
//Inicia el LCD
    PCFSetLED();  
//Enciende la luz de fondo
    PCFGotoXY(0,2);
//Coloca el cursor en la posición 2 de la fila 0
    PCFWriteMsg("** U.E.B **");
//Muestra el mensaje
    PCFWriteCMD(LCD_DISPLAY & LCD_DBLINKOFF);
//Muestra el cursor
    while(1)
    {
        if(tick1ms)
//Validacion en cada ms
        {
            tick1ms = 0;
            taskLED();
//Ajecuta la tarea para destellar el LED
            taskAPP();
//Muestra el contador de segundos
        }
    }
}

void taskAPP(void)
{
    static uint16_t cnt = 0;
    static uint8_t seg = 0;
    if(cnt++ > 999)
//Se valida cada segundo.
    {
        cnt = 0;
        seg = seg + 1;
//Incrementa el contador de segundos
        if(seg > 59) seg = 0;
//Reinicia el contador de segundos
        PCFGotoXY(1,0);
//Coloca el cursor en la posición 0 de la fila 2
        sprintf(msg, "SEG:%02u", seg);
//Cadena personalizada
        PCFWriteMsg(msg);
//Muestra la cadena con valores del segundo   
    }


Fig9. Montaje del circuito PIC16F

Paso 5. Conclusiones y Recomendaciones.
Luego de hacer la demostración del programa podemos concluir que podemos implementar fácilmente este modulo I2C para ahorrarnos entre 4 y 6 lineas o pines del PIC. Si bien la librería solo contiene procedimientos básicos para mostrar mensajes, con un mayor conocimiento de las instrucciones del controlador LCD es posible realizar modificaciones que permitan efectuar operaciones menos frecuentes como ser desplazamientos y generación de caracteres personalizados.
 
Este es el enlace para descargar el proyecto MPLABX  <PCFLCDP16F>
También de dejo vídeo donde explico como abrir el proyecto MPLABX y compilar con otro PIC diferente al utilizado. 

Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo visto pueda ser útil en tu formación y el proyecto que desarrollas.
Atte. Pablo Zárate Arancibia
email: pablinza@me.com / pablinzte@gmail.com, @pablinzar
Santa Cruz de la Sierra - Bolivia