feat: 添加 AHT30 温湿度传感器支持,优化 I2C 传感器管理逻辑
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS "i2c_master_messager.c"
|
SRCS "i2c_master_messager.c"
|
||||||
INCLUDE_DIRS "include"
|
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
|
||||||
)
|
)
|
||||||
|
|||||||
38
components/i2c_master_messager/Kconfig.projbuild
Normal file
38
components/i2c_master_messager/Kconfig.projbuild
Normal file
@@ -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
|
||||||
@@ -3,13 +3,22 @@
|
|||||||
`i2c_master_messager` 用于统一管理工程中的 I2C 传感器。
|
`i2c_master_messager` 用于统一管理工程中的 I2C 传感器。
|
||||||
当前已接入:
|
当前已接入:
|
||||||
|
|
||||||
- BH1750 光照传感器(默认地址 `0x23`)
|
- BH1750 光照传感器(使用驱动默认地址)
|
||||||
|
- AHT30 温湿度传感器(使用驱动默认地址)
|
||||||
|
|
||||||
设计目标:
|
设计目标:
|
||||||
|
|
||||||
- 提供统一的数据结构,方便其他模块读取
|
- 提供统一的数据结构,方便其他模块读取
|
||||||
- 提供独立采集任务,周期性更新数据
|
- 提供独立采集任务,周期性更新数据
|
||||||
- 为后续新增其他 I2C 传感器预留扩展位置
|
- 为后续新增其他 I2C 传感器预留扩展位置
|
||||||
|
- 各传感器驱动相互独立,管理层只做调度与数据汇总
|
||||||
|
- 支持每个传感器独立采样周期(例如光照快采、温湿度慢采)
|
||||||
|
|
||||||
|
## 驱动分层
|
||||||
|
|
||||||
|
- `k0i05__esp_ahtxx`:AHT30 驱动组件(通过组件管理器引入)
|
||||||
|
- `bh1750`:使用 ESP 组件管理器驱动
|
||||||
|
- `i2c_master_messager.c`:统一总线管理、任务轮询、线程安全数据缓存
|
||||||
|
|
||||||
## 对外数据结构
|
## 对外数据结构
|
||||||
|
|
||||||
@@ -20,13 +29,18 @@
|
|||||||
- `bh1750.valid`:当前数据是否有效
|
- `bh1750.valid`:当前数据是否有效
|
||||||
- `bh1750.last_update_ms`:最后一次成功更新时间(毫秒)
|
- `bh1750.last_update_ms`:最后一次成功更新时间(毫秒)
|
||||||
- `bh1750.last_error`:最后一次采集错误码
|
- `bh1750.last_error`:最后一次采集错误码
|
||||||
|
- `aht30.temperature_c`:温度(摄氏度)
|
||||||
|
- `aht30.humidity_rh`:湿度(%RH)
|
||||||
|
- `aht30.valid`:当前数据是否有效
|
||||||
|
- `aht30.last_update_ms`:最后一次成功更新时间(毫秒)
|
||||||
|
- `aht30.last_error`:最后一次采集错误码
|
||||||
|
|
||||||
后续新增传感器时,建议继续在 `i2c_master_messager_data_t` 中增加对应字段。
|
后续新增传感器时,建议继续在 `i2c_master_messager_data_t` 中增加对应字段。
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
- `esp_err_t i2c_master_messager_init(const i2c_master_messager_config_t *config);`
|
- `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_start(void);`
|
||||||
- 启动循环采集任务
|
- 启动循环采集任务
|
||||||
- `esp_err_t i2c_master_messager_stop(void);`
|
- `esp_err_t i2c_master_messager_stop(void);`
|
||||||
@@ -36,6 +50,18 @@
|
|||||||
- `esp_err_t i2c_master_messager_deinit(void);`
|
- `esp_err_t i2c_master_messager_deinit(void);`
|
||||||
- 释放总线和传感器资源
|
- 释放总线和传感器资源
|
||||||
|
|
||||||
|
## menuconfig 配置
|
||||||
|
|
||||||
|
路径:`Component config -> I2C Master Messager`
|
||||||
|
|
||||||
|
- `启用 BH1750 光照传感器`:开关 BH1750
|
||||||
|
- `启用 I2C 内部上拉电阻`:控制是否打开芯片内部上拉
|
||||||
|
- `BH1750 采样周期 (ms)`:光照采样周期
|
||||||
|
- `启用 AHT30 温湿度传感器`:开关 AHT30
|
||||||
|
- `AHT30 采样周期 (ms)`:温湿度采样周期
|
||||||
|
|
||||||
|
这两个周期相互独立,可按业务需求分别调优。
|
||||||
|
|
||||||
## 使用示例
|
## 使用示例
|
||||||
|
|
||||||
```c
|
```c
|
||||||
@@ -46,10 +72,13 @@ void app_main(void)
|
|||||||
{
|
{
|
||||||
i2c_master_messager_config_t cfg = {
|
i2c_master_messager_config_t cfg = {
|
||||||
.i2c_port = I2C_NUM_0,
|
.i2c_port = I2C_NUM_0,
|
||||||
.scl_io_num = GPIO_NUM_5,
|
.scl_io_num = GPIO_NUM_5,
|
||||||
.sda_io_num = GPIO_NUM_4,
|
.sda_io_num = GPIO_NUM_4,
|
||||||
.read_period_ms = 1000,
|
.i2c_enable_internal_pullup = true,
|
||||||
.bh1750_addr = 0x23,
|
.bh1750_enable = true,
|
||||||
|
.aht30_enable = true,
|
||||||
|
.bh1750_read_period_ms = 500,
|
||||||
|
.aht30_read_period_ms = 2000,
|
||||||
.bh1750_mode = BH1750_CONTINUE_1LX_RES,
|
.bh1750_mode = BH1750_CONTINUE_1LX_RES,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,8 +87,11 @@ void app_main(void)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
i2c_master_messager_data_t data;
|
i2c_master_messager_data_t data;
|
||||||
if (i2c_master_messager_get_data(&data) == ESP_OK && data.bh1750.valid) {
|
if (i2c_master_messager_get_data(&data) == ESP_OK && data.bh1750.valid && data.aht30.valid) {
|
||||||
printf("BH1750: %.2f lx\n", data.bh1750.lux);
|
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));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
}
|
}
|
||||||
@@ -72,6 +104,6 @@ void app_main(void)
|
|||||||
|
|
||||||
1. 在 `i2c_master_messager_data_t` 中增加该传感器的数据结构
|
1. 在 `i2c_master_messager_data_t` 中增加该传感器的数据结构
|
||||||
2. 在 `i2c_master_messager_config_t` 中增加该传感器配置项
|
2. 在 `i2c_master_messager_config_t` 中增加该传感器配置项
|
||||||
3. 在 `i2c_master_messager_init()` 中完成驱动初始化
|
3. 在任务循环中按需完成驱动初始化与重试
|
||||||
4. 在采集任务中加入周期读取逻辑并更新共享数据
|
4. 在采集任务中加入周期读取逻辑并更新共享数据
|
||||||
5. 在 `deinit()` 中释放对应资源
|
5. 在 `deinit()` 中释放对应资源
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "driver/i2c_master.h"
|
#include "driver/i2c_master.h"
|
||||||
|
#include "ahtxx.h"
|
||||||
#include "esp_check.h"
|
#include "esp_check.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
@@ -10,12 +11,18 @@
|
|||||||
#include "i2c_master_messager.h"
|
#include "i2c_master_messager.h"
|
||||||
|
|
||||||
static const char *TAG = "i2c_master_messager";
|
static const char *TAG = "i2c_master_messager";
|
||||||
|
#define BH1750_REINIT_INTERVAL_MS (3000)
|
||||||
|
#define AHT30_REINIT_INTERVAL_MS (3000)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
bool owns_i2c_bus;
|
||||||
|
bool bh1750_ready;
|
||||||
|
bool aht30_ready;
|
||||||
i2c_master_messager_config_t config;
|
i2c_master_messager_config_t config;
|
||||||
i2c_master_bus_handle_t i2c_bus;
|
i2c_master_bus_handle_t i2c_bus;
|
||||||
bh1750_handle_t bh1750;
|
bh1750_handle_t bh1750;
|
||||||
|
ahtxx_handle_t aht30;
|
||||||
i2c_master_messager_data_t data;
|
i2c_master_messager_data_t data;
|
||||||
SemaphoreHandle_t lock;
|
SemaphoreHandle_t lock;
|
||||||
TaskHandle_t task_handle;
|
TaskHandle_t task_handle;
|
||||||
@@ -23,38 +30,175 @@ typedef struct {
|
|||||||
|
|
||||||
static i2c_master_messager_ctx_t g_ctx;
|
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)
|
static void i2c_master_messager_task(void *arg)
|
||||||
{
|
{
|
||||||
(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) {
|
while (1) {
|
||||||
float lux = 0.0f;
|
int64_t now_ms = esp_timer_get_time() / 1000;
|
||||||
esp_err_t ret = bh1750_get_data(g_ctx.bh1750, &lux);
|
|
||||||
|
|
||||||
if (xSemaphoreTake(g_ctx.lock, pdMS_TO_TICKS(100)) == pdTRUE) {
|
if (g_ctx.config.bh1750_enable && !g_ctx.bh1750_ready &&
|
||||||
g_ctx.data.bh1750.valid = (ret == ESP_OK);
|
(now_ms - last_bh1750_reinit_ms) >= BH1750_REINIT_INTERVAL_MS) {
|
||||||
g_ctx.data.bh1750.last_error = ret;
|
last_bh1750_reinit_ms = now_ms;
|
||||||
if (ret == ESP_OK) {
|
esp_err_t init_ret = i2c_master_messager_try_init_bh1750();
|
||||||
g_ctx.data.bh1750.lux = lux;
|
if (init_ret == ESP_OK) {
|
||||||
g_ctx.data.bh1750.last_update_ms = esp_timer_get_time() / 1000;
|
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) {
|
if (g_ctx.bh1750_ready && g_ctx.bh1750 != NULL &&
|
||||||
ESP_LOGW(TAG, "bh1750_get_data failed: %s", esp_err_to_name(ret));
|
(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_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 != 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,
|
ESP_ERR_INVALID_ARG,
|
||||||
TAG,
|
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) {
|
if (g_ctx.initialized) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
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,
|
.scl_io_num = config->scl_io_num,
|
||||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||||
.glitch_ignore_cnt = 7,
|
.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);
|
esp_err_t ret = i2c_new_master_bus(&bus_cfg, &g_ctx.i2c_bus);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
vSemaphoreDelete(g_ctx.lock);
|
if (ret == ESP_ERR_INVALID_STATE) {
|
||||||
g_ctx.lock = NULL;
|
ESP_LOGW(TAG,
|
||||||
return ret;
|
"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 (!config->bh1750_enable) {
|
||||||
if (ret != ESP_OK) {
|
g_ctx.data.bh1750.valid = false;
|
||||||
i2c_del_master_bus(g_ctx.i2c_bus);
|
g_ctx.data.bh1750.last_error = ESP_ERR_NOT_SUPPORTED;
|
||||||
g_ctx.i2c_bus = NULL;
|
} else {
|
||||||
vSemaphoreDelete(g_ctx.lock);
|
g_ctx.data.bh1750.valid = false;
|
||||||
g_ctx.lock = NULL;
|
g_ctx.data.bh1750.last_error = ESP_ERR_INVALID_STATE;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_GOTO_ON_ERROR(bh1750_power_on(g_ctx.bh1750), err, TAG, "bh1750_power_on failed");
|
if (!config->aht30_enable) {
|
||||||
ESP_GOTO_ON_ERROR(bh1750_set_measure_mode(g_ctx.bh1750, config->bh1750_mode),
|
g_ctx.data.aht30.valid = false;
|
||||||
err,
|
g_ctx.data.aht30.last_error = ESP_ERR_NOT_SUPPORTED;
|
||||||
TAG,
|
} else {
|
||||||
"bh1750_set_measure_mode failed");
|
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;
|
g_ctx.initialized = true;
|
||||||
ESP_LOGI(TAG,
|
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->i2c_port,
|
||||||
config->scl_io_num,
|
config->scl_io_num,
|
||||||
config->sda_io_num,
|
config->sda_io_num,
|
||||||
config->bh1750_addr,
|
config->i2c_enable_internal_pullup,
|
||||||
config->read_period_ms);
|
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;
|
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)
|
esp_err_t i2c_master_messager_start(void)
|
||||||
@@ -174,11 +335,17 @@ esp_err_t i2c_master_messager_deinit(void)
|
|||||||
g_ctx.bh1750 = NULL;
|
g_ctx.bh1750 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_ctx.i2c_bus != NULL) {
|
if (g_ctx.aht30 != NULL) {
|
||||||
i2c_del_master_bus(g_ctx.i2c_bus);
|
ahtxx_delete(g_ctx.aht30);
|
||||||
g_ctx.i2c_bus = NULL;
|
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) {
|
if (g_ctx.lock != NULL) {
|
||||||
vSemaphoreDelete(g_ctx.lock);
|
vSemaphoreDelete(g_ctx.lock);
|
||||||
g_ctx.lock = NULL;
|
g_ctx.lock = NULL;
|
||||||
|
|||||||
@@ -16,8 +16,11 @@ typedef struct {
|
|||||||
i2c_port_num_t i2c_port;
|
i2c_port_num_t i2c_port;
|
||||||
gpio_num_t scl_io_num;
|
gpio_num_t scl_io_num;
|
||||||
gpio_num_t sda_io_num;
|
gpio_num_t sda_io_num;
|
||||||
uint16_t read_period_ms;
|
bool i2c_enable_internal_pullup;
|
||||||
uint8_t bh1750_addr;
|
bool bh1750_enable;
|
||||||
|
bool aht30_enable;
|
||||||
|
uint16_t bh1750_read_period_ms;
|
||||||
|
uint16_t aht30_read_period_ms;
|
||||||
bh1750_measure_mode_t bh1750_mode;
|
bh1750_measure_mode_t bh1750_mode;
|
||||||
} i2c_master_messager_config_t;
|
} i2c_master_messager_config_t;
|
||||||
|
|
||||||
@@ -28,8 +31,17 @@ typedef struct {
|
|||||||
esp_err_t last_error;
|
esp_err_t last_error;
|
||||||
} i2c_bh1750_data_t;
|
} 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 {
|
typedef struct {
|
||||||
i2c_bh1750_data_t bh1750;
|
i2c_bh1750_data_t bh1750;
|
||||||
|
i2c_aht30_data_t aht30;
|
||||||
} i2c_master_messager_data_t;
|
} i2c_master_messager_data_t;
|
||||||
|
|
||||||
#define I2C_MASTER_MESSAGER_MIN_PERIOD_MS (100)
|
#define I2C_MASTER_MESSAGER_MIN_PERIOD_MS (100)
|
||||||
|
|||||||
@@ -27,6 +27,30 @@ dependencies:
|
|||||||
source:
|
source:
|
||||||
type: idf
|
type: idf
|
||||||
version: 5.5.2
|
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:
|
lvgl/lvgl:
|
||||||
component_hash: 184e532558c1c45fefed631f3e235423d22582aafb4630f3e8885c35281a49ae
|
component_hash: 184e532558c1c45fefed631f3e235423d22582aafb4630f3e8885c35281a49ae
|
||||||
dependencies: []
|
dependencies: []
|
||||||
@@ -38,6 +62,7 @@ direct_dependencies:
|
|||||||
- espressif/bh1750
|
- espressif/bh1750
|
||||||
- espressif/esp_lvgl_port
|
- espressif/esp_lvgl_port
|
||||||
- idf
|
- idf
|
||||||
manifest_hash: 1fd264456e89adf9729f55472d73dc1ff5c869e32bf39dd97a5d1bb9225c0aff
|
- k0i05/esp_ahtxx
|
||||||
|
manifest_hash: 5762034b4c66072216d7ea1b788e5406026bf0ac8db349bd46ccb04dc37ff0d1
|
||||||
target: esp32c3
|
target: esp32c3
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ dependencies:
|
|||||||
# public: true
|
# public: true
|
||||||
espressif/esp_lvgl_port: ^2.7.2
|
espressif/esp_lvgl_port: ^2.7.2
|
||||||
espressif/bh1750: ^2.0.0
|
espressif/bh1750: ^2.0.0
|
||||||
|
k0i05/esp_ahtxx: ^1.2.7
|
||||||
|
|||||||
117
main/main.c
117
main/main.c
@@ -1,20 +1,48 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "esp_check.h"
|
#include "esp_check.h"
|
||||||
|
#include "esp_log.h"
|
||||||
#include "wifi-connect.h"
|
#include "wifi-connect.h"
|
||||||
#include "lvgl_st7735s_use.h"
|
#include "lvgl_st7735s_use.h"
|
||||||
#include "i2c_master_messager.h"
|
#include "i2c_master_messager.h"
|
||||||
|
|
||||||
#define BOTANY_I2C_PORT I2C_NUM_0
|
#ifndef CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE
|
||||||
#define BOTANY_I2C_SCL_GPIO GPIO_NUM_5
|
#define CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE 0
|
||||||
#define BOTANY_I2C_SDA_GPIO GPIO_NUM_4
|
#endif
|
||||||
#define BOTANY_READ_PERIOD_MS 1000
|
|
||||||
|
#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)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
//初始化 Wi-Fi 配网组件,支持长按按键进入配网
|
// 初始化 Wi-Fi 配网组件,支持长按按键进入配网
|
||||||
ESP_ERROR_CHECK(wifi_connect_init());
|
ESP_ERROR_CHECK(wifi_connect_init());
|
||||||
printf("设备启动完成:长按按键进入配网模式,手机连接 ESP32-* 后访问 http://192.168.4.1\n");
|
printf("设备启动完成:长按按键进入配网模式,手机连接 ESP32-* 后访问 http://192.168.4.1\n");
|
||||||
|
|
||||||
@@ -25,27 +53,78 @@ void app_main(void)
|
|||||||
.i2c_port = BOTANY_I2C_PORT,
|
.i2c_port = BOTANY_I2C_PORT,
|
||||||
.scl_io_num = BOTANY_I2C_SCL_GPIO,
|
.scl_io_num = BOTANY_I2C_SCL_GPIO,
|
||||||
.sda_io_num = BOTANY_I2C_SDA_GPIO,
|
.sda_io_num = BOTANY_I2C_SDA_GPIO,
|
||||||
.read_period_ms = BOTANY_READ_PERIOD_MS,
|
.i2c_enable_internal_pullup = BOTANY_I2C_INTERNAL_PULLUP,
|
||||||
.bh1750_addr = 0x23,
|
.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,
|
.bh1750_mode = BH1750_CONTINUE_1LX_RES,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ESP_ERROR_CHECK(i2c_master_messager_init(&i2c_cfg));
|
bool i2c_ready = false;
|
||||||
ESP_ERROR_CHECK(i2c_master_messager_start());
|
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 (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
i2c_master_messager_data_t sensor_data = {0};
|
i2c_master_messager_data_t sensor_data = {0};
|
||||||
if (i2c_master_messager_get_data(&sensor_data) == ESP_OK && sensor_data.bh1750.valid) {
|
if (i2c_ready && i2c_master_messager_get_data(&sensor_data) == ESP_OK)
|
||||||
char text[32] = {0};
|
{
|
||||||
snprintf(text, sizeof(text), "Light: %.1f lx", sensor_data.bh1750.lux);
|
char text[64] = {0};
|
||||||
ESP_ERROR_CHECK(lvgl_st7735s_set_center_text(text));
|
|
||||||
printf("[BH1750] lux=%.2f update_ms=%" PRId64 "\n",
|
if (BOTANY_BH1750_ENABLE && BOTANY_AHT30_ENABLE &&
|
||||||
sensor_data.bh1750.lux,
|
sensor_data.bh1750.valid && sensor_data.aht30.valid)
|
||||||
sensor_data.bh1750.last_update_ms);
|
{
|
||||||
} else {
|
snprintf(text,
|
||||||
ESP_ERROR_CHECK(lvgl_st7735s_set_center_text("Light: waiting..."));
|
sizeof(text),
|
||||||
printf("[BH1750] waiting data, err=0x%x\n", sensor_data.bh1750.last_error);
|
"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));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
|||||||
Reference in New Issue
Block a user