User Tools

Site Tools


en:pfw:dht22

**This is an old revision of the document!**

DHT22 Protocol

Introduction

The DHT22 module is a low-cost digital temperature and humidity sensor. It utilizes a capacitive humidity sensor and a thermistor to measure the surrounding air and outputs a digital signal via a single data pin. It's known for its wider measurement range and higher accuracy compared to its predecessor, the DHT11.

Key features include:

  • Measures both temperature (from -40°C to 80°C with an accuracy of ±0.5°C) and humidity (from 0% to 99.9%RH with an accuracy of ±2-5%).
  • Digital output via a single-wire interface, simplifying communication with microcontrollers like Arduino and Raspberry Pi.
  • Operates on a voltage range of 3.3V to 6V.
  • Has a relatively low power consumption.
  • Offers good long-term stability.
  • Typically comes on a small PCB with necessary pull-up resistors, making it easy to integrate into projects.
  • Has a sampling rate of no more than 0.5 Hz (once every 2 seconds).
  • Suitable for indoor environmental monitoring, weather stations, and HVAC systems.

SDA

The DHT22 communicates using a proprietary single-wire serial protocol. Here's a breakdown of the process:

  1. Start Signal from Microcontroller: The microcontroller initiates communication by pulling the data line low for a specific duration (typically > 800µs to 1ms). This signals the DHT22 to wake up and prepare to send data.
  2. Response from DHT22: After the start signal, the DHT22 pulls the data line low for about 80µs and then high for another 80µs. This serves as a response signal indicating that the sensor is ready to transmit data.
  3. Data Transmission (40 bits): The DHT22 transmits 40 bits of data representing humidity and temperature readings, followed by a checksum bit. Each bit is transmitted as follows: * The data line is first pulled low for approximately 50µs. * Then, it's pulled high for a varying duration: * 26-28µs high indicates a “0” bit. * 70µs high indicates a “1” bit.
  4. Data Format (5 bytes): The 40 bits of data are structured into five 8-bit bytes: * Byte 1: Humidity integer part (0-99) * Byte 2: Humidity decimal part (always 0 for DHT22) * Byte 3: Temperature integer part (-40 to +80) * Byte 4: Temperature decimal part (always 0 for DHT22) * Byte 5: Checksum (sum of the first four bytes, modulo 256)
  5. End of Transmission: After transmitting all 40 bits, the DHT22 releases the data line, and it's pulled high by an external pull-up resistor, returning to the idle state.

The microcontroller needs to carefully time these pulses to correctly interpret the data sent by the DHT22. Libraries for popular platforms like Arduino and Raspberry Pi handle these timing-critical operations.

am2302-en-aosong.pdf This Aosong document has the correct data, although it is a creepy English translation.

Screenshot of the 40-bit response on the SDA line. (PulsView Logic Analyser)

Implementation

Testing with a Logic Analyser (PulsView)

Pin P1.0 is bidirectional. It sends the start pulse and then receives the 40 data bits from the sensor module.

The code includes test pulses on pin P1.6 to check the timing. You can remove those.

The top line is the DHT22's response, and the following line shows the timing checks. The checksum is correct.

The time-critical part is assembler code. The surrounding code was written in noForth. It uses tools.f and noforth_m_asm from the noForth library. These must be compiled into noForth on the MSP430G2553 beforehand.

Sensor modules vary in their output speed due to manufacturing and temperature conditions. 1/4 of the response pulse is approximately the waiting time to read the bit. Therefore, the code adapts to the observed speed. A 'while' loop is used for this, but its execution takes about twice as long as the wait loop for reading the bit. The waiting time from 'moon' is therefore simply doubled to make it fit.

The timing is critical. So, it's correct now. Here we read a "0"

Pseudocode

Function: Pio    ( -- )  \ set port I/O function. SDA --> P1.0 
Function: wakeup ( -- )  \ notify sensor to prepare the data
Function: @data  ( -- sun moon hum tmp chk chksum )  \ get sensor data
  get response time of sensor, store in register 'sun' (just for testing)
  get startpulse duration, store in register 'moon'
  40 loop 
     read bit using 'moon' based delay 
     lshift bit into array xx yy zz
  08 loop       
     lshift array  \ adjust xx yy zz --> hum tmp chk 
  calculate chksum
