DHT22 liefert eigenartige Werte

Gast #2566032
Lesenswert?

Hallo,

gestern kam endlich der DHT22 Feuchtigkeits-/Temperatursensor aus China 
an. Nun sitze ich schon den ganzen Tag daran, das Teil zum Laufen zu 
kriegen. Es kommen zwar Werte an und ab und zu stimmt auch die 
Checksumme dazu, aber die Werte können nicht stimmen. Die Daten frage 
ich folgendermaßen ab:
1
#include "dht.h"
2
#include "uart.h"
3
#include <util/delay.h>
4
#include <stdlib.h>
5

6
#define TICKS  80
7

8
void dht_reset()
9
{
10
  INPUT_MODE();
11
  HIGH();
12
}
13

14
void dht_read()
15
{
16
  char ticks[TICKS],buf[100],checksum=0;
17
  uint8_t i=0,j=7,index=0;
18
  uint16_t lastState=PIN_STAT();
19

20
  dht_reset();
21

22
  HIGH();
23
  _delay_ms(250);
24

25
  data[0]=data[1]=data[2]=data[3]=data[4]=0;
26

27
  OUTPUT_MODE();
28
  LOW();
29
  _delay_ms(20);
30
  HIGH();
31
  _delay_us(40);
32
  INPUT_MODE();
33

34
  /*Sensor output starts*/
35
  lastState=1;
36
  for(i=0;i<TICKS;i++)      //40 bits
37
  {
38
    ticks[i]=0;
39
    //_delay_us(40);
40
    while(PIN_STAT()==lastState)    //wait, until state changes
41
    {
42
      ticks[i]++;      //count ticks
43
      _delay_us(1);
44
      if(ticks[i]>=255)
45
        break;
46
    }
47
    lastState=PIN_STAT();
48
  }
49

50
  /*Sensor output ends*/
51

52
  dht_reset();
53

54
  for(i=0;i<TICKS;i++)
55
  {
56

57
    if(i>0 && i%2==0)          
58
    {
59
      //uart_puts(itoa(ticks[i],buf,10));
60

61
      if(ticks[i]>=20)                        //1
62
      {
63
        data[index]|=(1<<j);            //save
64
        uart_puts("1");
65
      }
66
      else
67
      {
68
        uart_puts("0");
69
      }
70

71
      if(j==0)
72
      {
73
        uart_puts(" | ");
74
        j=7;
75
        index++;                     //next byte
76
      }else
77
      j--;
78

79
    }
80

81
  }
82

83
  uart_puts("\r\n");
84

85
  for(i=0;i<4;i++)
86
  {
87
    uart_puts("\r\n");
88
    uart_puts(itoa(data[i],buf,10));       //print 
89
    checksum+=data[i];
90
  }
91
  uart_puts("\r\n");
92

93
  uint8_t temp=0;
94
  temp = data[2] & 0x7F;
95

96
  uart_puts(itoa(temp,buf,10));
97
  uart_puts("\r\n");
98

99

100
  if((checksum&0xff)==data[4])
101
    uart_puts("DATA_OK");
102
  else
103
    uart_puts("DATA_NOT_OK");
104

105
  uart_puts("\r\n");
106

107
}

Folgende Daten kommen an:
1
10000001 | 00110000 | 00000000 | 01101001 | 0001101
2

3

4

5
129
6

7
48
8

9
0
10

11
105
12

13
0
14
DATA_OK
15

16

17
10000001 | 00110000 | 00000000 | 01101001 | 1001101
18

19

20

21
129
22

23
48
24

25
0
26

27
105
28

29
0
30

31
DATA_NOT_OK
32

33
10000001 | 00110000 | 10000000 | 01101001 | 1001101
34

35

36

37
129
38

39
48
40

41
128
42

43
105
44

45
0
46

47
DATA_OK

Vielleicht findet ihr den Fehler ;)

Schöne Grüße
Paul
Gast #2566160
Lesenswert?

Der Sensor ist an PD4 angeschlossen.

dht.h:
1
#include <avr/io.h>
2

3
#ifndef DHT_H_
4
#define DHT_H_
5

6
#define PORT PORTD
7
#define DDR DDRD
8
#define PIN PIND
9
#define DQ PD4
10
/* Utils */
11
#define INPUT_MODE() DDR&=~(1<<DQ)
12
#define OUTPUT_MODE() DDR|=(1<<DQ)
13
#define LOW() PORT&=~(1<<DQ)
14
#define HIGH() PORT|=(1<<DQ)
15
#define PIN_STAT()  (PIN&(1<<DQ))
16

