DHT11 Checksum error

Hallo,

mein DHT11 Modul kam heute an.
http://www.ebay.de/itm/331372092811

Ich erhalte leider sporadisch Fehlermeldungen:

DHT11, OK, 57.0, 22.0
DHT11, OK, 63.0, 25.0
DHT11, OK, 63.0, 34.0
DHT11, Checksum error, 4.0, 25.0
DHT11, Checksum error, 13.0, 25.0
DHT11, Checksum error, 12.0, 31.0
DHT11, Checksum error, 63.0, 63.0
DHT11, OK, 59.0, 22.0
DHT11, OK, 59.0, 22.0
DHT11, OK, 59.0, 22.0

Egal ob ich Baud 115200 oder 9600 verwende.
Die Verkabelung ist okay...
Modul defekt?

Danke und frohe Weihnachten :slight_smile:

JulHa:
Modul defekt?

Schaltungsaufbau defekt?
Abblockkondensator am Stromversorgungspin des Sensors vergessen?
(Edit: Abblockkondenstor scheint auf dem Breakout-Board vorhanden zu sein)
Kabel zum Sensor zu lang?

Bei der Schaltung die elektromagnetische Verträglichkeit nicht beachtet?

Also ich habe auch DHT11 Sensoren an einem ST Nucleo L152RE .

Und habe auch ab und zu einen CRC Error.
Mit dem Problem könnte ich leben, aber viel schlimmer ist das die Feuchtewerte nicht genau sind.
Wenn man Exemplare hat, und die quertauscht gibt es massive Unterschiede.
Die Temperaturausgabe ist halbwegs indendisch.

Mein Fazit ist das diese billig DHT11 Teile nicht mal halbwegs dazu geeignet sind genaue Luftfeuchtewerte zu erfassen.

Arduino Playground - HomePage demnach liegt die Genauigkeit bei rund 1%- das ist gar nicht mal übel.

Ihr habt übrigens bedacht, dass der Zeit brauch, um vernünftige Werte zu liefern, oder?
Zu schnell nacheinander messen funktioniert nicht.

Das Kabel ist ca. 20cm lang.
Habe nach jedem Auslesen Delays von 5 bis 15 Sekunden versucht.
Laut Ebay hat es eine Ansprechzeit von 10 - 12 Sekunden. Sollte also gehen, oder?

Danke schonmal :slight_smile:

Sollte es, stimmt.
So lange braucht der auch wieder nicht, ich hab da irgendwas mit ner dreiviertlen Sekunde im Hinterkopf, kann aber sein, es war weniger.
Hab grade mal in meinem Programm geschaut, ich geb mich mit der Prüfsumme gar nicht wirklich ab.
Ich prüfe lediglich mit

if (isnan(h) || isnan(t) || (t==0) || (h==0))
   {
    fehlerWettersensor=1;
    }

ob sinnvolle Werte raus kommen.
Allerdings messe ich mehrmals nacheinander, filtere alles, was unglaubwürdig ist, heraus, und vermittle den Rest.
So erreich ich recht brauchbare Ergebnisse.
Wie genau die sind, kann ich allerdings nicht sagen, aber sie stimmen im Wesentlichen mit einer der genannten Billig-"wetterstationen" überein, können also nicht soo weit daneben liegen.
Für meine Anwendung reicht mir das.

Bei mir liegt das auch schon länger zurück, und habe deshalb ebenfalls in das Programm reingesehen.

Ich lese im Sekundentakt aus, im Kontext zu dem was Rabenauge sagt ist das etwas zu schnell.
Kann leider gerade nicht testen, da am STM32 Board gerade was anderes dranhängt.

Der Sensor war aber direkt auf einer Adapterplatine gelötet, auf der das STM32 Board gesteckt ist.

@JulHa: Sind deine Meßwerte mit dem längerem Meßintervall halbwegs genau ?

JulHa:
Das Kabel ist ca. 20cm lang.

Damit dürfte es unter normalen Umständen niemals so viele CRC-Fehler geben wie Du oben gepostet hast.

Welche Schaltung?
Welcher Arduino?
Welche verwendete DHT11-Library?

JulHa:
Habe nach jedem Auslesen Delays von 5 bis 15 Sekunden versucht.
Laut Ebay hat es eine Ansprechzeit von 10 - 12 Sekunden. Sollte also gehen, oder?