Function: (dht22)  ( -- sun moon hum tmp chk chksum ) \ wake up and read sensor
Function:  dht22   ( -- )  \ print temperatur and humidity
Function:  test    ( n -- ) \ multiple readings  
    n loop  dht22

Source Code

DHT22 with Launchpad MSP430G2553

\ Read DHT22.  (bitbang)
\ TI MSP430G2553 Launchpad with noForth mv 2553 240101 

(* 
To do: timeout 

History
V0065 - Temperature in tenths of a degree. mk 20250424
V0064 - Loops named with ( A ) ... ( D ). Variants of loops B and D studied. This loop variation of B and D work well. Comments revised. mk 20250423 05:25
V0063 - Cleaned up the code. Data output reduced to the essentials. mk 20250421 02:04
V0062 - Works well, output rounded to whole digits. mk 20250419 21:51
Previous versions: Successive approximation to the solution.

Patch millisecond to 100 microseconds. 
See: config2553.f
  00c7 10B2 rom!  
  hex 10B2 DMP
After COLD this value is active.

addr acronym registername
020  P1IN    Input
021  P1OUT   Output 
022  P1DIR   Direction
023  P1IFG   Interupt Flag
024  P1IES   Interrupt Edge Select
025  P1IE    Interrupt Enable
026  P1SEL   Port Select
041  P1SEL2  Port Select2
027  P1REN   Resistor Enable 
*)


asm\    

hex

\ helper
code cls ( -- ) s0 # sp mov  next end-code  \ clear stack

code p1H     #1 021 & .b bis   next end-code \ set lines
code p1L     #1 021 & .b bic   next end-code
code p6H   40 # 021 & .b bis   next end-code
code p6L   40 # 021 & .b bic   next end-code


\ Assign DHT22 data line to pin p1.0, controll pin to p1.6
: Pio ( -- )  \ set I/O function
  41 027 *bic \ p1ren off
  41 025 *bic \ p1ie  disable interrupt
  41 026 *bic \ P1SEL I/0
  41 041 *bic \ P1SEL2 I/0 
  41 022 *bis \ set out for P1.0, P1.6
  ;

: wakeup ( -- ) \ notify sensor to prepare the data
  pio p1H p6H 1 ms  p1L 10 ms  ( p6L ) p1H  ; \ 1 ms == 100┬Ás !

Code @data ( -- sun moon hum tmp chk chksum )  \ read sensor data
 \ get response time 
  #1 022 & .b bic \ p1,0 IN
  #0 sun      mov   
  #1 024 & .b bis \ FALLING EDGE\__
  #1 023 & .b bic  \ clear P1IFG 
40 # 021 & .b bic \ p6L\___  (for logic analyser)
  begin, ( A )       \ wait for edge 
    #1 023 & .b bit  \ test bit 
    \ Z: Set if result is zero, reset otherwise
    \ C: Set if result is not zero, reset otherwise (.NOT. Zero)
  cc? while, 
    #1 sun add
  repeat,   
40 # 021 & .b bis \ ___/p6H  (for logic analyser)
  tos sp -) mov   
  sun tos   mov   ( -- sun )
 \ get startpulse time
  #0 moon     mov   
  #1 024 & .b bic \ ___/ RISING EDGE
  #1 023 & .b bic  \ clear P1IFG 
40 # 021 & .b bic \ p6L\___  (for logic analyser)
  begin, ( B )       \ wait for edge
    #1 023 & .b bit  \ test bit 
   \ Z: Set if result is zero, reset otherwise
   \ C: Set if result is not zero, reset otherwise (.NOT. Zero)
   cc? while,
   #1 moon add
  repeat,   
