DHT 11 sensor always return same value



  • Hi there!.

    I'm trying to use DHT11 sensor in my pycom+LoPy using different libraries and source code that I found in the forum. However, I'm not sure if the board is reading correctly or I have something wrong, because always return the same value (280.5 and 280.5 - temp and humi.).

    Anyone has have the same problem?. Thanks and best regards!.

    There is my source code (VDD is connected in Vin (I already tried with 3v3), GND in GND and Data in "G4"):

    from machine import enable_irq, disable_irq,  Pin
    import time
    
    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
    
    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])
    
        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])
    
    def DHT11(pin):
        res = decode(getval(pin))
        temp = 10*res[0] + res[1]
        hum = 10 * res[2] + res[3]
        return temp, hum
       
    def DHT22(pin) :
        res = decode(getval(pin))
        hum = res[0]*256+res[1]
        temp = res[2]*256 + res[3]
        if (temp > 0x7fff):
            temp = 0x8000 - temp
        return temp, hum   
    
    dht_pin=Pin('G4', mode=Pin.OPEN_DRAIN)
    dht_pin(1)
    
    temp, hum = DHT11(dht_pin)
    
    temp_str = '{}.{}'.format(temp//10,temp%10)
    hum_str = '{}.{}'.format(hum//10,hum%10)
    
    # Print or upload it
    print(temp_str, hum_str)
    


  • hello,
    if someone can try my dht11 class and say me if it works for him.
    It seems to be OK with a SiPy powered with USB .
    DHT11_PyCom

    Friendly, J.P



  • This post is deleted!


  • @robert-hh A slight re-arrangement of lines in getval() made the capture get the leading '0' bit. That also tells how critical the timing is. Still, even with IRQ disabled, sometimes transitions are missing.

    from machine import enable_irq, disable_irq,  Pin
    import time
    _LIMIT = const(8)
    _BUFFERSIZE = const(1000)
    
    def getval(pin) :
        ms = [1] * _BUFFERSIZE
        mslen = len(ms)
        pin(0)
        time.sleep_us(20000)
        pin(1)
        irqf = disable_irq()
        for _ in range(mslen):
            ms[_] = pin()      ## sample input and store value
        enable_irq(irqf)
        return ms
    
    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 Exception as err:
            print (err, ix, len(bits))
            return([0xff,0xff,0xff,0xff])
    
        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 > _LIMIT:
                    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])
    
    def DHT11(pin):
        res = decode(getval(pin))
        temp = 10 * res[0] + res[1]
        hum = 10 * res[2] + res[3]
        return temp, hum
    
    def DHT22(pin) :
        res = decode(getval(pin))
        hum = res[0]*256+res[1]
        temp = res[2]*256 + res[3]
        if (temp > 0x7fff):
            temp = 0x8000 - temp
        return temp, hum
    
    def run():
        dht_pin=Pin('G7', mode=Pin.OPEN_DRAIN)
        dht_pin(1)
    
        temp, hum = DHT11(dht_pin)
    
        temp_str = '{}.{}'.format(temp//10,temp%10)
        hum_str = '{}.{}'.format(hum//10,hum%10)
    
        # Print or upload it
        print(temp_str, hum_str)
    
    run()
    


  • @bihut I gave your code a try, and as @jmarcelino saidm

    • the port was wrong, and
    • the first trailing 0/1 change was not detected because python was busy with changing functions.
      The attached code works with my AM2302, which is identical to DHT22.
    from machine import enable_irq, disable_irq,  Pin
    import time
    _LIMIT = const(8)
    _BUFFERSIZE = const(1000)
    
    def getval(pin) :
        ms = [1] * _BUFFERSIZE
        pin(0)
        time.sleep_us(20000)
        pin(1)
        irqf = disable_irq()
        mslen = len(ms)
        for _ in range(mslen):
            ms[_] = pin()      ## sample input and store value
        enable_irq(irqf)
        return ms
    
    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 Exception as err:
            print (err, ix, len(bits))
            return([0xff,0xff,0xff,0xff])
    
        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 > _LIMIT:
                    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])
    
    def DHT11(pin):
        res = decode(getval(pin))
        temp = 10*res[0] + res[1]
        hum = 10 * res[2] + res[3]
        return temp, hum
    
    def DHT22(pin) :
        res = decode(getval(pin))
        hum = res[0]*256+res[1]
        temp = res[2]*256 + res[3]
        if (temp > 0x7fff):
            temp = 0x8000 - temp
        return temp, hum
    
    dht_pin=Pin('G7', mode=Pin.OPEN_DRAIN)
    dht_pin(1)
    
    temp, hum = DHT11(dht_pin)
    
    temp_str = '{}.{}'.format(temp//10,temp%10)
    hum_str = '{}.{}'.format(hum//10,hum%10)
    
    # Print or upload it
    print(temp_str, hum_str)
    

    It matches with a 10% difference with two cheap commercial temp/humidity devices I have, but I cannot tell which is right or wrong
    Update: After an hour of settling, the two sensors show almost identical readings.



  • @robert-hh
    Good catch, I was going by the datasheet which states 23ms for a read, but that includes the initial delay already accounted for in the code.

    So in summary @bihut :

    -Change power supplt to 3.3v
    -Use another Pin that isn't input only (so don't use G5, G4, G0, G3, G31, G30)



  • @jmarcelino If a cycle takes 20 µs, and the actual reading time is less than 5 ms (160 µs lead in and 40 bits at 120µs worst case), then 250 samples are sufficient. So with 300 takes the buffer is large enough. So taking the wrong Input is the first thing to change.



  • @robert-hh
    You don't need to look into the esp32 data sheet, it's on the LoPy pinout map with a red warning sign: https://docs.pycom.io/pycom_esp32/_downloads/lopy_pinout.pdf

    "Only Input pins!"

    The pinout map should really be required reading for everyone. Maybe the text could be made larger.

    By the way I tested the loop - you are absolutely right I was overlooking the loop and memory access involved - each cycle takes about 20 μS. So perhaps 1200 samples could be enough.



  • @jmarcelino Right, that's whatI wanted to check too. But at that point the docs at machine.pin should spend a few words about it. Normal users would not look into the esp32 data sheet.



  • Just noticed the original poster is also using G4 (P14) which is an input-only pin, so trying to set it high dht_pin(1) does nothing. This means the DHT11 is not initialising.



  • @jmarcelino The loop is a little bit slower than 1-2µs, because the loop management needs time too. But that has to be determined. So without real timing testing cou cannot get any results. There were people who managed to get this type of code working on ESP8266.
    Nevertheless, knowing about the irreular timing of the esp devices, it's better to use sensors with a stanard communication method.



  • @robert-hh
    Correct, 300 (not even 500) samples seems way too small for something like that.

    We saw in the pin interrupts experiments that toggling a Pin between (0) and (1) takes about 2-6 μS, so I'd expect reading should be similar maybe 1-2 μS.

    Total time for a reading from the DHT11 is 23.4 ms or 23400 μS so you really want to take and store at least the same (23400) samples to have a chance. (corrected in later reply, a buffer of 300 samples should suffice)

    Since we're only discerning between 28 μS (0) and 70 μS (1) pulses with 50 μS between them to me the more reasonable option is to simple add a small delay to the loop. But then you want to make sure it's properly calibrated/tested to the needs.

    0_1490782747130_CombinedTiming.jpg

    But again I'd strongly suggest moving on from the DHT11. It's a really cheap and nasty device. Anything that needs disabling IRQs especially in a LoRa device like the LoPy is a "bad idea"



  • @jmarcelino The code tries to perform a kind of digital sampling and then deduce the value from the samples time data. That assumes that during the loop the sampling is to some extend continuous. That's why IRQ's are disables. The whole DHT11 data takes about 40 ms. I'm not sure whther 500 samples are sufficient. That has to be determined. And the decoding looks wrong, if the ratio between sample timing and DHT11 timing is not known. The decoding here seems to assume a samping period of about 50 µs.



  • @bihut Is a pull-up resistor in the data line? 4k7 Ohm is reccomended. And does the raw data reading look reasonable?



  • Do not connect sensors powered by Vin/5V directly to the Pycom boards without a thorough understanding of what you're doing.

    The LoPy pins are not 5V tolerant so every time the DHT11 pulls up the data pin to it's Vcc (5V) you are killing your LoPy.

    After saying that - if you haven't destroyed your LoPy already - I can't see how your code would work

       for i in range(len(ms)):
            ms[i] = pin()      ## sample input and store value
    

    That's just loop without any timing/delays whatsoever so it's very likely the DHT hasn't updated the data line before you read it again.

    But I think the DHT11 is just too timing critical and not really suitable for the LoPy, you may solve your "always the same value " issue but won't get accurate results. Try one of the many I2C Temp/Humidity sensors instead like the Si7021.



  • This post is deleted!

Log in to reply
 

Pycom on Twitter