DHT12 I2C multi-byte read

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
User avatar
mcauser
Posts: 507
Joined: Mon Jun 15, 2015 8:03 am

DHT12 I2C multi-byte read

Post by mcauser » Tue Jul 19, 2016 2:51 pm

I'm trying to port some Arduino C++ to MicroPython for my DHT12 I2C temperature sensor.
The DHT12 is a newer version of the DHT11 sensor, which adds I2C and improved accuracy.
It's backwards compatible with the DHT11 one wire interface when you tie SCL to GND.

The following works on my Arduino Uno:

Code: Select all

byte address = 0x5C
Wire.beginTransmission(address);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(address, 5);
a[0] = Wire.read();
a[1] = Wire.read();
a[2] = Wire.read();
a[3] = Wire.read();
a[4] = Wire.read();
The following is not working on my WeMos D1 mini, but I've managed to get this far:

Code: Select all

import ustruct
from machine import I2C, Pin
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000)
i2c.scan()
[92]

address = 92
register = 0
i2c.start()
i2c.write(ustruct.pack('<BH', address, register))
ustruct.unpack('BBBBB', i2c.readfrom(address,5))
I keep seeing "OSError: I2C bus error".
I've tried i2c.readinto(buf), i2c.readfrom(92, 5), i2c.readfrom_mem(92, 0, 5) and a bunch of other combinations.
Doesn't appear to be a memory mapping i2c sensor, instead more like RTC1307 multi-byte read.

Confusing part is the docs say the device address is 0xB8 (184), yet it is showing up in i2c.scan() as 92 (0x5C).
92 << 1 == 184.

I've went through these and tons of repos found on GitHub and BitBucket, and still can't get it working!
https://github.com/micropython/micropython/issues/2073
https://github.com/micropython/micropython/issues/1948
viewtopic.php?t=872
https://docs.python.org/3/library/struct.html

The Google-translated datasheet:
https://drive.google.com/file/d/0B1LcZm ... gxRjA/view

There are supposed to be 5 bytes returned:
0x00 = Humidity
0x01 = Humidity decimal places
0x02 = Temperature
0x03 = Temperature decimal places
0x04 = Checksum (sum 0x00,0x01,0x02,0x03)

Arduino example returns data like this:
45,6,24,0,75 - which means 45.6 %RH, 24.0 deg C, (valid checksum 45+6+24+0=75)
45,6,23,9,83 - which means 45.6 %RH, 23.9 deg C, (valid checksum 45+6+23+9=83)
45,7,23,9,84 - which means 45.7 %RH, 23.9 deg C, (valid checksum 45+7+23+9=84)

Little help?

User avatar
mcauser
Posts: 507
Joined: Mon Jun 15, 2015 8:03 am

Re: DHT12 I2C multi-byte read

Post by mcauser » Tue Jul 19, 2016 3:24 pm

Getting warmer...

Code: Select all

i2c.start()
i2c.write(ustruct.pack('B', 184))
i2c.start()
i2c.write(ustruct.pack('B', 185))
ustruct.unpack('BBBBB', i2c.readfrom(92, 5))
(255, 255, 247, 255, 255)

i2c.start()
i2c.write(ustruct.pack('B', 184))
i2c.write(ustruct.pack('B', 0))
i2c.start()
i2c.write(ustruct.pack('B', 185))
ustruct.unpack('BBBBB', i2c.readfrom(92, 5))
(1, 127, 251, 255, 255)
Last edited by mcauser on Tue Jul 19, 2016 3:33 pm, edited 1 time in total.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: DHT12 I2C multi-byte read

Post by deshipu » Tue Jul 19, 2016 3:33 pm

If you write the address to i2c bus yourself, you need to shift it left by one bit, and add a bit that determines whether you are reading or writing -- that's why you got a bus error -- there was simply no device with the address you specified.

Code: Select all

    def _get_reg16(self, address):
        self.i2c.start()
        self.i2c.write(ustruct.pack('>BH', self._address << 1, address))
        data = self.i2c.readfrom(self._address, 2)
        return ustruct.unpack('>B', data)[0]

User avatar
mcauser
Posts: 507
Joined: Mon Jun 15, 2015 8:03 am

Re: DHT12 I2C multi-byte read

Post by mcauser » Fri Jul 22, 2016 7:27 am

DHT12 works fine in 1-wire mode, aka DHT11 mode.

Code: Select all

import time, dht, machine
d = dht.DHT11(machine.Pin(4))
while True:
	d.measure()
	print(d.temperature(), d.humidity())
	time.sleep_ms(2000)

Post Reply