Die "Ansprechzeit" hat nichts damit zu tun, wie schnell Du den Sensor sampeln darfst, sondern diese Ansprechzeit bestimmt, wie schnell sich die gemessenen Werte an geänderte Temperaturen anpassen. Also wie lange es nach einer Temperaturänderung dauert, bis der Sensor einen bestimmten Betrag der Temperaturänderung mitgemacht hat, er also auf die Temperaturänderung "reagiert".

Die Samplingrate gemäß Datenblatt beträgt 2s, d.h. Du darfst alle 2s einen Messwert abholen.

Irgendwas ist da faul, wenn Du so viele CRC-Fehler bekommst.

Entweder stimmt da etwas mit der Betriebsspannung nicht. Verwendest Du 5V oder 3.3V?

Oder es stimmt etwas mit dem Timing nicht, also dass Du evtl. eine nur für 16 MHz AVR-Controller gemachte Library auf einem 84 MHz Arduino DUE verwendest.

Es können natürlich immer mal CRC-Fehler auftreten, aber nicht so geballt und massiv wie bei Dir.

Wenn CRC-Fehler so zahlreich auftreten wie bei Dir, mußt Du sogar auch mit falschen Messwerten rechnen: Falls nämlich ein CRC-Fehler nicht auf einem einzigen gekippten Bit beruht, sondern möglicherweise mehrere Bits falsch sind, kann eine CRC-Prüfsumme aus nur 8 Bits auch "zufällig" richtig sein, und zwar mit einer Wahrscheinlichkeit von 1/256. So dass Du damit rechnen müßtest: Statistisch gesehen kommt auf 255 richtig erkannte CRC-Fehler ein nicht erkannter CRC-Fehler, der Dir als richtiger Messwert mit korrektem CRC gemeldet wird.

I built a humidity monitor with the DHT11 sensor, and noticed that I got an awful lot of checksum errors. After debugging, I came to the conclusion that the way the pulse width is measured is resulting in values that are all over the place --> I conclude that using the micros() function is not working properly, at least in my case. :smiley_cat:

My system: Arduino nano with ATMega 328.

I fixed the problem by removing a single line of the code in the dht11.read routine, and replacing it with even simpler code. There was another problem that the routine even returned incorrect values with checksum errors. I fixed this by changing the order of code at checksum test. The complete routine I use is posted below. I also added comments to explain more details. I can only test this on the nano, as I do not have more sensors....

Enjoy! :wink: For me the sensor now consistently works fine!

// Return values from this routine:
//   DHTLIB_OK
//   DHTLIB_ERROR_CHECKSUM
//   DHTLIB_ERROR_TIMEOUT
//
//   checksum error issue fixed (tested on nano), Ronald Gadget, 31 dec 2014
//
int dht11::read(int pin)
{
	// BUFFER TO RECEIVE
	uint8_t bits[5]; // 5 * 8 = 40 bits total
	uint8_t cnt = 7;
	uint8_t idx = 0;
	// EMPTY receive BUFFER
	for (int i=0; i< 5; i++) bits[i] = 0;
	// REQUEST reading from sensor
	pinMode(pin, OUTPUT);   // the sensor data pin is BIDI!!
	digitalWrite(pin, LOW);
	delay(20);  // was 18, get less timeouts now
	digitalWrite(pin, HIGH);
	delayMicroseconds(40);
	pinMode(pin, INPUT); // change to receive data, wait for sensor data now

	// ACKNOWLEDGE or TIMEOUT
	unsigned int loopCnt = 10000;
	while(digitalRead(pin) == LOW)
		if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

	loopCnt = 10000;
	while(digitalRead(pin) == HIGH)
		if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

	// READ OUTPUT, 40 BITS => 5 BYTES or TIMEOUT
        // each bit starts with 50uS low, a 0 is sent with 27uS high, a 1 is sent with 70uS high:
        //
        //       \______/------------\ one bit of 40
        //         50uS    27 or 70uS
        //
	for (int i=0; i<40; i++)
	{
		loopCnt = 10000;
		while(digitalRead(pin) == LOW) // is has to go low for this protocol
			if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

//		unsigned long t = micros(); // to check how long pulse is

		loopCnt = 10000;
		while(digitalRead(pin) == HIGH) {
			if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
                }
// old:		if ((micros() - t) > 55) bits[idx] |= (1 << cnt);  // 45 was 40
		if ((10000-loopCnt)>10) bits[idx] |= (1 << cnt);  // NEW!! -- either 2..5 iterations, or 13..15 
		if (cnt == 0)   // next byte?
		{
			cnt = 7;    // restart at MSB
			idx++;      // next byte!
		}
		else cnt--;
	}

	// WRITE TO RIGHT VARS
        // as bits[1] and bits[3] are allways zero they are omitted in formulas.


	uint8_t sum = bits[0] + bits[2];  

	if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;
	humidity    = bits[0]; //byte 0
	temperature = bits[2]; //byte 2
	return DHTLIB_OK;
}

