diff --git a/README.md b/README.md index 07bbf94..06fcdec 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP32 ESP-IDF component for AHT family humidity & temperature sensor +# ESP32 ESP-IDF zh_aht - Humidity & Temperature Sensor Component ## Wiki @@ -14,17 +14,10 @@ ## Features -1. Support of AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40. -2. Support some sensors on one device with [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a). - -## Attention - -For correct operation, please enable the following settings in the menuconfig: - -```text -I2C_ISR_IRAM_SAFE -I2C_MASTER_ISR_HANDLER_IN_IRAM -``` +1. Support of AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40 +2. Support multiple sensors on one device with [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a) +3. CRC8 data integrity verification +4. Error statistics tracking ## Using diff --git a/WIKI_EN.md b/WIKI_EN.md index f8f6daf..6fa98b5 100644 --- a/WIKI_EN.md +++ b/WIKI_EN.md @@ -24,7 +24,7 @@ The component is designed specifically for ESP32 microcontrollers and uses ESP-I ## Features -1. **Humidity and Temperature Measurement**: Reads humidity from 0 to 100% and temperature from -40 to +85°C +1. **Humidity and Temperature Measurement**: Reads humidity from 0 to 100% and temperature from -50 to +150°C 2. **I2C Interface**: Uses standard I2C protocol (400 kHz max frequency) 3. **Configurable I2C Address**: Supports 0x38, 0x39 and 0x44 addresses 4. **Multiple Model Support**: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40 @@ -330,9 +330,9 @@ void app_main(void) ## Technical Specifications | Parameter | Value | -|-----------|-------| +| ----------- | ------- | | **Humidity Range** | 0 - 100% | -| **Temperature Range** | -40 - +85°C | +| **Temperature Range** | -50 - +150°C | | **Humidity Resolution** | 0.01% | | **Temperature Resolution** | 0.01°C | | **I2C Address** | 0x38, 0x39, 0x44 | @@ -348,7 +348,7 @@ void app_main(void) ## Error Codes | Error Code | Description | -|------------|-------------| +| ------------ | ------------- | | `ESP_OK` | Operation successful | | `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or invalid configuration) | | `ESP_ERR_INVALID_STATE` | Sensor is already initialized | diff --git a/WIKI_RU.md b/WIKI_RU.md index 30a1ab9..41ac88e 100644 --- a/WIKI_RU.md +++ b/WIKI_RU.md @@ -16,7 +16,7 @@ ## Обзор -`zh_aht` - это легковесный компонент ESP-IDF для датчиков влажности и температуры AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40. Он предоставляет простой API для считывания значений влажности от 0 до 100% и температуры от -40 до +85°C. Компонент поддерживает несколько датчиков на одной шине I2C с использованием I2C мультиплексатора [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a). +`zh_aht` - это легковесный компонент ESP-IDF для датчиков влажности и температуры AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40. Он предоставляет простой API для считывания значений влажности от 0 до 100% и температуры от -50 до +150°C. Компонент поддерживает несколько датчиков на одной шине I2C с использованием I2C мультиплексатора [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a). Компонент разработан специально для микроконтроллеров ESP32 и использует API драйвера I2C ESP-IDF v5.0+. @@ -330,9 +330,9 @@ void app_main(void) ## Технические характеристики | Параметр | Значение | -|----------|----------| +| ---------- | ---------- | | **Диапазон влажности** | 0 - 100% | -| **Диапазон температуры** | -40 - +85°C | +| **Диапазон температуры** | -50 - +150C | | **Разрешение измерения влажности** | 0.01% | | **Разрешение измерения температуры** | 0.01°C | | **Адрес I2C** | 0x38, 0x39, 0x44 | @@ -348,7 +348,7 @@ void app_main(void) ## Коды ошибок | Код ошибки | Описание | -|------------|----------| +| ------------ | ---------- | | `ESP_OK` | Операция выполнена успешно | | `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или неверная конфигурация) | | `ESP_ERR_INVALID_STATE` | Датчик уже инициализирован | diff --git a/include/zh_aht.h b/include/zh_aht.h index 25dda48..5064df1 100644 --- a/include/zh_aht.h +++ b/include/zh_aht.h @@ -1,14 +1,19 @@ /** * @file zh_aht.h * - * @brief ESP-IDF driver for AHT family sensors (AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40). + * @brief Driver for AHT series temperature and humidity sensors (AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40) * - * This module provides a high-level interface to control AHT family I2C temperature & humidity sensors. - * All devices (AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40) share the same command set, data format, and CRC algorithm. + * Provides I2C-based communication with AHT sensors including initialization, + * data reading with CRC validation, reset functionality, and error statistics. * - * @note Supported devices: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40, and compatible clones. - * @note Default I2C address: 0x38 (ADR tied to GND). Some variants (e.g., AHT20/30 on certain boards) may use 0x39 (ADR tied to VDD). For AHT40 use 0x44. - * @note Measurement range and accuracy differ between variants, but communication protocol is identical. + * Key features: + * - I2C interface with configurable address and frequency + * - Automatic sensor initialization and probe detection + * - CRC8 data integrity verification + * - Error statistics tracking + * + * @note Requires ESP-IDF v5.0+ with I2C master driver + * @note Enable I2C_ISR_IRAM_SAFE and I2C_MASTER_ISR_HANDLER_IN_IRAM in menuconfig */ #pragma once @@ -18,14 +23,6 @@ #include "driver/i2c_master.h" #include "freertos/FreeRTOS.h" -/** - * @brief Default AHT initialization configuration. - * - * @note I2C frequency: 400 kHz (fast mode — supported by all AHT variants). - * @note I2C address: 0x38 (ADR = GND). If ADR is pulled high (VDD), use 0x39. For AHT40 use 0x44. - * - * @warning AHT20/30 may be configured to 0x39 by hardware — check your board! - */ #define ZH_AHT_INIT_CONFIG_DEFAULT() \ { \ .i2c_frequency = 400000, \ @@ -36,100 +33,99 @@ extern "C" { #endif - /** - * @brief Opaque handle type for AHT family sensor instance. - */ typedef struct _zh_aht_handle_t zh_aht_handle_t; /** - * @brief AHT sensor initialization configuration structure. + * @brief Configuration structure for AHT sensor initialization */ typedef struct { - i2c_master_bus_handle_t i2c_handle; /*!< I2C bus handle (created via i2c_master_bus_create() or i2c_master_bus_alloc_handle()). */ - uint8_t i2c_address; /*!< I2C address: 0x38 (ADR=GND) or 0x39 (ADR=VDD) or 0x44 (AHT40). */ - uint32_t i2c_frequency; /*!< I2C clock frequency in Hz (≤ 400000). */ + i2c_master_bus_handle_t i2c_handle; /*!< I2C bus handle for sensor connection */ + uint8_t i2c_address; /*!< I2C device address (0x38, 0x39, or 0x44) */ + uint32_t i2c_frequency; /*!< I2C clock frequency (up to 400000 Hz) */ } zh_aht_init_config_t; /** - * @brief Error statistics structure. + * @brief Structure containing sensor error statistics */ typedef struct { - uint32_t i2c_driver_error; /*!< Number of I2C errors in zh_aht_read()/zh_aht_reset(). */ + uint32_t i2c_driver_error; /*!< Counter of I2C driver errors */ } zh_aht_stats_t; /** - * @brief Initialize an AHT family sensor and allocate handle. + * @brief Initialize AHT sensor and establish I2C communication * - * Validates configuration, allocates handle, registers device, probes sensor, and triggers calibration if needed. + * Allocates handle, configures I2C device, probes sensor presence, + * and sends initialization command if required. * - * @param[in] config Pointer to initialized configuration (must be non `NULL`, valid). - * @param[out] handle Double pointer to handle structure (`zh_aht_handle_t **`). On success, `*handle` points to newly allocated structure. + * @param[in] config Pointer to initialization configuration (must not be NULL) + * @param[out] handle Pointer to receive the created sensor handle (must be NULL) * - * @return ESP_OK on success. - * @return ESP_ERR_INVALID_ARG if `config == NULL` or `handle == NULL`. - * @return ESP_ERR_INVALID_STATE if `*handle != NULL` (already initialized). - * @return ESP_ERR_NO_MEM if handle allocation failed. - * @return ESP_FAIL if I2C registration failed. - * @return ESP_ERR_NOT_FOUND if sensor did not respond. + * @return ESP_OK on success + * @return ESP_ERR_INVALID_ARG if configuration parameters are invalid + * @return ESP_ERR_INVALID_STATE if handle is already initialized + * @return ESP_ERR_NO_MEM if memory allocation fails + * @return ESP_FAIL if I2C initialization fails */ esp_err_t zh_aht_init(const zh_aht_init_config_t *config, zh_aht_handle_t **handle); /** - * @brief Deinitialize the AHT sensor and release resources. + * @brief Deinitialize AHT sensor and release resources * - * Removes I2C device, frees handle, sets `*handle = NULL`. + * Removes I2C device and frees the sensor handle. * - * @param[in,out] handle Double pointer to handle structure (`zh_aht_handle_t **`). Must not be `NULL`. Set to `NULL` on exit. + * @param[in,out] handle Pointer to sensor handle to deinitialize (must not be NULL) * - * @return ESP_OK on success. - * @return ESP_ERR_INVALID_ARG if `handle == NULL` or `*handle == NULL` (not initialized). - * @return ESP_FAIL if failed to remove I2C device. + * @return ESP_OK on success + * @return ESP_ERR_INVALID_ARG if handle is NULL */ esp_err_t zh_aht_deinit(zh_aht_handle_t **handle); /** - * @brief Trigger measurement and read temperature & humidity. + * @brief Read humidity and temperature from AHT sensor * - * Sends read command, waits 80 ms, validates CRC/status, and converts to physical units. + * Sends read command, receives 7-byte response with CRC validation, + * and converts raw data to engineering units. * - * @param[in] handle Double pointer to handle structure (`zh_aht_handle_t **`). Must not be `NULL`. - * @param[out] humidity Pointer to store humidity (%RH). - * @param[out] temperature Pointer to store temperature (°C). + * @param[in] handle Pointer to sensor handle (must not be NULL) + * @param[out] humidity Pointer to store humidity value in percentage (0-100%) (must not be NULL) + * @param[out] temperature Pointer to store temperature value in Celsius (-50 to +150°C) (must not be NULL) * - * @return ESP_OK on success. - * @return ESP_ERR_INVALID_ARG if `handle == NULL` or `*handle == NULL` (not initialized) or `humidity == NULL` or `temperature == NULL`. - * @return ESP_FAIL if I2C error. - * @return ESP_ERR_TIMEOUT if sensor still busy. - * @return ESP_ERR_INVALID_CRC if CRC mismatch. + * @return ESP_OK on success + * @return ESP_ERR_INVALID_ARG if parameters are NULL + * @return ESP_ERR_TIMEOUT if sensor does not respond within timeout + * @return ESP_ERR_INVALID_CRC if data integrity check fails + * @return ESP_FAIL on I2C communication errors */ esp_err_t zh_aht_read(zh_aht_handle_t **handle, float *humidity, float *temperature); /** - * @brief Soft reset the AHT sensor. + * @brief Reset AHT sensor via I2C command * - * Sends reset command and waits 20 ms for recovery. + * Sends reset command and waits for sensor recovery. * - * @param[in] handle Double pointer to handle structure (`zh_aht_handle_t **`). Must not be `NULL`. + * @param[in] handle Pointer to sensor handle (must not be NULL) * - * @return ESP_OK on success. - * @return ESP_ERR_INVALID_ARG if `handle == NULL` or `*handle == NULL` (not initialized). - * @return ESP_FAIL if I2C error. + * @return ESP_OK on success + * @return ESP_ERR_INVALID_ARG if handle is NULL + * @return ESP_FAIL on I2C communication errors */ esp_err_t zh_aht_reset(zh_aht_handle_t **handle); /** - * @brief Get pointer to internal error statistics. + * @brief Get pointer to sensor error statistics * - * @return Pointer to static statistics structure. + * Returns read-only pointer to global statistics structure. + * + * @return Pointer to statistics structure (valid until reset) */ const zh_aht_stats_t *zh_aht_get_stats(void); /** - * @brief Reset error statistics counter. + * @brief Reset all error statistics to zero * - * Sets `i2c_driver_error = 0`. + * Clears all error counters tracked in the global statistics structure. */ void zh_aht_reset_stats(void); diff --git a/zh_aht.c b/zh_aht.c index cb96e8f..3957b21 100644 --- a/zh_aht.c +++ b/zh_aht.c @@ -14,39 +14,56 @@ static const char *TAG = "zh_aht"; } /** - * @brief Opaque handle structure for the AHT family sensor (AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40). + * @brief Handle structure for AHT sensor. * - * This structure encapsulates the I2C device handle required to communicate with any sensor - * in the AHT family. All AHT sensors share the same I2C protocol, register map, and CRC algorithm. - * - * @note Supported devices: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40, and compatible clones. - * @note Default I2C addresses: - * - AHT10: 0x38 (ADR tied to GND) - * - AHT20/30: 0x38 (ADR tied to GND), 0x39 (ADR tied to VDD) - * - AHT40: 0x44 - * @note Some variants may differ in measurement range and accuracy, but not in communication protocol. - * - * @note Do not instantiate or modify this structure directly. All interactions must go through - * the public API functions: zh_aht_init(), zh_aht_read(), zh_aht_deinit(), etc. + * Internal structure managing the I2C device connection. */ struct _zh_aht_handle_t { - i2c_master_dev_handle_t dev_handle; /*!< I2C device handle (ESP-IDF i2c_master API) used for all bus transactions. */ + i2c_master_dev_handle_t dev_handle; /*!< I2C device handle for sensor communication */ }; -/** - * @brief AHT family command constants. - * - * @note All AHT family members (AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40) support these commands. - * @note CRC algorithm, data format, and command structure are identical across family. - */ -static const uint8_t _aht_reset_command = 0xBA; /*!< Soft reset command (AHT family common). */ -static const uint8_t _aht_read_command[] = {0xAC, 0x33, 0x00}; /*!< Trigger measurement and read data command. Format: 0xAC (measurement trigger) + 0x33 (normal mode) + 0x00 (unused byte). */ -static const uint8_t _aht_init_command[] = {0xBE, 0x08, 0x00}; /*!< Self-calibration/initialization command (must be sent if CALIBRATED bit (status[3]) = 0). */ -static zh_aht_stats_t _stats = {0}; +static const uint8_t _aht_reset_command = 0xBA; /*!< Reset command for AHT sensor */ +static const uint8_t _aht_read_command[] = {0xAC, 0x33, 0x00}; /*!< Command sequence to initiate sensor data read */ +static const uint8_t _aht_init_command[] = {0xBE, 0x08, 0x00}; /*!< Command sequence to configure sensor for normal operation */ +static zh_aht_stats_t _stats = {0}; /*!< Global statistics structure for error tracking */ +/** + * @brief Validate initialization configuration. + * + * Checks I2C address, frequency, and handle validity. + * + * @param config Pointer to initialization configuration + * + * @return ESP_OK on success + * @return ESP_ERR_INVALID_ARG if any configuration parameter is invalid + */ static esp_err_t _zh_aht_validate_config(const zh_aht_init_config_t *config); + +/** + * @brief Initialize I2C communication with AHT sensor. + * + * Configures I2C device, probes sensor, and performs initialization command if needed. + * + * @param config Pointer to initialization configuration + * @param handle Pointer to handle structure to store device handle + * + * @return ESP_OK on success + * @return ESP_FAIL on I2C communication errors + * @return ESP_ERR_NOT_FOUND if sensor is not detected + */ static esp_err_t _zh_aht_i2c_init(const zh_aht_init_config_t *config, zh_aht_handle_t *handle); + +/** + * @brief Calculate CRC8 for data validation. + * + * Implements CRC8 algorithm using polynomial 0x31 for sensor data integrity check. + * + * @param buf Pointer to data buffer + * @param len Length of data buffer + * + * @return Calculated CRC8 value + */ static uint8_t _zh_aht_calc_crc(const uint8_t *buf, size_t len); esp_err_t zh_aht_init(const zh_aht_init_config_t *config, zh_aht_handle_t **handle) // -V2008 @@ -166,4 +183,4 @@ static uint8_t _zh_aht_calc_crc(const uint8_t *buf, size_t len) } } return crc; -} \ No newline at end of file +}