diff --git a/components/i2c_master_messager/CMakeLists.txt b/components/i2c_master_messager/CMakeLists.txt index dbe9bc9..44a4ad5 100644 --- a/components/i2c_master_messager/CMakeLists.txt +++ b/components/i2c_master_messager/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRCS "i2c_master_messager.c" INCLUDE_DIRS "include" - REQUIRES bh1750 esp_driver_i2c esp_driver_gpio esp_timer + REQUIRES bh1750 k0i05__esp_ahtxx esp_driver_i2c esp_driver_gpio esp_timer ) diff --git a/components/i2c_master_messager/Kconfig.projbuild b/components/i2c_master_messager/Kconfig.projbuild new file mode 100644 index 0000000..01e4217 --- /dev/null +++ b/components/i2c_master_messager/Kconfig.projbuild @@ -0,0 +1,38 @@ +menu "I2C 传感器管理" + +config I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP + bool "启用 I2C 内部上拉电阻" + default y + help + 启用后,SCL/SDA 会使用芯片内部上拉。 + 如果你的硬件已经有外部上拉电阻,通常也可以关闭该选项。 + +config I2C_MASTER_MESSAGER_BH1750_ENABLE + bool "启用 BH1750 光照传感器" + default y + help + 关闭后将不会初始化与读取 BH1750。 + +config I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS + int "BH1750 采样周期 (ms)" + range 100 10000 + default 500 + depends on I2C_MASTER_MESSAGER_BH1750_ENABLE + help + BH1750 的轮询间隔,单位毫秒。 + +config I2C_MASTER_MESSAGER_AHT30_ENABLE + bool "启用 AHT30 温湿度传感器" + default y + help + 关闭后将不会初始化与读取 AHT30。 + +config I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS + int "AHT30 采样周期 (ms)" + range 100 10000 + default 2000 + depends on I2C_MASTER_MESSAGER_AHT30_ENABLE + help + AHT30 的轮询间隔,单位毫秒。 + +endmenu diff --git a/components/i2c_master_messager/README.md b/components/i2c_master_messager/README.md index e52befc..83fe4ac 100644 --- a/components/i2c_master_messager/README.md +++ b/components/i2c_master_messager/README.md @@ -3,13 +3,22 @@ `i2c_master_messager` 用于统一管理工程中的 I2C 传感器。 当前已接入: -- BH1750 光照传感器(默认地址 `0x23`) +- BH1750 光照传感器(使用驱动默认地址) +- AHT30 温湿度传感器(使用驱动默认地址) 设计目标: - 提供统一的数据结构,方便其他模块读取 - 提供独立采集任务,周期性更新数据 - 为后续新增其他 I2C 传感器预留扩展位置 +- 各传感器驱动相互独立,管理层只做调度与数据汇总 +- 支持每个传感器独立采样周期(例如光照快采、温湿度慢采) + +## 驱动分层 + +- `k0i05__esp_ahtxx`:AHT30 驱动组件(通过组件管理器引入) +- `bh1750`:使用 ESP 组件管理器驱动 +- `i2c_master_messager.c`:统一总线管理、任务轮询、线程安全数据缓存 ## 对外数据结构 @@ -20,13 +29,18 @@ - `bh1750.valid`:当前数据是否有效 - `bh1750.last_update_ms`:最后一次成功更新时间(毫秒) - `bh1750.last_error`:最后一次采集错误码 + - `aht30.temperature_c`:温度(摄氏度) + - `aht30.humidity_rh`:湿度(%RH) + - `aht30.valid`:当前数据是否有效 + - `aht30.last_update_ms`:最后一次成功更新时间(毫秒) + - `aht30.last_error`:最后一次采集错误码 后续新增传感器时,建议继续在 `i2c_master_messager_data_t` 中增加对应字段。 ## API - `esp_err_t i2c_master_messager_init(const i2c_master_messager_config_t *config);` - - 初始化 I2C 总线和 BH1750 + - 初始化 I2C 总线(传感器驱动在任务中懒初始化) - `esp_err_t i2c_master_messager_start(void);` - 启动循环采集任务 - `esp_err_t i2c_master_messager_stop(void);` @@ -36,6 +50,18 @@ - `esp_err_t i2c_master_messager_deinit(void);` - 释放总线和传感器资源 +## menuconfig 配置 + +路径:`Component config -> I2C Master Messager` + +- `启用 BH1750 光照传感器`:开关 BH1750 +- `启用 I2C 内部上拉电阻`:控制是否打开芯片内部上拉 +- `BH1750 采样周期 (ms)`:光照采样周期 +- `启用 AHT30 温湿度传感器`:开关 AHT30 +- `AHT30 采样周期 (ms)`:温湿度采样周期 + +这两个周期相互独立,可按业务需求分别调优。 + ## 使用示例 ```c @@ -46,10 +72,13 @@ void app_main(void) { i2c_master_messager_config_t cfg = { .i2c_port = I2C_NUM_0, - .scl_io_num = GPIO_NUM_5, - .sda_io_num = GPIO_NUM_4, - .read_period_ms = 1000, - .bh1750_addr = 0x23, + .scl_io_num = GPIO_NUM_5, + .sda_io_num = GPIO_NUM_4, + .i2c_enable_internal_pullup = true, + .bh1750_enable = true, + .aht30_enable = true, + .bh1750_read_period_ms = 500, + .aht30_read_period_ms = 2000, .bh1750_mode = BH1750_CONTINUE_1LX_RES, }; @@ -58,8 +87,11 @@ void app_main(void) while (1) { i2c_master_messager_data_t data; - if (i2c_master_messager_get_data(&data) == ESP_OK && data.bh1750.valid) { - printf("BH1750: %.2f lx\n", data.bh1750.lux); + if (i2c_master_messager_get_data(&data) == ESP_OK && data.bh1750.valid && data.aht30.valid) { + printf("BH1750: %.2f lx, AHT30: %.2f C %.2f %%RH\n", + data.bh1750.lux, + data.aht30.temperature_c, + data.aht30.humidity_rh); } vTaskDelay(pdMS_TO_TICKS(1000)); } @@ -72,6 +104,6 @@ void app_main(void) 1. 在 `i2c_master_messager_data_t` 中增加该传感器的数据结构 2. 在 `i2c_master_messager_config_t` 中增加该传感器配置项 -3. 在 `i2c_master_messager_init()` 中完成驱动初始化 +3. 在任务循环中按需完成驱动初始化与重试 4. 在采集任务中加入周期读取逻辑并更新共享数据 5. 在 `deinit()` 中释放对应资源 diff --git a/components/i2c_master_messager/i2c_master_messager.c b/components/i2c_master_messager/i2c_master_messager.c index f591d48..936b36e 100644 --- a/components/i2c_master_messager/i2c_master_messager.c +++ b/components/i2c_master_messager/i2c_master_messager.c @@ -1,6 +1,7 @@ #include #include "driver/i2c_master.h" +#include "ahtxx.h" #include "esp_check.h" #include "esp_log.h" #include "esp_timer.h" @@ -10,12 +11,18 @@ #include "i2c_master_messager.h" static const char *TAG = "i2c_master_messager"; +#define BH1750_REINIT_INTERVAL_MS (3000) +#define AHT30_REINIT_INTERVAL_MS (3000) typedef struct { bool initialized; + bool owns_i2c_bus; + bool bh1750_ready; + bool aht30_ready; i2c_master_messager_config_t config; i2c_master_bus_handle_t i2c_bus; bh1750_handle_t bh1750; + ahtxx_handle_t aht30; i2c_master_messager_data_t data; SemaphoreHandle_t lock; TaskHandle_t task_handle; @@ -23,38 +30,175 @@ typedef struct { static i2c_master_messager_ctx_t g_ctx; +static esp_err_t i2c_master_messager_try_init_bh1750(void) +{ + if (!g_ctx.config.bh1750_enable) { + return ESP_ERR_NOT_SUPPORTED; + } + + if (g_ctx.bh1750 != NULL) { + bh1750_delete(g_ctx.bh1750); + g_ctx.bh1750 = NULL; + } + + esp_err_t ret = bh1750_create(g_ctx.i2c_bus, BH1750_I2C_ADDRESS_DEFAULT, &g_ctx.bh1750); + if (ret != ESP_OK) { + return ret; + } + + ret = bh1750_power_on(g_ctx.bh1750); + if (ret != ESP_OK) { + bh1750_delete(g_ctx.bh1750); + g_ctx.bh1750 = NULL; + return ret; + } + + ret = bh1750_set_measure_mode(g_ctx.bh1750, g_ctx.config.bh1750_mode); + if (ret != ESP_OK) { + bh1750_delete(g_ctx.bh1750); + g_ctx.bh1750 = NULL; + return ret; + } + + g_ctx.bh1750_ready = true; + return ESP_OK; +} + +static esp_err_t i2c_master_messager_try_init_aht30(void) +{ + if (!g_ctx.config.aht30_enable) { + return ESP_ERR_NOT_SUPPORTED; + } + + if (g_ctx.aht30 != NULL) { + ahtxx_delete(g_ctx.aht30); + g_ctx.aht30 = NULL; + } + + ahtxx_config_t aht_cfg = I2C_AHT30_CONFIG_DEFAULT; + esp_err_t ret = ahtxx_init(g_ctx.i2c_bus, &aht_cfg, &g_ctx.aht30); + if (ret != ESP_OK) { + return ret; + } + + g_ctx.aht30_ready = true; + return ESP_OK; +} + static void i2c_master_messager_task(void *arg) { (void)arg; + int64_t last_bh1750_reinit_ms = 0; + int64_t last_bh1750_read_ms = 0; + int64_t last_aht30_read_ms = 0; + int64_t last_aht30_reinit_ms = 0; while (1) { - float lux = 0.0f; - esp_err_t ret = bh1750_get_data(g_ctx.bh1750, &lux); + int64_t now_ms = esp_timer_get_time() / 1000; - if (xSemaphoreTake(g_ctx.lock, pdMS_TO_TICKS(100)) == pdTRUE) { - g_ctx.data.bh1750.valid = (ret == ESP_OK); - g_ctx.data.bh1750.last_error = ret; - if (ret == ESP_OK) { - g_ctx.data.bh1750.lux = lux; - g_ctx.data.bh1750.last_update_ms = esp_timer_get_time() / 1000; + if (g_ctx.config.bh1750_enable && !g_ctx.bh1750_ready && + (now_ms - last_bh1750_reinit_ms) >= BH1750_REINIT_INTERVAL_MS) { + last_bh1750_reinit_ms = now_ms; + esp_err_t init_ret = i2c_master_messager_try_init_bh1750(); + if (init_ret == ESP_OK) { + ESP_LOGI(TAG, "BH1750 reinit success"); + } else { + ESP_LOGW(TAG, "BH1750 reinit failed: %s", esp_err_to_name(init_ret)); + if (xSemaphoreTake(g_ctx.lock, pdMS_TO_TICKS(100)) == pdTRUE) { + g_ctx.data.bh1750.valid = false; + g_ctx.data.bh1750.last_error = init_ret; + xSemaphoreGive(g_ctx.lock); + } } - xSemaphoreGive(g_ctx.lock); } - if (ret != ESP_OK) { - ESP_LOGW(TAG, "bh1750_get_data failed: %s", esp_err_to_name(ret)); + if (g_ctx.bh1750_ready && g_ctx.bh1750 != NULL && + (now_ms - last_bh1750_read_ms) >= g_ctx.config.bh1750_read_period_ms) { + float lux = 0.0f; + esp_err_t bh1750_ret = bh1750_get_data(g_ctx.bh1750, &lux); + last_bh1750_read_ms = now_ms; + + if (xSemaphoreTake(g_ctx.lock, pdMS_TO_TICKS(100)) == pdTRUE) { + g_ctx.data.bh1750.valid = (bh1750_ret == ESP_OK); + g_ctx.data.bh1750.last_error = bh1750_ret; + if (bh1750_ret == ESP_OK) { + g_ctx.data.bh1750.lux = lux; + g_ctx.data.bh1750.last_update_ms = now_ms; + } + xSemaphoreGive(g_ctx.lock); + } + + if (bh1750_ret != ESP_OK) { + ESP_LOGW(TAG, "bh1750_get_data failed: %s", esp_err_to_name(bh1750_ret)); + } } - vTaskDelay(pdMS_TO_TICKS(g_ctx.config.read_period_ms)); + if (g_ctx.config.aht30_enable && !g_ctx.aht30_ready && + (now_ms - last_aht30_reinit_ms) >= AHT30_REINIT_INTERVAL_MS) { + last_aht30_reinit_ms = now_ms; + esp_err_t init_ret = i2c_master_messager_try_init_aht30(); + if (init_ret == ESP_OK) { + ESP_LOGI(TAG, "AHT30 reinit success"); + } else { + ESP_LOGW(TAG, "AHT30 reinit failed: %s", esp_err_to_name(init_ret)); + if (xSemaphoreTake(g_ctx.lock, pdMS_TO_TICKS(100)) == pdTRUE) { + g_ctx.data.aht30.valid = false; + g_ctx.data.aht30.last_error = init_ret; + xSemaphoreGive(g_ctx.lock); + } + } + } + + if (g_ctx.aht30_ready && g_ctx.aht30 != NULL && + (now_ms - last_aht30_read_ms) >= g_ctx.config.aht30_read_period_ms) { + float temperature_c = 0.0f; + float humidity_rh = 0.0f; + esp_err_t aht30_ret = ahtxx_get_measurement(g_ctx.aht30, &temperature_c, &humidity_rh); + last_aht30_read_ms = now_ms; + + if (xSemaphoreTake(g_ctx.lock, pdMS_TO_TICKS(100)) == pdTRUE) { + g_ctx.data.aht30.valid = (aht30_ret == ESP_OK); + g_ctx.data.aht30.last_error = aht30_ret; + if (aht30_ret == ESP_OK) { + g_ctx.data.aht30.temperature_c = temperature_c; + g_ctx.data.aht30.humidity_rh = humidity_rh; + g_ctx.data.aht30.last_update_ms = now_ms; + } + xSemaphoreGive(g_ctx.lock); + } + + if (aht30_ret != ESP_OK) { + ESP_LOGW(TAG, "ahtxx_get_measurement failed: %s", esp_err_to_name(aht30_ret)); + if (aht30_ret == ESP_ERR_INVALID_STATE || aht30_ret == ESP_ERR_TIMEOUT) { + if (g_ctx.aht30 != NULL) { + ahtxx_delete(g_ctx.aht30); + g_ctx.aht30 = NULL; + } + g_ctx.aht30_ready = false; + } + } + } + + vTaskDelay(pdMS_TO_TICKS(I2C_MASTER_MESSAGER_MIN_PERIOD_MS)); } } esp_err_t i2c_master_messager_init(const i2c_master_messager_config_t *config) { ESP_RETURN_ON_FALSE(config != NULL, ESP_ERR_INVALID_ARG, TAG, "config is null"); - ESP_RETURN_ON_FALSE(config->read_period_ms >= I2C_MASTER_MESSAGER_MIN_PERIOD_MS, + ESP_RETURN_ON_FALSE(config->bh1750_enable || config->aht30_enable, ESP_ERR_INVALID_ARG, TAG, - "read_period_ms too small"); + "at least one sensor must be enabled"); + ESP_RETURN_ON_FALSE(!config->bh1750_enable || + config->bh1750_read_period_ms >= I2C_MASTER_MESSAGER_MIN_PERIOD_MS, + ESP_ERR_INVALID_ARG, + TAG, + "bh1750_read_period_ms too small"); + ESP_RETURN_ON_FALSE(!config->aht30_enable || + config->aht30_read_period_ms >= I2C_MASTER_MESSAGER_MIN_PERIOD_MS, + ESP_ERR_INVALID_ARG, + TAG, + "aht30_read_period_ms too small"); if (g_ctx.initialized) { return ESP_ERR_INVALID_STATE; @@ -72,51 +216,68 @@ esp_err_t i2c_master_messager_init(const i2c_master_messager_config_t *config) .scl_io_num = config->scl_io_num, .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, - .flags.enable_internal_pullup = true, + .flags.enable_internal_pullup = config->i2c_enable_internal_pullup, }; esp_err_t ret = i2c_new_master_bus(&bus_cfg, &g_ctx.i2c_bus); if (ret != ESP_OK) { - vSemaphoreDelete(g_ctx.lock); - g_ctx.lock = NULL; - return ret; + if (ret == ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, + "i2c port %d already initialized, trying to reuse existing master bus", + config->i2c_port); + ret = i2c_master_get_bus_handle(config->i2c_port, &g_ctx.i2c_bus); + if (ret != ESP_OK || g_ctx.i2c_bus == NULL) { + ESP_LOGE(TAG, + "failed to reuse i2c bus on port %d: %s", + config->i2c_port, + esp_err_to_name(ret)); + vSemaphoreDelete(g_ctx.lock); + g_ctx.lock = NULL; + return (ret == ESP_OK) ? ESP_ERR_INVALID_STATE : ret; + } + g_ctx.owns_i2c_bus = false; + } else { + ESP_LOGE(TAG, "i2c_new_master_bus failed: %s", esp_err_to_name(ret)); + vSemaphoreDelete(g_ctx.lock); + g_ctx.lock = NULL; + return ret; + } + } else { + g_ctx.owns_i2c_bus = true; } - ret = bh1750_create(g_ctx.i2c_bus, config->bh1750_addr, &g_ctx.bh1750); - if (ret != ESP_OK) { - i2c_del_master_bus(g_ctx.i2c_bus); - g_ctx.i2c_bus = NULL; - vSemaphoreDelete(g_ctx.lock); - g_ctx.lock = NULL; - return ret; + if (!config->bh1750_enable) { + g_ctx.data.bh1750.valid = false; + g_ctx.data.bh1750.last_error = ESP_ERR_NOT_SUPPORTED; + } else { + g_ctx.data.bh1750.valid = false; + g_ctx.data.bh1750.last_error = ESP_ERR_INVALID_STATE; } - ESP_GOTO_ON_ERROR(bh1750_power_on(g_ctx.bh1750), err, TAG, "bh1750_power_on failed"); - ESP_GOTO_ON_ERROR(bh1750_set_measure_mode(g_ctx.bh1750, config->bh1750_mode), - err, - TAG, - "bh1750_set_measure_mode failed"); + if (!config->aht30_enable) { + g_ctx.data.aht30.valid = false; + g_ctx.data.aht30.last_error = ESP_ERR_NOT_SUPPORTED; + } else { + g_ctx.data.aht30.valid = false; + g_ctx.data.aht30.last_error = ESP_ERR_INVALID_STATE; + } - g_ctx.data.bh1750.valid = false; - g_ctx.data.bh1750.last_error = ESP_ERR_INVALID_STATE; g_ctx.initialized = true; ESP_LOGI(TAG, - "initialized: port=%d scl=%d sda=%d addr=0x%02X period=%u ms", + "initialized: port=%d scl=%d sda=%d pullup_int=%d bh1750(en=%d,ready=%d,default,%ums) aht30(en=%d,ready=%d,default,%ums)", config->i2c_port, config->scl_io_num, config->sda_io_num, - config->bh1750_addr, - config->read_period_ms); + config->i2c_enable_internal_pullup, + config->bh1750_enable, + g_ctx.bh1750_ready, + config->bh1750_read_period_ms, + config->aht30_enable, + g_ctx.aht30_ready, + config->aht30_read_period_ms); + ESP_LOGI(TAG, + "i2c bus is ready; sensor drivers will initialize lazily in task loop"); return ESP_OK; - -err: - bh1750_delete(g_ctx.bh1750); - g_ctx.bh1750 = NULL; - i2c_del_master_bus(g_ctx.i2c_bus); - g_ctx.i2c_bus = NULL; - vSemaphoreDelete(g_ctx.lock); - g_ctx.lock = NULL; - return ret; } esp_err_t i2c_master_messager_start(void) @@ -174,11 +335,17 @@ esp_err_t i2c_master_messager_deinit(void) g_ctx.bh1750 = NULL; } - if (g_ctx.i2c_bus != NULL) { - i2c_del_master_bus(g_ctx.i2c_bus); - g_ctx.i2c_bus = NULL; + if (g_ctx.aht30 != NULL) { + ahtxx_delete(g_ctx.aht30); + g_ctx.aht30 = NULL; } + if (g_ctx.i2c_bus != NULL && g_ctx.owns_i2c_bus) { + i2c_del_master_bus(g_ctx.i2c_bus); + } + g_ctx.i2c_bus = NULL; + g_ctx.owns_i2c_bus = false; + if (g_ctx.lock != NULL) { vSemaphoreDelete(g_ctx.lock); g_ctx.lock = NULL; diff --git a/components/i2c_master_messager/include/i2c_master_messager.h b/components/i2c_master_messager/include/i2c_master_messager.h index c56dfe1..2d47c0b 100644 --- a/components/i2c_master_messager/include/i2c_master_messager.h +++ b/components/i2c_master_messager/include/i2c_master_messager.h @@ -16,8 +16,11 @@ typedef struct { i2c_port_num_t i2c_port; gpio_num_t scl_io_num; gpio_num_t sda_io_num; - uint16_t read_period_ms; - uint8_t bh1750_addr; + bool i2c_enable_internal_pullup; + bool bh1750_enable; + bool aht30_enable; + uint16_t bh1750_read_period_ms; + uint16_t aht30_read_period_ms; bh1750_measure_mode_t bh1750_mode; } i2c_master_messager_config_t; @@ -28,8 +31,17 @@ typedef struct { esp_err_t last_error; } i2c_bh1750_data_t; +typedef struct { + float temperature_c; + float humidity_rh; + bool valid; + int64_t last_update_ms; + esp_err_t last_error; +} i2c_aht30_data_t; + typedef struct { i2c_bh1750_data_t bh1750; + i2c_aht30_data_t aht30; } i2c_master_messager_data_t; #define I2C_MASTER_MESSAGER_MIN_PERIOD_MS (100) diff --git a/dependencies.lock b/dependencies.lock index a21ba95..78101a0 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -27,6 +27,30 @@ dependencies: source: type: idf version: 5.5.2 + k0i05/esp_ahtxx: + component_hash: 34ecd4cc05b54a8ee64a813f80cf2b8efea6f22ecdbf7244640fc29627416fed + dependencies: + - name: idf + require: private + version: '>5.3.0' + - name: k0i05/esp_type_utils + registry_url: https://components.espressif.com + require: private + version: '>=1.0.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.2.7 + k0i05/esp_type_utils: + component_hash: 95d8ec40268e045f7e264d8035f451e53844b4a2f6d5f112ece6645c5effd639 + dependencies: + - name: idf + require: private + version: '>5.3.0' + source: + registry_url: https://components.espressif.com + type: service + version: 1.2.7 lvgl/lvgl: component_hash: 184e532558c1c45fefed631f3e235423d22582aafb4630f3e8885c35281a49ae dependencies: [] @@ -38,6 +62,7 @@ direct_dependencies: - espressif/bh1750 - espressif/esp_lvgl_port - idf -manifest_hash: 1fd264456e89adf9729f55472d73dc1ff5c869e32bf39dd97a5d1bb9225c0aff +- k0i05/esp_ahtxx +manifest_hash: 5762034b4c66072216d7ea1b788e5406026bf0ac8db349bd46ccb04dc37ff0d1 target: esp32c3 version: 2.0.0 diff --git a/main/idf_component.yml b/main/idf_component.yml index 0026c33..0f890f0 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -16,3 +16,4 @@ dependencies: # public: true espressif/esp_lvgl_port: ^2.7.2 espressif/bh1750: ^2.0.0 + k0i05/esp_ahtxx: ^1.2.7 diff --git a/main/main.c b/main/main.c index dff3edf..63501de 100755 --- a/main/main.c +++ b/main/main.c @@ -1,20 +1,48 @@ #include #include +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_check.h" +#include "esp_log.h" #include "wifi-connect.h" #include "lvgl_st7735s_use.h" #include "i2c_master_messager.h" -#define BOTANY_I2C_PORT I2C_NUM_0 -#define BOTANY_I2C_SCL_GPIO GPIO_NUM_5 -#define BOTANY_I2C_SDA_GPIO GPIO_NUM_4 -#define BOTANY_READ_PERIOD_MS 1000 +#ifndef CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE +#define CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE 0 +#endif + +#ifndef CONFIG_I2C_MASTER_MESSAGER_AHT30_ENABLE +#define CONFIG_I2C_MASTER_MESSAGER_AHT30_ENABLE 0 +#endif + +#ifndef CONFIG_I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS +#define CONFIG_I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS 500 +#endif + +#ifndef CONFIG_I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS +#define CONFIG_I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS 2000 +#endif + +#ifndef CONFIG_I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP +#define CONFIG_I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP 1 +#endif + +#define BOTANY_I2C_PORT I2C_NUM_0 +#define BOTANY_I2C_SCL_GPIO GPIO_NUM_5 +#define BOTANY_I2C_SDA_GPIO GPIO_NUM_4 +#define BOTANY_BH1750_ENABLE CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE +#define BOTANY_AHT30_ENABLE CONFIG_I2C_MASTER_MESSAGER_AHT30_ENABLE +#define BOTANY_BH1750_PERIOD_MS CONFIG_I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS +#define BOTANY_AHT30_PERIOD_MS CONFIG_I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS +#define BOTANY_I2C_INTERNAL_PULLUP CONFIG_I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP + +static const char *TAG = "main"; void app_main(void) { - //初始化 Wi-Fi 配网组件,支持长按按键进入配网 + // 初始化 Wi-Fi 配网组件,支持长按按键进入配网 ESP_ERROR_CHECK(wifi_connect_init()); printf("设备启动完成:长按按键进入配网模式,手机连接 ESP32-* 后访问 http://192.168.4.1\n"); @@ -25,27 +53,78 @@ void app_main(void) .i2c_port = BOTANY_I2C_PORT, .scl_io_num = BOTANY_I2C_SCL_GPIO, .sda_io_num = BOTANY_I2C_SDA_GPIO, - .read_period_ms = BOTANY_READ_PERIOD_MS, - .bh1750_addr = 0x23, + .i2c_enable_internal_pullup = BOTANY_I2C_INTERNAL_PULLUP, + .bh1750_enable = BOTANY_BH1750_ENABLE, + .aht30_enable = BOTANY_AHT30_ENABLE, + .bh1750_read_period_ms = BOTANY_BH1750_PERIOD_MS, + .aht30_read_period_ms = BOTANY_AHT30_PERIOD_MS, .bh1750_mode = BH1750_CONTINUE_1LX_RES, + }; - ESP_ERROR_CHECK(i2c_master_messager_init(&i2c_cfg)); - ESP_ERROR_CHECK(i2c_master_messager_start()); + bool i2c_ready = false; + esp_err_t ret = i2c_master_messager_init(&i2c_cfg); + if (ret == ESP_OK) + { + ret = i2c_master_messager_start(); + } + + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "I2C 传感器管理启动失败: %s", esp_err_to_name(ret)); + ESP_LOGW(TAG, "请检查 I2C 引脚/上拉电阻/端口占用情况,系统将继续运行但不采集传感器"); + ESP_ERROR_CHECK(lvgl_st7735s_set_center_text("I2C init failed")); + } + else + { + i2c_ready = true; + } for (;;) { i2c_master_messager_data_t sensor_data = {0}; - if (i2c_master_messager_get_data(&sensor_data) == ESP_OK && sensor_data.bh1750.valid) { - char text[32] = {0}; - snprintf(text, sizeof(text), "Light: %.1f lx", sensor_data.bh1750.lux); - ESP_ERROR_CHECK(lvgl_st7735s_set_center_text(text)); - printf("[BH1750] lux=%.2f update_ms=%" PRId64 "\n", - sensor_data.bh1750.lux, - sensor_data.bh1750.last_update_ms); - } else { - ESP_ERROR_CHECK(lvgl_st7735s_set_center_text("Light: waiting...")); - printf("[BH1750] waiting data, err=0x%x\n", sensor_data.bh1750.last_error); + if (i2c_ready && i2c_master_messager_get_data(&sensor_data) == ESP_OK) + { + char text[64] = {0}; + + if (BOTANY_BH1750_ENABLE && BOTANY_AHT30_ENABLE && + sensor_data.bh1750.valid && sensor_data.aht30.valid) + { + snprintf(text, + sizeof(text), + "L:%.0f T:%.1fC\nH:%.1f%%", + sensor_data.bh1750.lux, + sensor_data.aht30.temperature_c, + sensor_data.aht30.humidity_rh); + ESP_ERROR_CHECK(lvgl_st7735s_set_center_text(text)); + } + else if (BOTANY_BH1750_ENABLE && sensor_data.bh1750.valid) + { + snprintf(text, sizeof(text), "Light: %.1f lx", sensor_data.bh1750.lux); + ESP_ERROR_CHECK(lvgl_st7735s_set_center_text(text)); + } + else if (BOTANY_AHT30_ENABLE && sensor_data.aht30.valid) + { + snprintf(text, + sizeof(text), + "T:%.1fC\nH:%.1f%%", + sensor_data.aht30.temperature_c, + sensor_data.aht30.humidity_rh); + ESP_ERROR_CHECK(lvgl_st7735s_set_center_text(text)); + } + else + { + ESP_ERROR_CHECK(lvgl_st7735s_set_center_text("Sensor waiting...")); + } + + } + else if (i2c_ready) + { + ESP_ERROR_CHECK(lvgl_st7735s_set_center_text("Sensor read fail")); + } + else + { + vTaskDelay(pdMS_TO_TICKS(2000)); } vTaskDelay(pdMS_TO_TICKS(1000));