ronaldgadget:

 // READ OUTPUT, 40 BITS => 5 BYTES or TIMEOUT

// each bit starts with 50uS low, a 0 is sent with 27uS high, a 1 is sent with 70uS high:
       //
       //       ______/------------\ one bit of 40
       //         50uS    27 or 70uS
       //

That's the correct timing diagram for a DHT11.
So the average of a 0-Bit (27µs) and a 1-Bit (70µs) is at (27+70)/2= 48.25µs = ca. 48 µs.
So 48µs should be the time to split between 0-bits and 1-bits.

I don't know which library the toptic starter was using with his test, but I've seen at last one library, where the split time was set to 40µs, which is only a tolerance of +13µs for a 0-bit, but a tolerance of -30µs for a 1-bit. I'd better use a split time of 48µs to make the decision between a 0-bit and a 1-bit.

ronaldgadget:

 loopCnt = 10000;

while(digitalRead(pin) == HIGH) {
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
               }
// old: if ((micros() - t) > 55) bits[idx] |= (1 << cnt);  // 45 was 40
if ((10000-loopCnt)>10) bits[idx] |= (1 << cnt);  // NEW!! -- either 2..5 iterations, or 13..15

Be careful: Counting loop runs is NOT hardware independent. And the duration that "digitalRead(pin)" takes is NOT constant. In the Arduino IDE one call of "digitalRead(pin)" will take:

  • about 4µs on an ATMEGA328 on a non-PWM pin
  • slightly less than 5µs on an ATMEGA328 on PWM pin
  • about 5µs on an ATMEGA2560 on a non-PWM pin
  • slightly less than 6µs on an ATMEGA2560 on PWM pin

So ten times "digitalRead(pin)" may take from 40µs (ATMEGA328, non-PWM pin) to about 60µs (ATMEGA2560, PWM pin). The time nearly doubles on an Arduino which runs at 8 MHz instead of 16 MHz. And the time is much less on an Arduino DUE.

So to keep everything hardware independent, the code should better rely on the micros() function to do the sensor timing.

And now lets switch to German.

Also: Lieber hardwareunabhängigen Code mit Hilfe der micros()-Funktion schreiben als Code für jeden Controller und für jede Controller-Taktrate anpassen zu müssen.

Insbesondere bei Arduino-Code mit einem dubiosen Timing durch das Zählen von Schleifendurchläufen, würde ich davon ausgehen: Wenn der Code für Arduino 1.0 geschrieben wurde, dann funktioniert er nur:

  • auf den Compilerversionen 1.0.x einwandfrei
  • auf AVR Atmega Arduinos mit 16 MHz Systemtakt

Entsprechend kann der Code versagen

  • unter Compilerversion 1.5.x (wg. anderer Codeoptimierung)
  • auf Boards, die keinen AVR Atmega-Controller haben (z.B. Arduino DUE)
  • auf Boards, die nicht mit 16 MHz Systemtakt laufen

Bei Interesse könnte ich einen DHT11-Code schreiben und posten, der das Timing mit micros() macht, und der daher sowohl unter alten als auch neuen Compilerversionen, auf AVR Atmega und auf ARM-basierenden Boards, und mit unterschiedlichen Taktraten funktioniert. Es sollte eigentlich eine Kleinigkeit sein, dass der Code weder hardware- noch compilerabhängig die Bitlängen korrekt mißt und und daher unter normalen Umständen auch keine Checksum-Fehler produzieren sollte.

