Forum: Mikrocontroller und Digitale Elektronik DHT22 liefert eigenartige Werte


von Paul (Gast)


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

von Nico (nico123)


Lesenswert?

Das ist auch nicht das komplette Programm! So können wir dir nicht 
helfen!
Wie ist der Sensor angeschlossen?

von Paul (Gast)


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
}

von Paul (Gast)


Lesenswert?

Achso, Am Sensor ist noch ein 10k-pullup am Datenpin und ein 100nF an 
Vcc zu GND

von Paul (Gast)


Lesenswert?

Ich hatte mich ja teilweise an folgendem Code orientiert:

https://github.com/adafruit/DHT-sensor-library/blob/master/DHT.cpp

Leider mit wenig Erfolg. Mich wundert am meisten, dass data[2], also das 
Temperaturbyte meistens leer ist, da scheint wohl noch etwas mit dem 
Empfangen/Auswerten des Bitstreams nicht zu stimmen, ich kann nur leider 
keinen Fehler finden...

von Thomas K. (muetze1)


Angehängte Dateien:

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.

von Paul (Gast)


Lesenswert?

So, ich habe deine Hinweise mal umgesetzt und es funktioniert immer noch 
nicht. Deinen Code habe ich auch schon probiert, gleiches Ergebnis. Ich 
weiß langsam nicht mehr weiter... :(

von Paul (Gast)


Angehängte Dateien:

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

von Paul (Gast)


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 :)

von Sebastian (Gast)


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.

von Sebastian (Gast)


Lesenswert?

Oh, Du hat es schon...dann gut.

von Thomas R. (gastrodus)


Lesenswert?

Hallo zusammen

Hat denn schon jemand Code in Bascom für den DHT11?

Dankende Grüsse
Thomas

Beitrag #4807925 wurde von einem Moderator gelöscht.
von Thomas K. (muetze1)


Lesenswert?

Hi,

was mir so auffällt dazu:

- es werden niemals .c Dateien includiert
- die Funktionen dht11() oder dht11_output() gibt es nicht in der 
dht11.h
- stimmen die Deklarationen in der dht11.h bezüglich der genutzten Pins 
und Ports?

Grüße,
Muetze1

Beitrag #4808119 wurde von einem Moderator gelöscht.
von Thomas K. (muetze1)


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.
von Thomas K. (muetze1)


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.
von Thomas K. (muetze1)


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

: Bearbeitet durch User
von Thomas K. (muetze1)


Angehängte Dateien:

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.