Autor Tema: sensor dht11 pic18f4550  (Leído 2164 veces)

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

Desconectado ulisescesaton

  • PIC10
  • *
  • Mensajes: 7
sensor dht11 pic18f4550
« en: 10 de Octubre de 2019, 00:55:43 »
hola buenas noches soy nuevo en esto de los micro controladores y estoy intentando programar un sensor dht11 y una lcd con un pic 18f4550 y tengo varias dudas con respecto a este programa que encontre
especificamente en esta parte del codigo :
------------------------------------------------------------------------------------------------------------------
RH = (RH << 8  ) | RH_Byte2;
Temp = T_Byte1;
Temp = (Temp << 8  ) | T_Byte2;

if( RH >= 1000)
Humidity[0] = '1';
else
Humidity[0] = ' ';

if(Temp > 0x8000) {
Temperature[0] = '-';
Temp = Temp & 0x7FFF;
}
else
Temperature[0] = ' ';

Temperature[1] = (Temp / 100) % 10 + 48;
Temperature[2] = (Temp / 10) % 10 + 48;
Temperature[4] = Temp % 10 + 48;
Humidity[1] = (RH / 100) % 10 + 48;
Humidity[2] = (RH / 10) % 10 + 48;
Humidity[4] = RH % 10 + 48;

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
mi duda es porque (Temp / 100) % 10 + 48; porque se hace esta operacion, en otros codigos hacen algo similar pero no entiendo que es
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)) porque esta condicion agrega esto "& 0xFF" tengo entendido que es suficiente con determinar la suma de los 4 bytes =checksum pero porque agrega un operador de direccion y un 255 en hexadecimal
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
no entiendo bien esta parte podrían explicarme que hace o comentar linea por linea su funcionamiento:

RH = (RH << 8  ) | RH_Byte2;
Temp = T_Byte1;
Temp = (Temp << 8   ) | T_Byte2;

if( RH >= 1000)
Humidity[0] = '1';
else
Humidity[0] = ' ';

if(Temp > 0x8000) {
Temperature[0] = '-';
Temp = Temp & 0x7FFF;
}
else
Temperature[0] = ' ';
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#define SSD1306_RST PIN_B2



// DHT22 sensor connection
#define DHT22_PIN PIN_B3

#include <18F4550.h>
#device PASS_STRINGS = IN_RAM
#fuses NOMCLR, INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(clock = 8MHz)
#use fast_io(B)
#use I2C(MASTER, I2C1, FAST = 400000, stream = SSD1306_STREAM) // Initialize I2C

// Include SSD1306 OLED driver source code
#include <SSD1306OLED.c>

char Temperature[] = " 00.0 C";
char Humidity[] = " 00.0 %";
int8 T_Byte1, T_Byte2, RH_Byte1, RH_Byte2, CheckSum;
int16 Temp, RH;


// Send start signal to the sensor
void Start_Signal(void) {
output_drive(DHT22_PIN); // Configure connection pin as output
output_low(DHT22_PIN); // Connection pin output low
delay_ms(25); // Wait 25 ms
output_high(DHT22_PIN); // Connection pin output high
delay_us(30); // Wait 30 us
output_float(DHT22_PIN); // Configure connection pin as input
}

// Check sensor response
int1 Check_Response(void) {
set_timer1(0); // Set Timer1 value to 0
while(!input(DHT22_PIN) && get_timer1() < 100); // Wait until DHT22_PIN becomes high (cheking of 80µs low time response)
if(get_timer1() >= 100) // If response time >= 100µS ==> Response error
return 0; // Return 0 (Device has a problem with response)
else {
set_timer1(0); // Set Timer1 value to 0
while(input(DHT22_PIN) && get_timer1() < 100); // Wait until DHT22_PIN becomes low (cheking of 80µs high time response)
if(get_timer1() >= 100) // If response time >= 100µS ==> Response error
return 0; // Return 0 (Device has a problem with response)
else
return 1; // Return 1 (response OK)
}
}