Bei Interesse kurze Rückmeldung, dann schreibe ich das mal zusammen.

Dear Jurs,

you are fully correct that using loopCnt makes the code completely HW dependent, and that micros() is the safe way.... when micros() works.

I wrote a piece of debugging code, where I count the times a bit transition happens at each uS using the original routine with the micros() call. This showed bit transitions happening at times that were all over the place (many transitions anywhere between 1 and 80 uS).

I then thought that the signal from the sensor must be noisy. I attached a storage scope which showed the signal is perfect (no noise). --> so SW must be the problem.

Then I changed to using the loopCnt to decide on sensor bit length, and immediately the chksum problem went away. My conclusion: the micro() routine that should make things HW independent and 'better' does not work as desired (at least for my case with the Nano).

I studied the micro() code, and could not find anything wrong with it. I admit that I do not understand why the micro() based code does not work as expected....

I also played with interrupts (turning them on / off at various places) --> made no difference.

Ronald

PS. just got my Arduino mega 2560 to work. Finally enough code space to have TFT and SDcard working at the same time!

ronaldgadget:
I studied the micro() code, and could not find anything wrong with it. I admit that I do not understand why the micro() based code does not work as expected....

I think the problem is how you trigger the data using "delayMicroseconds(40);".
I don't think that this is really OK doing it that way.

 delay(20);
 digitalWrite(pin, HIGH);
 delayMicroseconds(40);
 pinMode(pin, INPUT); // change to receive data, wait for sensor data now

 // ACKNOWLEDGE or TIMEOUT
 unsigned int loopCnt = 10000;
 while(digitalRead(pin) == LOW)
 if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

This means, you set the bus to OUTPUT/HIGH for 40µs, then release the bus to INPUT/HIGH and then immediately start a loop that measures how long the bus stays LOW.

I think the programming logic should be more like that:

 delay(20);
 digitalWrite(pin, HIGH); // pull the bus to HIGH
 pinMode(pin, INPUT); // change to receive data, wait for sensor data now
        
 // include here: loop waiting while signal is HIGH (or timeout occurs)

 // ACKNOWLEDGE or TIMEOUT
 unsigned int loopCnt = 10000;
 while(digitalRead(pin) == LOW)
 if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

I think the problem is how you trigger the data using "delayMicroseconds(40);".
I don't think that this is really OK doing it that way.

This is the original DHT11 code that I did not touch... However, the spec says the host (read Arduino) must force the line 40 uSec HIGH, and then turn it to input to check the sensor response...

I am still hoping someone can explain the micros() mystery...

Ronald

ronaldgadget:
I am still hoping someone can explain the micros() mystery...

I've done some extra debugging on that topic and found, that there is a big variation in time measured with micros() loops. I found 8...28 microseconds for 0-bits and 48..68 microseconds for 1-bits in my tests.

This seems strange as a single call of digitalRead() takes a 4µs up to 6µs at most on AVR Atmega controllers. So I'd normally expect that only differences in time of max. 8µs should occur.

But on the other hand: Calculations with "long" and "unsigned long" numbers take a lot of time also, and most likely even the micros() funktion call takes some time. So at last, the time measures differ about 20µs, even if the bit lengths are absolutely the same.

Most likely "loopCnt--" with an integer variable is so much quicker than "micros()-time" with unsigned long, so that the time measure is much more exact because it is executed more often.

So perhaps counting loops with int variables may lead to more accurate results than calculations with long variables and microseconds, simply because it's quicker.

Perhaps the code can be made hardware independent when doing an initialization which measures the time for "digitalRead + counting in a loop", so that the same code can run an Atmega controllers or the ARM based DUE as well. I'do do some further testing on that...

Can the issue with the slowly portread timeing fixed by using the library digitalwritefast ?

rudirabbit:
Can the issue with the slowly portread timeing fixed by using the library digitalwritefast ?

digitalRead() function runtime is 4...6µs on 8-bit Atmega controllers.
digitalReadFast() is about 1µs.

So you can make the timing better by at most 5µs.
This can help a little bit.

But what about hardware compatibility?
I don't think that digitalReadFast is available for Arduino DUE?
Not so far from now the "Arduino ZERO" will become the entry Arduino.
Is different code for different types of Arduino boards really a good solution?