17
char data[5];
18

19
void dht_reset();
20
void dht_read();
21

22
#endif /* DHT_H_ */

main.c:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "dht.h"
4
#include "uart.h"
5

6
int main()
7
{
8

9
  uint8_t i=0;
10

11
  uart_init(UART_BAUD_SELECT(9600, F_CPU));
12
  sei();
13

14
  dht_read();
15
  
16
  while(1);
17
  return 0;
18
}
#2566614
Lesenswert?

Ich habe nur einen DHT11 an meinem AVR, aber das sollte keinen 
Unterschied machen. Bei mir sind halt immer die zweiten Bytes 0x00 
während bei dir dort die Nachkommastellen zu finden sein sollten. Schau 
doch sonst mal probeweise, ob der Code klappt.

Hinweis 1: im initdht() müsstest du noch das Einschalten des Pullups 
auskommentieren.

Hinweis 2: Der Sensor darf nach dem Einschalten ein paar (Milli)Sekunden 
lang nicht angesprochen werden, ansonsten bekommt man ihn leicht in 
einen undefinierten Zustand. Siehe auch das verlinkte PDF bei 
adafruit.com. Mach also mal ein _delay_ms(500) o.ä. bei dir in die 
main() vor dem read.
Angehängte Dateien:
Gast #2568381
Lesenswert?

Ich habe noch einiges ausprobiert und festgestellt, dass wenn der 
Bitstream vom Sensor um 3 Bit nach links verschoben wird, zumindest die 
checksumme so gut wie immer stimmt. Außerdem ändern sich die Werte 
nicht. Testweise habe ich den Sensor mal angehaucht und siehe da, in den 
ersten zwei Bytes tut sich was :) Die Werte werden größer und nach 
einiger Zeit werden sie auch wieder kleiner, also scheint die 
Feuchtigkeitsmessung zumindest zu funktionieren, wenn auch keine 
korrekten Werte kommen. Leider bleibt die Temperaturmessung unverändert 
bei 0 :( Im Anhang hab ich mal ein Werteprotokoll hochgeladen. Die 
empfangenen Bytes sind zeilenweise binär dargestellt.

Gruß
Paul
Angehängte Dateien:
Gast #2568413
Lesenswert?

Ah, ok, ich glaub, ich habs verstanden ;) Die zwei Bytes müssen 
konkateniert und dann durch 10 geteilt werden, um den eigentlichen Wert 
herauszubekommen. Ich dachte im ersten Byte steht der Vorkommawert und 
im zweiten der Nachkommawert. Aber jetzt ist ja alles klar :)
Gast #2568417
Lesenswert?

Ja nachdem, wann Du anfängst zu messen, werden 42 Signale / Impulse 
empfangen, davon sind 40 Nutzsignale. Die langen Impulse sind 1 und die 
kurzen 0. Wartet man auf das erste "High" nach der Anfrage (siehe 
Datenblatt), muss man die ersten beiden Signale Ignorieren. Ich habe 
leider nur einen BASCOM Code. Darin messe ich die Zeiten der Impulse und 
generiere dann daraus die Bits.

Wichtig ist das umschalten des Pins. In Bascom sieht das so aus 
(pinc.0):
1
 Config Pinc.0 = Output : Portc.0 = 0                     ' request data
2
 Waitms 20                                                ' wait 20 ms
3
 Config Pinc.0 = Input

In C sollte es ähnlich aussehen. Aber Du empfängst ja Daten, daran 
sollte es nicht liegen.

Schau doch nochmal, ob Du wirklich an der richtigen Stelle ansetzt. Die 
ersten beiden 16 Bits kann man auch als Word für H und T nehmen. Das 
restliche Byte ist dann die Prüfsumme.
Beitrag #4807925 wurde von einem Moderator gelöscht.
Beitrag #4808119 wurde von einem Moderator gelöscht.
#4808194
Lesenswert?

Hi,

also die Typen der Variablen stimmen nicht. Wie in der dht11.h zu sehen 
sollte es int16_t sein und keine unsigned Variante. Die gelieferten 
Werte sind wimre um Faktor 10 verschoben. Die Nachkommastelle ist dann 
die unterste Stelle.

Aber mal eine andere Frage: Du fragst ständig ob du so die Werte mit 
Vor- und Nachkommastelle rausbekommst. Gegenfrage: was bekommst du denn 
raus? Was ist die Differenz zwischen Erwartung und Resultat?

