#pragma once /** * humidity and temperature sensor * https://asairsensors.com/wp-content/uploads/2021/09/Data-Sheet-AHT21-Humidity-and-Temperature-Sensor-ASAIR-V1.0.03.pdf */ template class AHT2x { private: I2C& i2c; static constexpr const uint8_t ADDR = 0x38; static constexpr const char* NAME = "AHT2x"; static constexpr const uint8_t BIT_BUSY = 0x80; static constexpr const uint8_t BIT_CALIBRATED = 0x08; public: struct Result { float temp; float humi; }; public: AHT2x(I2C& i2c) : i2c(i2c) { } void init() { softReset(); int ok = calibrate(); printf("aht calib: %d\n", ok); } /** is the device present on the bus? */ bool isPresent() { return i2c.query(ADDR); } void softReset() { uint8_t cmd = 0xBA; i2c.writeRaw(ADDR, 1, &cmd); DELAY_MS(100); } bool calibrate() { uint8_t cmdCalibrate[3] = {0xBE, 0x08, 0x00}; i2c.writeRaw(ADDR, 3, cmdCalibrate); waitUntilDone(); return readStatus() & BIT_CALIBRATED; } void waitUntilDone() { for (uint8_t i = 0; i < 200; ++i) { printf("."); if (!(readStatus() & BIT_BUSY)) {break;} DELAY_MS(1); } printf("x\n"); } uint8_t readStatus() { uint8_t status = 0; i2c.readRaw(ADDR, 1, &status); return status; } Result measure() { // trigger measurement uint8_t cmdMeasure[3] = {0xAC, 0x33, 0x00}; i2c.writeRaw(ADDR, 3, cmdMeasure); // fetch result, also waits until the busy-bit is cleared uint8_t raw[6]; for(uint8_t i = 0; i < 50; ++i) { DELAY_MS(10); i2c.readRaw(ADDR, 6, raw); bool busy = (raw[0] & BIT_BUSY); if (!busy) {break;} } // calculate Result res; uint32_t _humi = ((raw[1] << 16) | (raw[2] << 8) | (raw[3] << 0)) >> 4; res.humi = _humi * 100 / 1048576.0f; uint32_t _temp = ((raw[3] & 0x0F) << 16) | (raw[4] << 8) | (raw[5] << 0); res.temp = (_temp * 200 / 1048576.0f) - 50; return res; } };