The real issue indeed is the total runtime of the while loop.

Such code:

 unsigned int loopCnt = 10000;
 while(digitalRead(pin) == LOW) if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

is running much quicker in the while-loop than such code:

  unsigned long time=micros();
  while (digitalRead(pin)==LOW) if (micros()-time>=120) return DHTLIB_ERROR_TIMEOUT;

That while-loop uses extra time for

  • "micros()" function calls
  • math substraction with 32-bit numbers
    Function calls are slow and numeric 32-bit math on an 8-bit controller is slow.

So because the while loop with micros() runs much slower than the while loop with loopCnt you will get much less accurate timing results.

Im just testing some ideas, how to create better code for reading DHT sensors.
Code that will avoid issues of older code.
And code that can work perfectly with 8-Bit AVR Atmega controllers as well as with Arduino DUE ARM based controllers, using the same code.
I'm not yet finished.
But when I have code ready, I will post it here.

So finally after some thinking and testing I think I've got a solution avoiding most checksum errors with DHT sensors. DHT11 as well as DHT22.

I think that a mix of a "loop counting timeout" and "delayMicroseconds" is the best solution, avoiding checksum errors as well as multiple function calls of the micros() function which would lead to big variations in timing.

A loop such like this executed on a 16 MHz Arduino board:

        loopCnt = 120;
        while(digitalRead(pin) == LOW) if (loopCnt-- == 0) return DHT_ERROR_TIMEOUT;

will end about 6 to 8µs after the pin has gone HIGH.
This is caused, because the digitalRead() function call will take 4...6µs and the loop overhead takes about 2µs .

Followed by:

        delayMicroseconds(32);               
        boolean dhtBit=digitalRead(pin);

which will take 32µs for the delay and 4...6µs for the digitalRead, we get a sample of the pin after a total time of 6+32+4 to 8+32+6 Microseconds, this is 42 to 46 Microseconds after the pin went HIGH.

If the DHT sensor sends a 0-bit with a 27µs duration, or a 1-bit with a 70µs duration, we are in the middle of it in any case with a sample timing of 42 to 46µs.

In case we are using a DUE board, timing is a bit different. The digitalRead function is much quicker as well as the loop that detects the HIGH state. So the sample is taken after about 1+32+1= 34µs. But also 34µs is surely longer than 27µs for a 0-bit, so even with the DUE and the same code it is possible to detect 0-bits from 1-bits safely.

Total demo code, tested with 16 MHz MEGA and with 84 MHz DUE boards as well as with DHT11 and DHT22 sensors (configurable):

// DHT11 and DHT22 sensor reading demo
// by 'jurs' for German Arduino Forum
// Code should be fine for all Arduino boards from 16 MHz (i.e. "UNO") to 84 MHz ("DUE")

// DHT functions enumerated
enum {DHT11_SAMPLE, DHT22_SAMPLE, DHT_TEMPERATURE, DHT_HUMIDITY, DHT_DATAPTR};

// Begin of user configuration area
#define DHT_SAMPLE DHT11_SAMPLE // must be DHT11_SAMPLE or DHT22_SAMPLE
#define DHT_PIN 2
// End of user configuration area

// DHT error codes enumerated
enum {DHT_OK=0, DHT_ERROR_TIMEOUT=-1, DHT_ERROR_CRC=-2, DHT_ERROR_UNKNOWN=-3};

void setup()
{
  Serial.begin(9600);
  Serial.println("DHT Temperature and Huminity Measurement");
}

// DHT sensor pinout from left to right looking at the gridded side
// 1-VCC  2-DATA  3-NC  4-GND