// Data read function
int1 Read_Data(int8 *dht_data) {
int8 j;
*dht_data = 0;
for(j = 0; j < 8; j++){
set_timer1(0); // Reset Timer1
while(!input(DHT22_PIN)) // Wait until DHT22_PIN becomes high
if(get_timer1() >= 100) { // If low time >= 100µs ==> Time out error (Normally it takes 50µs)
return 1;
}
set_timer1(0); // Reset Timer1
while(input(DHT22_PIN)) // Wait until DHT22_PIN becomes low
if(get_timer1() > 100) { // If high time > 100µs ==> Time out error (Normally it takes 26-28µs for 0 and 70µs for 1)
return 1; // Return 1 (timeout error)
}
if(get_timer1() > 50) // If high time > 50µS ==> Sensor sent 1
bit_set(*dht_data, (7 - j)); // Set bit (7 - j)
}

return 0; // Return 0 (data read OK)
}

// main function
void main(void) {

setup_oscillator(OSC_8MHZ); // Set internal oscillator to 8MHz
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2); // Start Timer1 with internal clock source + 2 prescaler

delay_ms(1000);

// Initialize the SSD1306 OLED with an I2C addr = 0x7A (default address)
SSD1306_Begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);

// Clear the buffer
SSD1306_ClearDisplay();
SSD1306_Display();

SSD1306_DrawFastHLine(0, 31, SSD1306_LCDWIDTH); // Draw a horizontal line
SSD1306_DrawText(10, 0, "DHT22 TEMPERATURE:");
SSD1306_DrawText(19, 37, "DHT22 HUMIDITY:");
SSD1306_Display();

while(TRUE) {

Start_Signal(); // Send a start signal to the sensor

if(Check_Response()) { // Check if there is a response from sensor (If OK start reding humidity and temperature data)

// Response OK ==> read (and save) data from the DHT22 sensor and check time out errors
Read_Data(&RH_Byte1); // Read humidity 1st byte and store its value in the variable RH_Byte1
Read_Data(&RH_Byte2); // Read humidity 2nd byte and store its value in the variable RH_Byte2
Read_Data(&T_Byte1); // Read temperature 1st byte and store its value in the variable T_Byte1
Read_Data(&T_Byte2); // Read temperature 2nd byte and store its value in the variable T_Byte2
Read_Data(&CheckSum); // Read checksum and store its value in the variable CheckSum

// Test if all data were sent correctly
if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)) {

RH = RH_Byte1;
RH = (RH << 8  ) | RH_Byte2;
Temp = T_Byte1;
Temp = (Temp << 8  ) | T_Byte2;

if( RH >= 1000)
Humidity[0] = '1';
else
Humidity[0] = ' ';

if(Temp > 0x8000) {
Temperature[0] = '-';
Temp = Temp & 0x7FFF;
}
else
Temperature[0] = ' ';

Temperature[1] = (Temp / 100) % 10 + 48;
Temperature[2] = (Temp / 10) % 10 + 48;
Temperature[4] = Temp % 10 + 48;
Humidity[1] = (RH / 100) % 10 + 48;
Humidity[2] = (RH / 10) % 10 + 48;
Humidity[4] = RH % 10 + 48;

}

// Checksum error
else {
Temperature[0] = Temperature[1] = Temperature[2] = Temperature[4] = 'E';
Humidity[0] = Humidity[1] = Humidity[2] = Humidity[4] = 'E';
}

}

// Sensor response error (connection error)
else {
Temperature[0] = Temperature[1] = Temperature[2] = Temperature[4] = 'E';
Humidity[0] = Humidity[1] = Humidity[2] = Humidity[4] = 'E';
}

// Display data on the display
SSD1306_DrawText(24, 12, temperature, 2); // Print temperature with text size = 2
SSD1306_DrawCircle(88, 13, 2); // Put degree symbol ( ° )
SSD1306_DrawText(24, 49, humidity, 2); // Print humidity with text size = 2
SSD1306_Display();

delay_ms(1000); // Wait 1 second between readings

}

}
// End of code.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:sensor dht11 pic18f4550
« Respuesta #1 en: 10 de Octubre de 2019, 08:16:19 »
Citar
mi duda es porque (Temp / 100) % 10 + 48; porque se hace esta operacion, en otros codigos hacen algo similar pero no entiendo que es