Wenn man sich die Dokumentation der Funktion itoa() anschaut, dann 
sollte auch klar sein warum keine Nachkommastelle mit einem separatem 
Dezimalpunkt rauskommt. Aber ich denke mit der Info aus dem ersten 
Abschnitt, sollte man das gelöst bekommen.

Grüße,
Muetze1
Beitrag #4808328 wurde von einem Moderator gelöscht.
#4808366
Lesenswert?

> Thomas K. schrieb:
>> Aber mal eine andere Frage: Du fragst ständig ob du so die Werte mit
>> Vor- und Nachkommastelle rausbekommst. Gegenfrage: was bekommst du denn
>> raus? Was ist die Differenz zwischen Erwartung und Resultat?
>
> Erwartung:
> Temperatur: 00011000 01000111 // so in etwas
> Luftfeuchte: 00110101 01100001

Wieso binär? Dann wäre die Funktion itoa() falsch. Wie soll es denn nun 
ausgegeben werden?

Was sagt die Dokumentation von itoa() über das Ergebnis der Funktion 
aus?
Was muss man noch beachten bezüglich dem Faktor 10 für die 
Nachkommastellen? Da müsste der Code auch noch angepasst werden, wenn es 
dezimal ausgegeben werden sollte. Um das mit dem Faktor 10 mal als 
Beispiel zu schreiben:

Rückgabewert: 1234
bedeutet: 123,4

Ansonsten sehe ich keine Notwendigkeit für die volatile Deklaration der 
beiden Variablen.

Grüße,
Muetze1
Beitrag #4808467 wurde von einem Moderator gelöscht.
#4808476
Lesenswert?

Nach den ganzen Beiträgen ein wichtiger und notwendiger Rat: Du musst 
Dir unbedingt die Grundlagen erarbeiten. Ansonsten wird das 
programmieren immer kompliziert und schwierig bleiben. So bleibt mir nur 
noch auf ein paar Dinge hinzuweisen:

- binär und dezimal sind nur Darstellung von Daten/Zahlen. Der Wert im 
Speicher ist davon komplett unabhängig. Somit werden die Daten nicht 
binär oder dezimal zurück gegeben.
-  Was ist mit der Nachkommastelle? Diese wird nun natürlich weggeworfen 
- aber ich dachte die wäre wichtig?
- die lcd_string() Routine nimmt nur einen Parameter und nicht zwei. Ein 
formatiertes String replacement musst Du somit selbst vorher machen.

Aber solche grundlegenden Sachen kann man auch jetzt schon testen: die 
IDE, Compiler etc. für den AVR bekommt man kostenlos. Und 
compileren/bauen kann man somit den ganzen Quellcode auch jetzt schon. 
Nur halt testen auf der Original-Hardware nicht. Aber solche 
syntaktischen Fehler würden dann schon jetzt auffallen und korrigierbar.

Grüße und viel Erfolg morgen.

Grüße,
Muetze1
#4924491
Lesenswert?

Hi!

Da ich gerade mal wieder eine Anfrage zu dem Code bekommen habe, stelle 
ich hier noch einmal meinen aktuellen Stand des Codes ein. Dieser ist 
ein wenig angepasst worden. Zum einen kann er nun DHT11 und DHT21/22 
einlesen (und erkennen) und zum anderen kann er zwei Sensoren am 
gleichen Port (aber unterschiedlichen Pins) einlesen. Gespeichert werden 
die Daten in der Struct und kann durch die Funktionen ausgelesen werden. 
Auch ein abziehen und späteres wieder anstecken oder Tausch der Sensoren 
macht der Code problemlos mit.

Bezüglich der Port Konfiguration wird in der Datei die hwconfig.h 
angezogen, welche die folgenden Definitionen enthält:

SENSOR_HUMIDITY_DDR
SENSOR_HUMIDITY_PORT
SENSOR_HUMIDITY_PIN
SENSOR_HUMIDITY1_SIG
SENSOR_HUMIDITY2_SIG

Wobei die Definitionen eindeutig sein sollten (DDR, PORT, PIN) und die 
SIG Definitionen sollten das Port Bit sein (z.B. PD2).

Die readDHT() liest immer nur einen Sensor ein (0 oder 1) und sollte 
auch nicht zu oft aufgerufen werden. Ich habe es bei mir alle halbe 
Sekunde bis Sekunde angestoßen.

Grüße,
Muetze1
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren