Here's something you might find useful. The DHT22 is pretty mysterious first off because it uses pulse code modulation to send and receive, employs a non-standard way of representing negative temperatures, and lastly because the numeric format is not explained in the poorly translated data sheet.
So, I've put together an include file that takes all the misery and mystery out of it. This is my first attempt at an include file, so I would appreciate any comments or suggestions. It's pretty much self-documented and heavily annotated. Observe that it now returns relative humidity, Celsius and Fahrenheit properly rounded and accurate to the nearest tenth. I'm not sure how attach files here, so will simply list it. Below the file is a sample program using the include.
DHT22.H Include File
~~~~
;DHT22 Humidity/Temperature Sensor Library for Great Cow Basic
;Thomas Henry
;Version 1.0 -- 4/2/2014
;There is only one subroutine here. When called, it will
;return the relative humidity, Celsius and Faharenheit
;temperatures to one decimal place. The three numbers are
;treated as signed integers, scaled up by ten. For example,
;a return value of 657 for the relative humidity would be
;interpreted as 65.7%.
;Also returned is an error condition (a byte):
;0 = no error
;1 = no response from the sensor
;2 = bad checksum from the sensor
;Nine local bytes are consumed in the computations here,
;and seven bytes used for the output parameters. That's a
;grand total of sixteen bytes required when invoking this.
;The only constant required in the main calling program
;is that which sets the single data pin, e.g.,
;#define DHT22_pin Port A.0
;Note that whichever pin is employed, it must be capable
;of both input and output operation and must have a
;10k pull-up resistor.
;For reference, the pinout of the DHT22 is, looking from
;the front, (grill side):
;This sensor transmits data via pulse code modulation at a
;fairly zippy rate, so the microcontroller clock should be
;at least 8 MHz. Observe that the DHT22 can not be
;polled more frequently than once every two seconds.
;----- Variables
dim DHT22_values(5)
dim DHT22_counter, DHT22_i, DHT22_byte as byte
;reuse a couple variables to save memory
dim DHT22_chksum alias DHT22_counter
dim DHT22_abs alias DHT22_counter
;----- Subroutine
sub readDHT22(out DHT22_rh as integer, out DHT22_cels as integer, out DHT22_fahr as integer, out DHT22_error as byte)
;----- request an update
dir DHT22_pin out ;port is output now
set DHT22_pin off ;go low
wait 18 mS ;for 18 milliseconds
set DHT22_pin on ;then go high
wait 40 uS ;for 40 microseconds
;----- wait for an acknowledgment
dir DHT22_pin in ;port is input now
DHT22_counter = 0 ;count by tens of microseconds
do while DHT22_pin = off ;until pin goes high
wait 1 10uS
DHT22_counter++
if DHT22_counter > 9 then ;should take 80 microseconds
goto DHT22_noResponse ;so must be a dud
end if
loop
DHT22_counter = 0 ;repeat, looking for a low now
do while DHT22_pin = on
wait 1 10uS
DHT22_counter++
if DHT22_counter > 9 then ;should take 80 microseconds
goto DHT22_noResponse ;so must be a dud
end if
loop
;----- start of transmission
for DHT22_i = 1 to 5 ;five bytes to collect
DHT22_byte = 0 ;build up DHT22_byte here
repeat 8 ;8 bits to a byte
DHT22_byte = 2 * DHT22_byte ;shift left one place
do while DHT22_pin = off ;wait for start of pulse
loop
DHT22_counter = 0 ;measure incoming pulse
do while DHT22_pin = on
wait 1 10uS ;count by tens of microseconds
DHT22_counter++
loop
if DHT22_counter > 4 then ;long pulse is a 1
DHT22_byte++ ;factor the bit in
end if
end repeat ;next bit
DHT22_values(DHT22_i) = DHT22_byte ;store complete byte
next DHT22_i
;----- construct output values
DHT22_chksum = DHT22_values(1) ;compute the checksum
for DHT22_i = 2 to 4
DHT22_chksum = DHT22_chksum + DHT22_values(DHT22_i)
next DHT22_i
if DHT22_chksum <> DHT22_values(5) then
DHT22_error = 2 ;Error 2 means bad checksum
goto DHT22_conclude
else
DHT22_error = 0 ;Error 0 means all okay
;compute relative humidity scaled up by 10
DHT22_rh = [integer]256 * DHT22_values(1) + DHT22_values(2)
;save the absolute value of the Celsius temperature
DHT22_abs = DHT22_values(3) & 0x7F
;compute Celsius temperature scaled up by 10
DHT22_cels = [integer]256 * DHT22_abs + DHT22_values(4)
;factor in the sign if needed
if DHT22_values(3).7 = on then ;a negative temp
DHT22_cels = -DHT22_cels ;make a true 2's complement
end if
DHT22_fahr = [integer]10*DHT22_cels ;scaled up by 100 now
DHT22_fahr = [integer]DHT22_fahr*9/5+3205 ;force rounding in the 100ths
DHT22_fahr = [integer]DHT22_fahr/10 ;this is 10*Fahrenheit, rounded
goto DHT22_conclude ;all done!
end if
DHT22_noResponse:
DHT22_error = 1 ;Error 1 means no response
DHT22_conclude:
end sub
And here's a sample program using it to show how easy it is now.
;Humidity/Temperature Sensor demo using DHT22.h include file.
;Thomas Henry
;This revision: 4/2/2014
include <dht22.h> ;sensor include file
;----- Settings
chip 16F88, 8 ;PIC16F88 running at 8 MHz
config mclr=off ;reset handled internally
config osc=int ;use internal clock
;----- Constants
define DHT22_Pin PortA.0 ;RH/Temp sensor on pin 17
define LCD_IO 4 ;4-bit mode
define LCD_RS PortB.2 ;LCD Register Select on pin 6
define LCD_Enable PortB.3 ;LCD Enable on pin 7
define LCD_DB4 PortB.4 ;DB4 on pin 8
define LCD_DB5 PortB.5 ;DB5 on pin 9
define LCD_DB6 PortB.6 ;DB6 on pin 10
define LCD_DB7 PortB.7 ;DB7 on pin 11
define LCD_NO_RW 1 ;ground the RW line on LCD
define degree 223 ;ASCII code for degree mark
define period 2 S ;update period
;----- Variables
dim msg, whole, tenths as byte
dim rh, cels, fahr as integer
;----- Main Program
dir portB 0b00000000 ;Port B is all output
cls
print "Initializing..."
wait period ;let unit stabilize
do
readDHT22(rh, cels, fahr, msg) ;get current values
cls
select case msg
case 0: ;all okay, so proceed
print "Humidity: " ;print relative humidity
printResult(rh)
print "%"
Hello all,
Here's something you might find useful. The DHT22 is pretty mysterious first off because it uses pulse code modulation to send and receive, employs a non-standard way of representing negative temperatures, and lastly because the numeric format is not explained in the poorly translated data sheet.
So, I've put together an include file that takes all the misery and mystery out of it. This is my first attempt at an include file, so I would appreciate any comments or suggestions. It's pretty much self-documented and heavily annotated. Observe that it now returns relative humidity, Celsius and Fahrenheit properly rounded and accurate to the nearest tenth. I'm not sure how attach files here, so will simply list it. Below the file is a sample program using the include.
DHT22.H Include File
~~~~
;DHT22 Humidity/Temperature Sensor Library for Great Cow Basic
;Thomas Henry
;Version 1.0 -- 4/2/2014
;There is only one subroutine here. When called, it will
;return the relative humidity, Celsius and Faharenheit
;temperatures to one decimal place. The three numbers are
;treated as signed integers, scaled up by ten. For example,
;a return value of 657 for the relative humidity would be
;interpreted as 65.7%.
;Also returned is an error condition (a byte):
;0 = no error
;1 = no response from the sensor
;2 = bad checksum from the sensor
;Nine local bytes are consumed in the computations here,
;and seven bytes used for the output parameters. That's a
;grand total of sixteen bytes required when invoking this.
;The only constant required in the main calling program
;is that which sets the single data pin, e.g.,
;#define DHT22_pin Port A.0
;Note that whichever pin is employed, it must be capable
;of both input and output operation and must have a
;10k pull-up resistor.
;For reference, the pinout of the DHT22 is, looking from
;the front, (grill side):
;Pin 1: +5V
;Pin 2: DHT22_pin
;Pin 3: no connection
;Pin 4: ground
;This sensor transmits data via pulse code modulation at a
;fairly zippy rate, so the microcontroller clock should be
;at least 8 MHz. Observe that the DHT22 can not be
;polled more frequently than once every two seconds.
;----- Variables
dim DHT22_values(5)
dim DHT22_counter, DHT22_i, DHT22_byte as byte
;reuse a couple variables to save memory
dim DHT22_chksum alias DHT22_counter
dim DHT22_abs alias DHT22_counter
;----- Subroutine
sub readDHT22(out DHT22_rh as integer, out DHT22_cels as integer, out DHT22_fahr as integer, out DHT22_error as byte)
;----- request an update
dir DHT22_pin out ;port is output now
set DHT22_pin off ;go low
wait 18 mS ;for 18 milliseconds
set DHT22_pin on ;then go high
wait 40 uS ;for 40 microseconds
;----- wait for an acknowledgment
dir DHT22_pin in ;port is input now
DHT22_counter = 0 ;count by tens of microseconds
do while DHT22_pin = off ;until pin goes high
wait 1 10uS
DHT22_counter++
if DHT22_counter > 9 then ;should take 80 microseconds
goto DHT22_noResponse ;so must be a dud
end if
loop
DHT22_counter = 0 ;repeat, looking for a low now
do while DHT22_pin = on
wait 1 10uS
DHT22_counter++
if DHT22_counter > 9 then ;should take 80 microseconds
goto DHT22_noResponse ;so must be a dud
end if
loop
;----- start of transmission
for DHT22_i = 1 to 5 ;five bytes to collect
DHT22_byte = 0 ;build up DHT22_byte here
repeat 8 ;8 bits to a byte
DHT22_byte = 2 * DHT22_byte ;shift left one place
do while DHT22_pin = off ;wait for start of pulse
loop
next DHT22_i
;----- construct output values
DHT22_chksum = DHT22_values(1) ;compute the checksum
for DHT22_i = 2 to 4
DHT22_chksum = DHT22_chksum + DHT22_values(DHT22_i)
next DHT22_i
if DHT22_chksum <> DHT22_values(5) then
DHT22_error = 2 ;Error 2 means bad checksum
goto DHT22_conclude
else
DHT22_error = 0 ;Error 0 means all okay
end if
DHT22_noResponse:
DHT22_error = 1 ;Error 1 means no response
DHT22_conclude:
end sub
And here's a sample program using it to show how easy it is now.
;Humidity/Temperature Sensor demo using DHT22.h include file.
;Thomas Henry
;This revision: 4/2/2014
include <dht22.h> ;sensor include file
;----- Settings
chip 16F88, 8 ;PIC16F88 running at 8 MHz
config mclr=off ;reset handled internally
config osc=int ;use internal clock
;----- Constants
define DHT22_Pin PortA.0 ;RH/Temp sensor on pin 17
define LCD_IO 4 ;4-bit mode
define LCD_RS PortB.2 ;LCD Register Select on pin 6
define LCD_Enable PortB.3 ;LCD Enable on pin 7
define LCD_DB4 PortB.4 ;DB4 on pin 8
define LCD_DB5 PortB.5 ;DB5 on pin 9
define LCD_DB6 PortB.6 ;DB6 on pin 10
define LCD_DB7 PortB.7 ;DB7 on pin 11
define LCD_NO_RW 1 ;ground the RW line on LCD
define degree 223 ;ASCII code for degree mark
define period 2 S ;update period
;----- Variables
dim msg, whole, tenths as byte
dim rh, cels, fahr as integer
;----- Main Program
dir portB 0b00000000 ;Port B is all output
cls
print "Initializing..."
wait period ;let unit stabilize
do
readDHT22(rh, cels, fahr, msg) ;get current values
cls
select case msg
case 0: ;all okay, so proceed
print "Humidity: " ;print relative humidity
printResult(rh)
print "%"
end select
wait period ;2 seconds min between readings
loop ;repeat in perpetuity
;----- Subroutines
sub printResult(in param as integer)
if param.15 = on then ;if it's negative
param = -param ;make non-negative
print "-" ;print a minus sign
end if
whole = param / 10 ;whole number part
tenths = param % 10 ;and the tenths
print whole ;integer part
print "." ;print decimal point
print tenths ;and the tenths
end sub