En realidad es esto:

Código: C
  1. Temperature[1] = (Temp / 100) % 10 + 48;
  2. Temperature[2] = (Temp / 10) % 10 + 48;
  3. Temperature[4] = Temp % 10 + 48;

Lo que estas buscando, es obtener los digitos de la temperatura en ASCII, por ejemplo si tuviera 178ºC en Temp, el prrimer resultado, seria 178 / 100 = 1 (se pierde los decimales) Luego 1 % 10 = 1 + '0' (este es tu 48)
http://www.asciitable.com/
Por lo tanto en Temperature[1] estas obteniendo un caracter ASCII '1'
Si sigo con el ejemplo el segundo tendrias lo siguiente:
178/10 = 17 -> 17 %10 = 7 -> 7 + '0' = '7'

El % es el modulo, es decir el resto de la division... 17/10 es cociente 1 con resto 7.

Citar
if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)) porque esta condicion agrega esto "& 0xFF" tengo entendido que es suficiente con determinar la suma de los 4 bytes =checksum pero porque agrega un operador de direccion y un 255 en hexadecimal

Porque sumar 4 bytes el resultado mas grande que podrias tener ocuparia 2 bytes.. Pero el checksum es unicamente el byte de menos peso. Al hacerle una AND con 0xFF hace que unicamente quede con valor (y como estaban) el byte mas bajo. Todo lo demas queda en 0. Por lo tanto siempre vas a comparar 1 byte con un byte...
Acstumbrate al uso del AND como para estos casos o para eliminar/dejar pasar algun bit de dato.


Citar
no entiendo bien esta parte podrían explicarme que hace o comentar linea por linea su funcionamiento:

Primero necesitas entender como llega la informacion del dht11 al pic.. Lo voy a sacar del datasheet:

8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit check sum

Es decir vienen de paquetes de 8 bits, pero aca arma en un solo registro todo el dato. es decir va a juntar las dos partes de la humedad y de la temperatura en un solo registro para cada uno
Código: C
  1. RH = (RH << 8  ) | RH_Byte2;  // Junta las partes en el registro RH
  2. Temp = T_Byte1;     // Aca llega la parte integral y al asignarlo ocupa el byte de menos peso.. Voy a denominar i lo entero y d lo decimal, el registro queda asi 00ii
  3. Temp = (Temp << 8   ) | T_Byte2;  // Aca traslada lo entero a la parte alta, rotando 8 veces ii00, y luego pone lo decimal abajo quedando iidd
  4.  
  5. if( RH >= 1000)  // Revisa si la humedad es mayor cierto valor
  6. Humidity[0] = '1';
  7. else
  8. Humidity[0] = ' ';
  9.  
  10. if(Temp > 0x8000) {  // La temperatura es otro tema. El bit de mayor peso indica si la temperatura es positiva o negativa. Por lo tanto si esta en 1 significa que es mayor a 0x800
  11. Temperature[0] = '-';  // Si es negativa, le pone el '-' a mostrar
  12. Temp = Temp & 0x7FFF;
  13. }
  14. else
  15. Temperature[0] = ' ';

Espero que eso te saque de las dudas.
El unico problema que no te voy a poder solucionar es como traducir la temperatura y humedad al los valores correctos... Me parece absurdo la forma de llemarles "entero" y "decimal" cuanto es todo entero segun algunos datasheets, por que encima no existe algun datasheet como debe ser.
« Última modificación: 10 de Octubre de 2019, 08:29:44 por KILLERJC »

Desconectado ulisescesaton

  • PIC10
  • *
  • Mensajes: 7
