Autor Tema: DHT11 y XC8  (Leído 2815 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
DHT11 y XC8
« en: 14 de Septiembre de 2018, 12:04:43 »
Hola gente, tanto tiempo, de regreso por estos lados. Y con un proyecto nuevo.

Resulta que en mi aprendizaje del uso del XC8 me encuentro con un problema: Tratar de que un PIC pueda comunicarse con el sensor de humedad/temperatura DHT11, y si bien en .asm ya lo tendría resuelto, la idea es aprender el XC8.

Buscando por internet hay poco y muy difícil de entender, por lo que recurro a ustedes para ver si me pueden orientar hacia alguna página que sea entendible.

Desde ya cualquier aporte será bienvenido.

Un saludo.

Atte. CARLOS.

La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.

Desconectado george.manson.69

  • PIC10
  • *
  • Mensajes: 33
    • Microcontroladores en General
Re:DHT11 y XC8
« Respuesta #1 en: 14 de Septiembre de 2018, 14:07:40 »
https://drive.google.com/drive/folders/0B5PHuBzaImxfR1VNMTZZOUlzc1E?usp=sharing

Te comparto un mini tutorial...le falta actualizar pero es un avance

¡Saludos!

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:DHT11 y XC8
« Respuesta #2 en: 14 de Septiembre de 2018, 14:35:01 »
Viendo que lo hiciste en ASM, podriamos hacer una version rapida en XC8..

https://www.mouser.com/ds/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf (Pag 6)

Primero necesitamos enviar el pulso de start:

Código: C
  1. TRISBbits.RB0 = 0;    //Salida
  2.  PORTBbits.RB0 = 0;   // Y a cero
  3.  __delay_ms(20);       // minimo 18ms segun el pdf
  4.  TRISBbits.RB0 = 1;    // Entrada

De alli nos queda saber si responde el DHT11, al principio va a estar en alto por que pusimos como entrada el pin, y luego el DHT11 va a responder poniendo a 0 el pin de DATA

Código: C
  1. while(PORTBbits.RB0);   // Mientras este en 1 se quede encerrado
  2. while(!PORTBbits.RB0);   // Mientras este en 0 quedamos aca
  3. while(PORTBbits.RB0);

Ya aca sabemos que el DHT11 respondio, para hacer una cosa bien hecha deberiamos implementar un timeout arriba, pero por ahora vamos asi

De ahora en adelante comienzan a llegar los datos. Asi que necesitamos saber que dato es, asi que la unica forma de verlo es que luego del pulso bajo, viene uno alto de ancho variable. gracias a eso podemos determinar si es un 0 o un 1. Primero esperamos el flanco positivo:

Código: C
  1. while(!PORTBbits.RB0);  // Mientras este en bajo, quede atrapado aca.
  2. __delay_us(90);            // Superior a un "0" que es 50+28us y menor a un "1" que es 50 + 70us
  3. dato |= PORTBbits.RB0;  // Guardo el estado del bit

Y eso deberia repetirlo unas 40 veces para los bits y la paridad. una forma de hacerlo es usar un array (para no meternos con punteros).

Código: C
  1. char datos[5], i, j, checksum;
  2.  
  3. for(i = 0 ; i < sizeof datos; i++) {  // Los 5 bytes
  4.   datos[i] = 0;  // Limpio
  5.   for(j = 0; j < 8; j++) {
  6.     while(!PORTBbits.RB0);  // Mientras este en bajo, quede atrapado aca.
  7.     __delay_us(90);            // Superior a un "0" que es 50+28us y menor a un "1" que es 50 + 70us
  8.     datos[i] |= PORTBbits.RB0;  // Guardo el estado del bit
  9.     datos[i] <<= 1;                   // Roto un bit a la izquierda
  10.   }
  11. }



Ahora es necesario verificar el checksum:

Código: C
  1. checksum = 0;
  2. for ( i = 0; i< sizeof datos - 1; i++) checksum += datos[i];
  3. if ( checksum != datos[4])  return ERROR;     // Aca hubo un problema, no coincide el checksum

En fin... algo asi quedaria el total:

Código: C
  1. char datos[5], i, j, checksum;
  2.  
  3. char leer_DHT11(){
  4.  
  5.     TRISBbits.RB0 = 0;    //Salida
  6.     PORTBbits.RB0 = 0;   // Y a cero
  7.     __delay_ms(20);       // minimo 18ms segun el pdf
  8.     TRISBbits.RB0 = 1;    // Entrada
  9.  
  10.     while(PORTBbits.RB0);   // Mientras este en 1 se quede encerrado
  11.     while(!PORTBbits.RB0);   // Mientras este en 0 quedamos aca
  12.     while(PORTBbits.RB0);
  13.  
  14.     for(i = 0 ; i < sizeof datos; i++) {  // Los 5 bytes
  15.       datos[i] = 0;  // Limpio
  16.       for(j = 0; j < 8; j++) {
  17.         while(!PORTBbits.RB0);  // Mientras este en bajo, quede atrapado aca.
  18.         __delay_us(90);            // Superior a un "0" que es 50+28us y menor a un "1" que es 50 + 70us
  19.         datos[i] |= PORTBbits.RB0;  // Guardo el estado del bit
  20.         datos[i] <<= 1;                   // Roto un bit a la izquierda
  21.       }
  22.     }
  23.     checksum = 0;
  24.     for ( i = 0; i< sizeof datos - 1; i++) checksum += datos[i];
  25.     if ( checksum != datos[4])  return 1;     // Aca hubo un problema, no coincide el checksum
  26.     return 0;
  27. }

PD: Puede y seguramente existan errores, es lo que pude hacer en mis 30min de tiempo libre, espero que te sirva, y como ves puede mejorarse mucho mas.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5878
    • Picuino
Re:DHT11 y XC8
« Respuesta #3 en: 14 de Septiembre de 2018, 14:52:11 »
Hola Chaly, si subes el programa en ASM intento traducir todo a C para que veas que es más sencillo de lo que parece.


Desconectado stk500

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4917
Re:DHT11 y XC8
« Respuesta #4 en: 14 de Septiembre de 2018, 17:17:44 »
Hola chaly, y me alegro de verte otras vez por aqui,
aqui te dejo un link con el projectos acabado
http://www.electronicwings.com/pic/dht11-sensor-interfacing-with-pic18f4550

espero te sirva,

Un saludo

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
Re:DHT11 y XC8
« Respuesta #5 en: 16 de Septiembre de 2018, 03:00:25 »
Hola a todos y muchas gracias por la ayuda.

george.manson.69, sin dudas estaré estudiando un poco tos tutoriales.

Picuino, no tengo el .asm realizado, y no me costaría nada hacerlo, pero si lo llegara hacer, ya me daría pereza tratar de hacerlo con XC8  ;-) y así nunca aprendería.

