#include "sensors.h" #include "esp_log.h" #include "ahtxx.h" #include "bh1750.h" #include "sgp30/sgp30.h" #include "driver/i2c_master.h" #include "vars.h" static const char *TAG = "sensors"; // 实际全局变量定义(从 main.c 抽取到这里) sensor_data_t g_sensor_data = {0}; i2c_master_bus_handle_t bus_handle = NULL; i2c_master_dev_handle_t dev_handle = NULL; esp_err_t i2c_master_init(void) { /* 如果本地已有句柄,直接返回(避免重复初始化) */ if (bus_handle != NULL) { ESP_LOGI(TAG, "I2C bus already initialized (local handle)"); return ESP_OK; } /* 优先尝试获取已有的总线句柄(其它模块可能已初始化) */ esp_err_t ret = i2c_master_get_bus_handle(I2C_MASTER_NUM, &bus_handle); if (ret == ESP_OK) { ESP_LOGI(TAG, "I2C bus already initialized (existing handle)"); return ESP_OK; } /* 如果不是未初始化的常见返回(ESP_ERR_INVALID_STATE),记录警告并尝试创建 */ if (ret != ESP_ERR_INVALID_STATE && ret != ESP_ERR_INVALID_ARG) { ESP_LOGW(TAG, "i2c_master_get_bus_handle returned %s, will try to create new bus", esp_err_to_name(ret)); } i2c_master_bus_config_t i2c_mst_config = { .clk_source = I2C_CLK_SRC_DEFAULT, .i2c_port = I2C_MASTER_NUM, .scl_io_num = I2C_MASTER_SCL_IO, .sda_io_num = I2C_MASTER_SDA_IO, .glitch_ignore_cnt = 7, .flags.enable_internal_pullup = true, }; ret = i2c_new_master_bus(&i2c_mst_config, &bus_handle); if (ret == ESP_OK) { ESP_LOGI(TAG, "I2C master bus initialized successfully"); return ESP_OK; } /* 若创建失败且是已被占用的状态,再次尝试取句柄(防止竞态) */ if (ret == ESP_ERR_INVALID_STATE) { esp_err_t get_ret = i2c_master_get_bus_handle(I2C_MASTER_NUM, &bus_handle); if (get_ret == ESP_OK) { ESP_LOGW(TAG, "I2C bus already acquired by other module; obtained existing handle"); return ESP_OK; } ESP_LOGE(TAG, "i2c_new_master_bus failed and get_bus_handle also failed: %s / %s", esp_err_to_name(ret), esp_err_to_name(get_ret)); return get_ret; } ESP_LOGE(TAG, "i2c_new_master_bus failed: %s", esp_err_to_name(ret)); return ret; } void i2c0_ahtxx_task(void *pvParameters) { (void)pvParameters; ahtxx_config_t ahtxx_config = I2C_AHT30_CONFIG_DEFAULT; ahtxx_handle_t ahtxx_handle = NULL; esp_err_t ret = ahtxx_init(bus_handle, &ahtxx_config, &ahtxx_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "AHTxx init failed, sensor invalid, err=0x%x", ret); while (1) { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.ahtxx_valid = false; xSemaphoreGive(xSensorDataMutex); } vTaskDelay(pdMS_TO_TICKS(5000)); } } float temperature, humidity; while (1) { ret = ahtxx_get_measurement(ahtxx_handle, &temperature, &humidity); if (ret != ESP_OK) { ESP_LOGE(TAG, "AHTxx read failed, err=0x%x", ret); if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.ahtxx_valid = false; xSemaphoreGive(xSensorDataMutex); } } else { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.temperature = temperature; g_sensor_data.humidity = humidity; g_sensor_data.ahtxx_valid = true; xSemaphoreGive(xSensorDataMutex); } // ESP_LOGI(TAG, "AHTxx: temperature=%.1f°C, humidity=%.1f%%", temperature, humidity); // 更新屏幕显示变量 char temp_str[16]; char humidity_str[16]; snprintf(temp_str, sizeof(temp_str), "%.1f", temperature); snprintf(humidity_str, sizeof(humidity_str), "%.1f", humidity); set_var_tempture(temp_str); set_var_humity(humidity_str); } vTaskDelay(pdMS_TO_TICKS(5000)); } } void i2c0_bh1750_task(void *pvParameters) { (void)pvParameters; bh1750_handle_t bh1750_handle = NULL; // 使用默认地址创建 BH1750 设备 esp_err_t ret = bh1750_create(bus_handle, BH1750_I2C_ADDRESS_DEFAULT, &bh1750_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "BH1750 create failed, sensor invalid, err=0x%x", ret); while (1) { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.bh1750_valid = false; xSemaphoreGive(xSensorDataMutex); } vTaskDelay(pdMS_TO_TICKS(5000)); } } // 先上电 ret = bh1750_power_on(bh1750_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "BH1750 power on failed, err=0x%x", ret); } // 设置测量模式为连续高分辨率模式(必须在power_on之后) ret = bh1750_set_measure_mode(bh1750_handle, BH1750_CONTINUE_1LX_RES); if (ret != ESP_OK) { ESP_LOGE(TAG, "BH1750 set measure mode failed, err=0x%x", ret); } float lux; while (1) { ret = bh1750_get_data(bh1750_handle, &lux); if (ret != ESP_OK) { ESP_LOGE(TAG, "BH1750 read failed, err=0x%x", ret); if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.bh1750_valid = false; xSemaphoreGive(xSensorDataMutex); } } else { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.lux = lux; g_sensor_data.bh1750_valid = true; xSemaphoreGive(xSensorDataMutex); } // ESP_LOGI(TAG, "BH1750: illuminance=%.1f lux", lux); // 更新屏幕显示变量 char light_str[16]; snprintf(light_str, sizeof(light_str), "%.1f", lux); set_var_light_value(light_str); } vTaskDelay(pdMS_TO_TICKS(5000)); } } void i2c0_sgp30_task(void *pvParameters) { (void)pvParameters; // SGP30 配置 sgp30_config_t sgp30_config = { .i2c_master_port = I2C_MASTER_NUM, .i2c_address = 0x58, // SGP30 默认地址 }; // 初始化 SGP30 esp_err_t ret = sgp30_init(&sgp30_config); if (ret != ESP_OK) { ESP_LOGE(TAG, "SGP30 init failed, err=0x%x", ret); while (1) { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.sgp30_valid = false; xSemaphoreGive(xSensorDataMutex); } vTaskDelay(pdMS_TO_TICKS(5000)); } } ESP_LOGI(TAG, "SGP30 initialized successfully"); uint16_t co2_ppm, tvoc_ppb; while (1) { ret = sgp30_read_measurements(&co2_ppm, &tvoc_ppb); if (ret != ESP_OK) { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.sgp30_valid = false; xSemaphoreGive(xSensorDataMutex); } } else { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { g_sensor_data.co2_ppm = co2_ppm; g_sensor_data.tvoc_ppb = tvoc_ppb; g_sensor_data.sgp30_valid = true; xSemaphoreGive(xSensorDataMutex); } // ESP_LOGI(TAG, "SGP30: CO2=%d ppm, TVOC=%d ppb", co2_ppm, tvoc_ppb); // 更新屏幕显示变量 char co2_str[16]; char voc_str[16]; snprintf(co2_str, sizeof(co2_str), "%d", co2_ppm); snprintf(voc_str, sizeof(voc_str), "%d", tvoc_ppb); set_var_co2_value(co2_str); set_var_voc_value(voc_str); } // SGP30 建议每秒读取一次 vTaskDelay(pdMS_TO_TICKS(1000)); } } void get_sensor_data(sensor_data_t *data) { if (data != NULL) { if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE) { *data = g_sensor_data; xSemaphoreGive(xSensorDataMutex); } } } esp_err_t sensors_init(void) { // esp_err_t err = i2c_master_init(); // if (err != ESP_OK) // { // ESP_LOGW(TAG, "i2c_master_init failed: %s", esp_err_to_name(err)); // return err; // } ESP_LOGI(TAG, "创建传感器任务前堆: %d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); /* i2c0_ahtxx_task 需要较大栈,防止栈溢出(观察到任务崩溃),恢复为 4096 */ BaseType_t ok = xTaskCreate(i2c0_ahtxx_task, "i2c0_ahtxx_task", 3048, NULL, 5, NULL); ESP_LOGI(TAG, "创建 i2c0_ahtxx_task 后堆: %d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); if (ok != pdPASS) { return ESP_ERR_NO_MEM; } // 降低光照/SGP30任务栈到 1536,释放堆空间(如遇溢出可再调大) ok = xTaskCreate(i2c0_bh1750_task, "i2c0_bh1750_task", 3072, NULL, 5, NULL); ESP_LOGI(TAG, "创建 i2c0_bh1750_task 后堆: %d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); if (ok != pdPASS) { return ESP_ERR_NO_MEM; } ok = xTaskCreate(i2c0_sgp30_task, "i2c0_sgp30_task", 2048, NULL, 5, NULL); ESP_LOGI(TAG, "创建 i2c0_sgp30_task 后堆: %d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); if (ok != pdPASS) { return ESP_ERR_NO_MEM; } return ESP_OK; } esp_err_t sensors_read(void) { // 保留占位,如需单次读可以实现 return ESP_OK; }