Re:sensor dht11 pic18f4550
« Respuesta #2 en: 11 de Octubre de 2019, 00:46:59 »
Código: C
  1. [  
  2. #include <18f4550.h>                      //Libreria del PIC a usar
  3. #Fuses HSPLL, NOWDT, NOPROTECT, NOLVP, NODEBUG, PLL2, CPUDIV1, VREGEN      //Palabra de configuración
  4. #use delay (clock=48M)                    //Frecuencia del reloj del pic              //Esta función afecta directamente al registro para configurar como entrada o salida
  5. #include <MLCD.c>
  6. #DEFINE DHT11 PIN_A2
  7.  
  8.  
  9. VOID START_SIGNAL(VOID) {
  10. OUTPUT_DRIVE(DHT11); // Configure connection pin as output
  11. OUTPUT_LOW(DHT11); // Connection pin output low
  12. DELAY_MS(25); // Wait 25 ms
  13. OUTPUT_HIGH(DHT11); // Connection pin output high
  14. DELAY_US(30); // Wait 30 us
  15. OUTPUT_FLOAT(DHT11); // Configure connection pin as input
  16. }
  17.  
  18. INT1 CHECK_RESPONSE(VOID) {
  19.  
  20. WHILE(INPUT(DHT11)){
  21.  
  22. RETURN 0;
  23. }
  24. DELAY_US(80);
  25. WHILE(!INPUT(DHT11)){
  26. RETURN 0;
  27. }
  28. RETURN 1;
  29.  
  30. }
  31. INT1 READ_DATA(FLOAT*TEMPERATURA11,FLOAT*HUMEDAD11){
  32. INT8 I,X=0;
  33. INT8 DATA[5];
  34.  
  35. OUTPUT_DRIVE(DHT11);
  36. FOR (X=0; X<5; X++){
  37. INT8 VALUE=0;
  38. FOR(I=0;I<8;I++){
  39. VALUE<<=1;
  40. WHILE(!INPUT(DHT11));
  41. DELAY_US(38);
  42. IF(INPUT(DHT11))
  43. {
  44. VALUE |=1;
  45. }
  46. WHILE(INPUT(DHT11));
  47. }
  48. DATA[X]=VALUE;
  49. }
  50. IF((int8)(DATA[0] + DATA[1] + DATA[2] +DATA[3])==DATA[4])
  51. {
  52. INT16 RAWHUMEDAD=DATA[0]<<8 | DATA[1];
  53. INT16 RAWTEMPERATURA=DATA[2]<<8 | DATA[3];
  54. IF(RAWTEMPERATURA & 0X8000){
  55. *TEMPERATURA11=(FLOAT)((RAWTEMPERATURA & 0x7fff)/10.0)*-1.0;
  56. }
  57. ELSE
  58. {
  59. *TEMPERATURA11 =(FLOAT)(RAWTEMPERATURA)/10.0;
  60. }
  61. *HUMEDAD11=((FLOAT)(RAWHUMEDAD)/10);
  62. RETURN 1 ;
  63. }
  64. RETURN 0;
  65. }
  66.  
  67. VOID MAIN(VOID){
  68. FLOAT TEMPERATURA;
  69. FLOAT HUMEDAD;
  70.  
  71. LCD_INIT();
  72. START_SIGNAL();
  73. CHECK_RESPONSE();
  74. WHILE (TRUE){
  75. INT8 ESTADO = READ_DATA(&TEMPERATURA,&HUMEDAD);
  76. IF(ESTADO==1) {
  77. LCD_GOTOXY(1,1);
  78. printf(lcd_putc,"TEMP=%04.2f",TEMPERATURA);
  79. lcd_putc("                ");
  80. LCD_GOTOXY(1,2);
  81. printf(lcd_putc,"HUM=%04.2f",HUMEDAD);
  82. }
  83. ELSE{
  84. lcd_gotoxy(1,1);
  85.    lcd_putc("SENSOR NO CONECTADO");
  86. }
  87. DELAY_MS(20);
  88. }
  89. RETURN ;
  90. }
  91.  
  92. ]
  93. me sirvio  pero ahora me compilabien el programa y todo pero en la lcd me arroja 0.20 en la temperatura y 12.80 pero son valores erroneos podrias ayudarme no se que puede estar mal

Desconectado ulisescesaton

  • PIC10
  • *
  • Mensajes: 7