stk500 gracias por el aporte, le estaré hechando una mirada.

KILLERJC, lo tuyo me a ayudado mucho para este proyecto y para aprender. De hecho, para la familia 16FXX estaría funcionando, sin el checksum, pero funcionando en fin.

El problema se presento cuando quise aplicarlo al micro 12F629 que es el que finalmente usaré. Y resulta que me sucede algo de lo más extraño (por lo menos para mi como total novato en C)

Resulta que no encuentro el problema del porque los while(GP1) y while(!GP1) dejaron de funcionar, el sea, en los 16F esperaba la presencia de los 1 o 0 respectivamente para salir del "encierro", pero en el 12F no me cumple esa función, de hecho, pasa de largo como si la función no existiera para luego prederse y quedar el micro completamente colgado.

A que se puede deber esto?

Desde ya muchas gracias a todos por sus ayudas.

Atte. CARLOS.

La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:DHT11 y XC8
« Respuesta #6 en: 16 de Septiembre de 2018, 08:57:23 »
Si funciona para uno y no para otro entonces se debe al hardware y tal ves la definicion de los pines en software. Y tampoco puede omitir los whiles deliberadamente el compilador ya que uno lo fuerza a revisar los pines (estan declarados como volatile), asi que las unicas que me quedan son:

Respecto al Hardware tenes que:

- Deshabilitar el CMCON, ( CMCON = 0x7)
- Deshabilitar el ANSEL, ( ANSEL = 0 )

Con respecto al software las denominaciones son:

Código: C
  1. TRISIObits.TRISIO0 = 0;
  2.     GPIObits.GP0 = 0;

es decir el nombre del registro + bits, y al poner el punto ya se te abren las opciones de la estructura. Es decir:

Código: C
  1. while(GPIObits.GP1)

PD, para que no tengas que cambiar todo a mano, usa un define por ahora:

Código: C
  1. #define PIN_DATA  GPIObits.GP1
  2. #define PIN_TRIS  TRISIObits.TRISIO1
  3.  
  4. char datos[5], i, j, checksum;
  5.  
  6. void leer_DHT11(){
  7.  
  8.     PIN_TRIS = 0;    //Salida
  9.     PIN_DATA = 0;   // Y a cero
  10.     __delay_ms(20);       // minimo 18ms segun el pdf
  11.     PIN_TRIS = 1;    // Entrada
  12.  
  13.     while(PIN_DATA);   // Mientras este en 1 se quede encerrado
  14.     while(!PIN_DATA);   // Mientras este en 0 quedamos aca
  15.     while(PIN_DATA);
  16.  
  17.     for(i = 0 ; i < sizeof datos; i++) {  // Los 5 bytes
  18.       datos[i] = 0;  // Limpio
  19.       for(j = 0; j < 8; j++) {
  20.         while(!PIN_DATA);  // Mientras este en bajo, quede atrapado aca.
  21.         __delay_us(90);            // Superior a un "0" que es 50+28us y menor a un "1" que es 50 + 70us
  22.         datos[i] |= PIN_DATA;  // Guardo el estado del bit
  23.         datos[i] <<= 1;                   // Roto un bit a la izquierda
  24.       }
  25.     }
  26. }