int dhtCall(byte pin, byte function)
// input parameters are the data pin and one of the DHT functions
// return value is DHT error code with function DHT11_SAMPLE or DHT22_SAMPLE
// alsways do sampling with DHT_OK result before calling other functions
// return value is temperature with function DHT_TEMPERATURE
// return value is humidity with function DHT_HUMIDITY
// return value is pointer to byte array containing raw data with function DHT_DATAPTR
{
  static int temperature=-999;
  static int humidity=-999;
  static byte data[5]; // 5 bytes to receive 40 data bits
  unsigned int loopCnt; // loop counter
  byte sum;  // checksum
  #define DHT_LOOPS 120
  int triggerTime;
  switch (function)
  {
    case DHT11_SAMPLE: // REQUEST DHT11 SAMPLE
    case DHT22_SAMPLE: // REQUEST DHT22 SAMPLE
      if (function==DHT11_SAMPLE) triggerTime=20000; // 20000µs trigger time for DHT11
      else triggerTime=1000; // 1000µs trigger time for DHT22
      pinMode(pin, OUTPUT); 
      digitalWrite(pin, LOW);
      delayMicroseconds(triggerTime); 
      digitalWrite(pin,HIGH);
      pinMode(pin,INPUT);
      loopCnt = DHT_LOOPS;
      while(digitalRead(pin) == HIGH) if (loopCnt-- == 0) return DHT_ERROR_TIMEOUT;
      loopCnt = DHT_LOOPS;
      while(digitalRead(pin) == LOW) if (loopCnt-- == 0) return DHT_ERROR_TIMEOUT;
      loopCnt = DHT_LOOPS;
      while(digitalRead(pin) == HIGH) if (loopCnt-- == 0) return DHT_ERROR_TIMEOUT;
      for (byte bitNum=0;bitNum<40;bitNum++) // try reading 40 bits
      {
        loopCnt = DHT_LOOPS;
        while(digitalRead(pin) == LOW) if (loopCnt-- == 0) return DHT_ERROR_TIMEOUT;
        delayMicroseconds(32);
        boolean dhtBit=digitalRead(pin);
        bitWrite(data[bitNum/8],7-bitNum%8,dhtBit);
        loopCnt = DHT_LOOPS;
        while(digitalRead(pin) == HIGH) if (loopCnt-- == 0) return DHT_ERROR_TIMEOUT;
      }
      sum = data[0] + data[1] + data[2] + data[3];  
      if (data[4] != sum) return DHT_ERROR_CRC;
      if (function==DHT11_SAMPLE)
      {
        humidity=data[0];
        temperature=data[2];
      }
      else
      {
        humidity=data[0]*256+data[1];
        temperature= (data[2] & 0x7F) * 256 + data[3];
        if (data[2] & 0x80) temperature= -temperature;
      }
      return DHT_OK;
    case DHT_TEMPERATURE:
      return temperature;
    case DHT_HUMIDITY:  
      return humidity;
    case DHT_DATAPTR:
      return (int)data;
    default:
      return DHT_ERROR_UNKNOWN;
  }  
}

void loop()
{
  byte* b; // byte pointer for showing raw data
  switch (dhtCall(DHT_PIN, DHT_SAMPLE)) // always request a sample first
  {
    case DHT_OK: // only if DHT_OK is true, get temperature, humidity and possibly raw data
      Serial.print("Humidity: ");
      Serial.print(dhtCall(DHT_PIN, DHT_HUMIDITY));
      Serial.print("   Temp: ");
      Serial.print(dhtCall(DHT_PIN, DHT_TEMPERATURE));
      Serial.print("     raw data:  ");
      b=(byte*)dhtCall(DHT_PIN, DHT_DATAPTR);
      for (int i=0;i<5;i++)
      {
        Serial.print(b[i]);Serial.print('\t');
      }
      Serial.println();
      break;
    case DHT_ERROR_TIMEOUT:
      Serial.println("Timeout Error");
      break;
    case DHT_ERROR_CRC:
      Serial.println("CRC Error");
      break;
    default:
      Serial.println("Unknown Error");
  }
  delay(2000); // minimum time between two DHT samples is two seconds
}

The temperature and humidity values returned from my function are degrees and percent in case of a DHT11 and they are tenths of degrees and tenths of percent in case of a DHT22. Always integer numbers. So in case you want do display decimals with DHT22, either use a special formatting routine or divide the values by 10.0 to make float values before doing float formatting.

As a goodie which is not available with any DHT-library I've seen before, I have made the raw data bytes readable after sampling. So it would be possible to send out the raw data just as sampled from the sensor via a RF sender over an wireless connection.

Not tested with 8 MHz Arduinos, I only tested with 16 MHz and 84 MHz DUE boards.
Works fine without checksum errors for me.