40 # 021 & .b bis \ ___/p6H  (for logic analyser)
  tos sp -)  mov   
  moon tos   mov   ( -- moon )
 \ read 40 bits to array
  #0 xx mov  \ init array
  #0 yy mov
  #0 zz mov 
  dm 40 # day mov
  begin, ( C )
    #1 023 & .b bic \ clear P1IFG 
    begin,           \ wait for edge
      #1 023 & .b bit \ test IFG
      \ Z: Set if result is zero, reset otherwise
      \ C: Set if result is not zero, reset otherwise (.NOT. Zero)
    cs? until,
    \ wait to read bit
    moon w mov 
	w w add     \  2*moon, Loop D is about twice as fast as loop B.
40 # 021 & .b bic \ p6L\___  (for logic analyser)	
    begin, ( D )
      #1 w sub  
    0=? until,
	\ read bit
40 # 021 & .b bis  \ __/p6H  (for logic analyser)
    020 & w .b mov  \ read data line: bit H or L
    #1 w       bia   \ get bit
      \ tos sp -) mov  
      \ w tos     mov  ( ... -- ... bit ) \ test
      \ #1 sr bic  \ clear carry bit
	\ shift left all bits
    zz zz add   
    yy yy addc
    xx xx addc
    w  zz bix   \ = xor : write data bit
  #1 day sub
  0=? until, \ 40 bits are read
  \ adjust bits
  8 # day mov  \ lshift 40 bits up 8x -> xx=hum yy=tmp 
  begin,
    zz zz add 
    yy yy addc
    xx xx addc
    #1 day sub
  0=? until,
  \ push data to stack
  tos sp -)  mov   xx tos mov  ( -- xx ) 
  tos sp -)  mov   yy tos mov  ( -- yy ) 
  zz swpb  \ get upper byte
  tos sp -)  mov   zz tos mov  ( -- zz.b ) 
  \ calculate checksumme
  #0 w mov
  xx w .b add   xx swpb   xx w .b add
  yy w .b add   yy swpb   yy w .b add
  tos sp -)  mov  
  w tos   mov
next end-code

\ display 
decimal
: (dht22) ( -- sun moon hum tmp chk chksum )
  cls wakeup @data 
  ;

: decemit ( c -- ) \ print c from DEC special character set 
  hx 1B emit  [char] ( emit  [char] 0 emit   emit 
  hx 1B emit  [char] ( emit  [char] B emit   \ back to normal output
  ;

: .tmp ( tmp -- )  
  10 /mod 3 .r [char] , emit .
  [char] f decemit 
  [char] C emit space
  ;  \ ja, geht.

  
: .hum ( hum -- )  \ rounded to whole percent
  10 / . ." %rel" space 
  ;  
	
: dht22 ( -- ) \ print temperatur and humidity
  cr (dht22)   ( 2 + ) \ add 2 for 'else' part
  = if ." chk  " else ." chksum error" cls exit then
  .tmp space space  .hum space space
  \ ( sun moon -- ) drop drop 
    ( sun moon -- )  . .      \ testing
  ;

(*
The DHT22 starts its next measurement AFTER the query and saves the values. 
These are output with the next query, so they are old. 
For up-to-date values, query twice. 
There must be more than 2 seconds between each query, otherwise the DHT22 will not respond again.
*)
    
: test ( n -- )
  >r
  cr ." discard old values..." (dht22) cls 
  cr ." reading current data:"
  r> 0 do   
    dm 40000 ms  \ wait until the sensor is ready again.
    dht22  
  loop
  ;

shield nn\
freeze
( finis)

More information on the MSP430G2553

Source code editor

I like Notepad Next for Linux, a cross-platform, reimplementation of Notepad++. https://github.com/dail8859/NotepadNext

Terminal

To work with the embedded noForth system I use e4thcom by Manfred Mahlow. https://wiki.forth-ev.de/doku.php/projects:e4thcom

Logic Analyser

AZDelivery Logic Analyzer 8 CH, 24MHz. (Amazon) PulseView is a Qt-based logic analyzer and oscilloscope GUI for sigrok.


en/pfw/dht22.1745536128.txt.gz · Last modified: 2025-04-25 01:08 by mka