Interfacing with AM2320 on FiPy over I2C?
Has anyone had any success using the AM2320 on any of the pycom boards over i2c? I have been trying to interface with one using my FiPy and have only been able to receive errors. I have tried using various micropython libraries including ones by alexmrqt and mcauser. I always get some sort of OSError. I know my sensor works and is wired properly because I have been able to get accurate readings using a Raspberry Pi.
Here is the code I have to use the alexmrqt library:
i2c = I2C(0, I2C.MASTER) i2c = I2C(0, pins=('P10','P11')) i2c.init(I2C.MASTER, baudrate=100000) am = AM2320.AM2320(i2c) while True: pycom.rgbled(0x7f0000) # red try: temp = am.temperature humidity = am.relative_humidity print([str(temp), str(humidity)]) except OSError: # In case the sensor fails print(OSError) pass except RuntimeError: print(RuntimeError) pass pycom.rgbled(0x007f00) # green time.sleep(5)
And here is the driver itself:
# Driver code for AM2320 temperature and humidity sensor try: import struct except ImportError: import ustruct as struct import time from micropython import const __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/alexmrqt/Adafruit_CircuitPython_am2320.git" _AM2320_DEFAULT_ADDR = const(0x5C) _AM2320_CMD_READREG = const(0x03) _AM2320_REG_TEMP_H = const(0x02) _AM2320_REG_HUM_H = const(0x00) def _crc16(data): crc = 0xffff for byte in data: crc ^= byte for _ in range(8): if crc & 0x0001: crc >>= 1 crc ^= 0xA001 else: crc >>= 1 return crc class AM2320: """A driver for the AM2320 temperature and humidity sensor. :param i2c_bus: The `I2C` object to use. This is the only required parameter. :param int address: (optional) The I2C address of the device. """ def __init__(self, i2c_bus, address=_AM2320_DEFAULT_ADDR): self._i2c_bus = i2c_bus self._addr = address def _read_register(self, register, length): # wake up sensor self._i2c_bus.writeto(self._addr, bytes([0x00])) time.sleep(0.01) # wait 10 ms # Send command to read register cmd = [_AM2320_CMD_READREG, register & 0xFF, length] # print("cmd: %s" % [hex(i) for i in cmd]) self._i2c_bus.writeto(self._addr, bytes(cmd)) time.sleep(0.002) # wait 2 ms for reply result = bytearray(length+4) # 2 bytes pre, 2 bytes crc self._i2c_bus.readfrom_into(self._addr, result) # print("$%02X => %s" % (register, [hex(i) for i in result])) # Check preamble indicates correct readings if result != 0x3 or result != length: raise RuntimeError('I2C modbus read failure') # Check CRC on all but last 2 bytes crc1 = struct.unpack("<H", bytes(result[-2:])) crc2 = _crc16(result[0:-2]) if crc1 != crc2: raise RuntimeError('CRC failure 0x%04X vs 0x%04X' % (crc1, crc2)) return result[2:-2] @property def temperature(self): """The measured temperature in celsius.""" temperature = struct.unpack(">H", self._read_register(_AM2320_REG_TEMP_H, 2)) if temperature >= 32768: temperature = 32768 - temperature return temperature/10.0 @property def relative_humidity(self): """The measured relative humidity in percent.""" humidity = struct.unpack(">H", self._read_register(_AM2320_REG_HUM_H, 2)) return humidity/10.0
I have been searching everywhere but nobody seems to have any info on combining the AM2320 with the pycom boards. Any help would be greatly appreciated!
robert-hh last edited by
@zwarcola No clue, and I cannot test since I do not have that sensor here. Reading the data sheet it seems important, that SCL is pulled high during power up of the device, since that defines, whether the sensor runs in I2C mode or the old Single-Wire mode of the AM2302/DHT11.
@robert-hh Hey Robert, sorry for the delayed response. So I have been toying with the i2c sensor a little more. After changing the initialization of the i2c device and adding pull-up resistors, I am still getting a blank list of addresses "" and am unable to read values from it either.
Here is my updated i2c initialization:
i2c = I2C(0, I2C.MASTER, baudrate=100000, pins=('P10','P11'))
robert-hh last edited by robert-hh
@zwarcola I see the problem. The call to i2c.init() resets the pin definition. Just drop that call and add baudrate=100000 to the constructor call for i2c, or add pins=() to the init call.
That's subtle pitfall in the code, for SPI and other interfaces too. The constructor and init() share the same init code, which means, you have to do all initialization in a single call.
robert-hh last edited by robert-hh
@zwarcola Do you have added pull-up resistors? If yes, what is the result to i2c.scan()? Does that report the address of the device, which is 92?