The protocol description indicates that we have to discriminate between high pulses of 28 us and 70 us. But if we use a loop to read an input pin and store its value:
Code: Select all
for i in range(100):
dat[i] = pin()
In order to read the message from the DHT11/DHT22 we need an I/O pin with open drain, assuming an external pull-up resistor. In the examples I use 'GP4'. De code for the sample function is:
Code: Select all
from machine import Pin, enable_irq, disable_irq
dat=Pin('GP4', Pin.OPEN_DRAIN)
dat(1)
def getval(pin) :
ms = [1]*300
pin(0)
time.sleep_us(20000)
pin(1)
irqf = disable_irq()
for i in range(len(ms)):
ms[i] = pin() ## sample input and store value
enable_irq(irqf)
return ms
We now have collected a list of sample values that we need to convert to bits. As indicated a 0-bit is encoded by a low followed by a short high, and a 1-bit as a low followed by a long high. This means we need to count the consecutive high samples (indicated by the value 1). But first we have to skip a start low pulse followed by a high pulse. The function that does this all is:
Code: Select all
def decode( inp):
res= [0]*5
bits=[]
ix = 0
try:
if inp[0] == 1 : ix = inp.index(0, ix) ## skip to first 0
ix = inp.index(1,ix) ## skip first 0's to next 1
ix = inp.index(0,ix) ## skip first 1's to next 0
while len(bits) < len(res)*8 : ##need 5 * 8 bits :
ix = inp.index(1,ix) ## index of next 1
ie = inp.index(0,ix) ## nr of 1's = ie-ix
bits.append(ie-ix)
ix = ie
except:
return( [0xff,0xff,0xff,0xff])
## … second part of function
After counting the consecutive number of 1's for 40 bits we now need to determine the exact value of each bit. This is a simple operation. If the count is larger than 2, the bit value is 1, and otherwise the bit value is 0. The second part of the convert function does this:
Code: Select all
def decode( inp):
## … first part of the function
for i in range(len(res)) :
for v in bits[i*8 : (i+1)*8] : #process next 8 bit
res[i] = res[i]<<1 ##shift byte one place to left
if v > 2 : res[i] = res[i]+1 ##and add 1 if lsb is 1
if (res[0]+res[1]+res[2]+res[3])&0xff != res[4] : ##parity error!
print("Checksum Error")
res= [0xff,0xff,0xff,0xff]
return(res[0:4])
Basically this is all we need to read humidity and temperature values from the DHT11 and DHT22 devices. But since the DHT22 gives a different meaning to the 4 byte result, we need to present the result differently, depending on the device. I therefore declared 2 additional functions:
Code: Select all
def DHT11(pin) :
res = decode(getval(pin))
print('Humidity = {},{}'.format(res[0],res[1]))
print('Temperat = {},{}'.format(res[2],res[3]))
#
def DHT22(pin) :
res = decode(getval(pin))
hum = res[0]*256+res[1]
tem = res[2]*256 + res[3]
if ( tem > 0x7fff ):
tem = 0x8000 - tem
print('Humidity = {},{}'.format(hum//10,hum%10))
print('Temperat = {},{}'.format(tem//10,tem%10))