Re:sensor dht11 pic18f4550
« Respuesta #3 en: 11 de Octubre de 2019, 00:48:11 »
me sirvio  pero ahora me compilabien el programa y todo pero en la lcd me arroja 0.20 en la temperatura y 12.80 pero son valores erroneos podrias ayudarme no se que puede estar mal

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:sensor dht11 pic18f4550
« Respuesta #4 en: 11 de Octubre de 2019, 10:07:26 »
Esto pasa por solucionar problemas... Siempre vas a tener de estos problemas por lo tanto las estrategias son relativamente sencillas. Es el Divide y conquistaras.. Asi que mis recomendaciones es que lo busques vos.¿Como? ahi si te puedo ayudar un poco.

Primero nos tenemos que asegurar que lo recibido en RH_Byte2, RH_Byte1, T_Byte1 y T_Byte2

Intenta mostrar esos valores en hexadecimal o decimal en el LCD con un printf..
Puede ocurrir dos cosas...
Que los valores esten bien ... Entonces el problema esta en la conversion de esos valores al valor a mostrar en el LCD
Que los valores esten mal.. Esto puede significar un problema en el driver del DHT11 o un problema en el DHT11.

El mayor inconveniente es si esta mal... Porque una de las formas que vas a poder ver si esta bien o mal es con un analizador logico o un osciloscopio digital, para ver si corresponde lo enviado por el DHT11 con lo recibido. Nuevamente tenes 2 opciones
Que los valores coincidan ... Y el problema esta en el DHT11 que esta enviando cualquier cosa
Que los valores NO coincidan.. Y es que el driver esta recibiendo mal los datos.. Es decir mal programado.


Empeza a ver donde  tenes el error, como digo es una habilidad que se debe conseguir y aprender.


Desconectado kidpic

  • PIC16
  • ***
  • Mensajes: 231
Re:sensor dht11 pic18f4550
« Respuesta #5 en: 07 de Marzo de 2020, 23:27:08 »
Hola, estoy trabajando con estas líneas
Temperature[1] = (Temp / 100) % 10 + 48;
Temperature[2] = (Temp / 10) % 10 + 48;
Temperature[4] = Temp % 10 + 48;
 Y todavía no me queda claro como es la division por 100 y por 10 y para que le suma el 48.

Donde puedo leer acerca de esta nomenclatura...Temperature[1] a que se debe el 1,2,4 dentro de los corchetes??
Gracias
Si quieres trascender..., enseña humildemente  lo que sabes.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:sensor dht11 pic18f4550
« Respuesta #6 en: 08 de Marzo de 2020, 08:54:21 »
Hola empecemos por lo basico:

Temperature es un array, por lo que estamos accediendo a cada uno de los componentes del array. No se ve donde lo define pero ya te va a quedar claro que es un string, o un array de char como lo quieras ver.

Respecto a las divisiones, la idea es separar las centenas de las decenas y así en adelante....

Supongamos que Temp posee el numero 145.
La primer instruccion:
(Temp / 100) % 10 + 48;

Consta de lo siguiente..
- Una división por 100, eso hace que quede 1
- Un modulo 10, que significa el resto de una división por 10, en este caso sigue siendo 1
- Una conversión a ASCII, ya que el 48 decimal es el '0'. Entonces queda '1'

En las siguientes instrucciones, para separar las decenas y unidades queda asi:
- Una division por 10, eso hace que quede 14
- Un modulo 10, que significa el resto de una división por 10, en este caso es 4
- Una conversion a ASCII, quedando '4'

- Un modulo 10, en este caso final es la unidad 5
- Una conversion a ASCII, quedando '5'


La pregunta del porque son 1,2 y 4, es porque seguramente esta persona en el 3 piensa poner un punto, entonces el string quedaria "12.5"

Desconectado kidpic

  • PIC16
  • ***
  • Mensajes: 231
Re:sensor dht11 pic18f4550
« Respuesta #7 en: 08 de Marzo de 2020, 11:20:25 »
Muchas gracias!!!. Entendido!!!
Si quieres trascender..., enseña humildemente  lo que sabes.