Asi si cambias de micro lo podes cambiar mas facil, (aunque podes usar el buscar y reemplazar)
« Última modificación: 16 de Septiembre de 2018, 08:59:42 por KILLERJC »

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
Re:DHT11 y XC8
« Respuesta #7 en: 16 de Septiembre de 2018, 20:28:29 »
Hola KILLERJC, una maravilla tu explicación, y ya lo tengo funcionando, el programa (intento de librería) a quedado de esta manera:

Código: C
  1. void DHT11_Leer(void){
  2.         TRIS_DHT = 0;                       // Pin GP1 como salida
  3.         DATA_DHT = 0;                       // Coloco la salida en bajo
  4.         __delay_ms (20);                    // Retardo de 20 mseg.
  5.         DATA_DHT = 1;                       // Pin en alto
  6.         TRIS_DHT = 1;                       // Pin GP1 como entrada
  7.     while(DATA_DHT);                    // Mientras este en 1 se quede encerrado
  8.     while(!DATA_DHT);                   // Mientras este en 0 quedamos aca
  9.     while(DATA_DHT);                    // Mientras este en 1 se quede encerrado
  10.     while(!DATA_DHT);                   // Mientras este en 0 quedamos aca
  11.    
  12.     __delay_us(18);
  13.     for(i = 0 ; i < sizeof datos; i++){                             // Los 5 bytes
  14.         datos[i] = 0;                                               // Limpio
  15.         for(j = 0; j < 8; j++){
  16.             datos[i] |= DATA_DHT;                                   // Guardo el estado del bit
  17.             datos[i] <<= 1;                                         // Roto un bit a la izquierda
  18.             if (DATA_DHT == 1){
  19.                 while(DATA_DHT);                                    // Mientras este en 1 se quede encerrado
  20.             }
  21.             while(!DATA_DHT);                                       // Mientras este en bajo, quede atrapado aca.
  22.             if(j < 7){
  23.                 __delay_us(22);
  24.             }
  25.         }
  26.         datos[i] >>= 1;                                             // Roto un bit a la derecha
  27.     }
  28. }

El error que tuve (bien de principiante) fue no haber configurado el

Las modificaciones que se ven en esta versión con respecto a la tuya es para ajustar tiempos y un par de detalles más para optimizar la lectura y hacer que lea correctamente.

El checksum no esta implementado, igualmente mi aplicación tampoco es que lo necesita tanto. Tampoco sabría que hacer con el "return ERROR". Supongo que irá como return de una función while. O me equivoco?

Lo que si me interesaría, es saber como implementar el borrado del registro del Watchdog, una ves este sea activado en la configuración.

Por otro lado, el compilador me muestra la siguiente advertencia:

my_dht11_12F.h:33: warning: (373) implicit signed to unsigned conversion

Referida a la siguiente linea del programa antes mostrado:

datos |= DATA_DHT;

Esta advertencia solo apareció una ves para el 12F, y varias para el 16F. Igual el programa en simulación funciona perfectamente ya que hasta ahora no lo implemente físicamente por no tener todavía el sensor. Es una advertencia a tener en cuenta o puede ser obviada?

Desde ya muchas gracias por toda la ayuda.

Atte. CARLOS.



La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:DHT11 y XC8
« Respuesta #8 en: 16 de Septiembre de 2018, 23:38:25 »
Citar
Lo que si me interesaría, es saber como implementar el borrado del registro del Watchdog, una ves este sea activado en la configuración.

XC8 provee un macro para eso, mientras tengas incluido el archivo xc.h usarias:

Código: C
  1. CLRWDT();

Citar
Por otro lado, el compilador me muestra la siguiente advertencia:

my_dht11_12F.h:33: warning: (373) implicit signed to unsigned conversion

Referida a la siguiente linea del programa antes mostrado:

datos |= DATA_DHT;

Puede ser, suele suceder con otras lineas tambien. Uno supone que al usar GPIObits.GP1 deberia devolver 1 o 0, pero tal ves en realidad devuelve un numero de 8 bits con signo con valor 1 o 0, Al momento de realizar el OR, lo transforma a un numero sin signo, ya que datos seguramente es sin signo. Se me ocurren las siguientes soluciones, Reemplazar por:

Código: C
  1. if (DATA_DHT) datos |= 1;

o

Código: C
  1. datos |= (unsigned char)DATA_DHT;

En uno no habria problema, y en el otro ahora es explicita la conversion, por lo tanto el warning no saldria mas.

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
Re:DHT11 y XC8
« Respuesta #9 en: 17 de Septiembre de 2018, 12:33:17 »
Hola KILLERJC, perfecto, tanto las dos opciones para desaparecer el mensaje de advertencia como los del CLRWDT funcionaron perfectamente.

Muchas gracias por la ayuda. Aparte de aprender mucho fue de mucha utilidad para poder terminar el proyecto.

Un saludo.

Atte. CARLOS.

La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.


 

anything