/** * Raspberry Pico / RP2040 library for DHT20 I2C temperature and humidity sensor * Ported from this Arduino library: https://github.com/RobTillaart/DHT20 by Rob Tillaart * * @author Johannes Braun * @version 0.1 * @url https://codeberg.org/hannenz/pico-dht20 */ #include "DHT20.h" #define millis() (to_ms_since_boot(get_absolute_time())) const uint8_t DHT20_ADDRESS = 0x38; DHT20::DHT20(int pin_sda, int pin_scl) { _temperature = 0; _humidity = 0; _humOffset = 0; _tempOffset = 0; _status = DHT20_OK; _lastRequest = 0; _lastRead = 0; // Setup / init I2C i2c_init(i2c_default, 100 * 1000); gpio_set_function(pin_sda, GPIO_FUNC_I2C); gpio_set_function(pin_scl, GPIO_FUNC_I2C); gpio_pull_up(pin_sda); gpio_pull_up(pin_scl); } bool DHT20::begin() { return isConnected(); } bool DHT20::isConnected() { return true; // don't know yet how to translate this, // some sort of sending a dummy byte and checking the return value? // _wire->beginTransmission(DHT20_ADDRESS); // int rv = _wire->endTransmission(); // return rv == 0; } uint8_t DHT20::getAddress() { return DHT20_ADDRESS; } // See datasheet 7.4 Sensor Reading Process, point 1 // use with care. uint8_t DHT20::resetSensor() { uint8_t count = 255; if ((readStatus() & 0x18) != 0x18) { count++; if (_resetRegister(0x1B)) count++; if (_resetRegister(0x1C)) count++; if (_resetRegister(0x1E)) count++; sleep_ms(10); } return count; } //////////////////////////////////////////////// // // READ THE SENSOR // int DHT20::read() { // do not read too fast == more than once per second. if (millis() - _lastRead < 1000) { return DHT20_ERROR_LASTREAD; } int status = requestData(); if (status < 0) { return status; } // wait for measurement ready uint32_t start = millis(); while (isMeasuring()) { if (millis() - start >= 1000) { return DHT20_ERROR_READ_TIMEOUT; } break; } // read the measurement status = readData(); if (status < 0) { return status; } // convert it to meaningful data return convert(); } int DHT20::requestData() { // reset sensor if needed. resetSensor(); // GET CONNECTION uint8_t buf[] = {0xAC, 0x33, 0x00}; int rv = i2c_write_blocking(i2c_default, DHT20_ADDRESS, buf, 3, false); _lastRequest = millis(); return rv; } int DHT20::readData() { // GET DATA const uint8_t length = 7; int bytes = i2c_read_blocking(i2c_default, DHT20_ADDRESS, _bits, length, false); if (bytes == 0) return DHT20_ERROR_CONNECT; if (bytes < length) return DHT20_MISSING_BYTES; bool allZero = true; for (int i = 0; i < bytes; i++) { allZero = allZero && (_bits[i] == 0); } if (allZero) return DHT20_ERROR_BYTES_ALL_ZERO; _lastRead = millis(); return bytes; } int DHT20::convert() { // CONVERT AND STORE _status = _bits[0]; uint32_t raw = _bits[1]; raw <<= 8; raw += _bits[2]; raw <<= 4; raw += (_bits[3] >> 4); _humidity = raw * 9.5367431640625e-5; // ==> / 1048576.0 * 100%; raw = (_bits[3] & 0x0F); raw <<= 8; raw += _bits[4]; raw <<= 8; raw += _bits[5]; _temperature = raw * 1.9073486328125e-4 - 50; // ==> / 1048576.0 * 200 - 50; // TEST CHECKSUM uint8_t _crc = _crc8(_bits, 6); if (_crc != _bits[6]) return DHT20_ERROR_CHECKSUM; return DHT20_OK; } //////////////////////////////////////////////// // // TEMPERATURE & HUMIDITY & OFFSET // float DHT20::getHumidity() { return _humidity + _humOffset; }; float DHT20::getTemperature() { return _temperature + _tempOffset; }; void DHT20::setHumOffset(float offset) { _humOffset = offset; }; void DHT20::setTempOffset(float offset) { _tempOffset = offset; }; float DHT20::getHumOffset() { return _humOffset; }; float DHT20::getTempOffset() { return _tempOffset; }; //////////////////////////////////////////////// // // STATUS // uint8_t DHT20::readStatus() { uint8_t byte; i2c_read_blocking(i2c_default, DHT20_ADDRESS, &byte, 1, false); return byte; } bool DHT20::isCalibrated() { return (readStatus() & 0x08) == 0x08; } bool DHT20::isMeasuring() { return (readStatus() & 0x80) == 0x80; } bool DHT20::isIdle() { return (readStatus() & 0x80) == 0x00; } int DHT20::internalStatus() { return _status; }; //////////////////////////////////////////////// // // TIMING // uint32_t DHT20::lastRead() { return _lastRead; }; uint32_t DHT20::lastRequest() { return _lastRequest; }; //////////////////////////////////////////////// // // PRIVATE // uint8_t DHT20::_crc8(uint8_t *ptr, uint8_t len) { uint8_t crc = 0xFF; while (len--) { crc ^= *ptr++; for (uint8_t i = 0; i < 8; i++) { if (crc & 0x80) { crc <<= 1; crc ^= 0x31; } else { crc <<= 1; } } } return crc; } // Code based on demo code sent by www.aosong.com // no further documentation. // 0x1B returned 18, 0, 4 // 0x1C returned 18, 65, 0 // 0x1E returned 18, 8, 0 // 18 seems to be status register // other values unknown. bool DHT20::_resetRegister(uint8_t reg) { uint8_t value[3]; value[0] = reg; value[1] = 0x00; value[2] = 0x00; int rv = i2c_write_blocking(i2c_default, DHT20_ADDRESS, value, 3, false); if (rv != 3) { return false; } sleep_ms(5); int bytes = i2c_read_blocking(i2c_default, DHT20_ADDRESS, value, 3, false); sleep_ms(10); value[0] = 0xB0; i2c_write_blocking(i2c_default, DHT20_ADDRESS, value, 3, false); sleep_ms(5); return true; }