From fc906db35f85e9f806565aa457f62397f5740277 Mon Sep 17 00:00:00 2001 From: Wang Beihong Date: Mon, 20 Apr 2026 23:48:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=BB=A7=E7=94=B5=E5=99=A8?= =?UTF-8?q?=E4=B8=89=E4=B8=AA=E9=80=9A=E9=81=93=E7=9A=84=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=EF=BC=8C=E8=BF=98=E6=9C=891=E9=80=9A=E9=81=93=E5=BC=95?= =?UTF-8?q?=E8=84=9A=E5=8D=A0=E7=94=A8=E9=94=99=E8=AF=AF=E8=A6=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/relay_ctrl/include/relay_ctrl.h | 54 +++++------------ components/relay_ctrl/relay_ctrl.c | 68 +++++++--------------- main/CMakeLists.txt | 2 +- main/main.cpp | 53 ++++++++--------- 4 files changed, 60 insertions(+), 117 deletions(-) diff --git a/components/relay_ctrl/include/relay_ctrl.h b/components/relay_ctrl/include/relay_ctrl.h index 25cb4a9..f2cdb6e 100644 --- a/components/relay_ctrl/include/relay_ctrl.h +++ b/components/relay_ctrl/include/relay_ctrl.h @@ -1,9 +1,7 @@ #pragma once -#include - -#include "driver/gpio.h" #include "esp_err.h" +#include "driver/gpio.h" #ifdef __cplusplus extern "C" { @@ -11,51 +9,31 @@ extern "C" { typedef enum { RELAY_CTRL_ID_1 = 0, - RELAY_CTRL_ID_2 = 1, - RELAY_CTRL_ID_3 = 2, - RELAY_CTRL_ID_4 = 3, - RELAY_CTRL_ID_MAX, + RELAY_CTRL_ID_2, + RELAY_CTRL_ID_3, + RELAY_CTRL_ID_4, + RELAY_CTRL_ID_MAX } relay_ctrl_id_t; /** - * @brief 初始化四路继电器控制模块。 - * - * @param relay1_gpio 继电器1控制引脚 - * @param relay2_gpio 继电器2控制引脚 - * @param relay3_gpio 继电器3控制引脚 - * @param relay4_gpio 继电器4控制引脚 - * @param active_high 继电器有效电平,true=高电平吸合,false=低电平吸合 + * @brief 继电器配置结构体 */ -esp_err_t relay_ctrl_init(gpio_num_t relay1_gpio, - gpio_num_t relay2_gpio, - gpio_num_t relay3_gpio, - gpio_num_t relay4_gpio, - bool active_high); +typedef struct { + gpio_num_t pin; // GPIO 引脚 + bool active_high; // 该继电器是否为高电平触发 +} relay_config_t; /** - * @brief 设置指定继电器状态。 - * - * @param relay_id 继电器编号 - * @param on true=吸合,false=断开 + * @brief 初始化继电器控制模块 + * + * @param config 包含 4 个继电器详细配置的数组 + * @return esp_err_t */ +esp_err_t relay_ctrl_init(const relay_config_t config[RELAY_CTRL_ID_MAX]); + esp_err_t relay_ctrl_set(relay_ctrl_id_t relay_id, bool on); - -/** - * @brief 翻转指定继电器状态。 - */ esp_err_t relay_ctrl_toggle(relay_ctrl_id_t relay_id); - -/** - * @brief 获取指定继电器状态。 - * - * @param relay_id 继电器编号 - * @param on_out [out] 当前逻辑状态,true=吸合,false=断开 - */ esp_err_t relay_ctrl_get(relay_ctrl_id_t relay_id, bool *on_out); - -/** - * @brief 一次性设置四个继电器状态。 - */ esp_err_t relay_ctrl_set_all(bool relay1_on, bool relay2_on, bool relay3_on, bool relay4_on); #ifdef __cplusplus diff --git a/components/relay_ctrl/relay_ctrl.c b/components/relay_ctrl/relay_ctrl.c index 585a13f..4e785ac 100644 --- a/components/relay_ctrl/relay_ctrl.c +++ b/components/relay_ctrl/relay_ctrl.c @@ -1,7 +1,5 @@ #include "relay_ctrl.h" - #include - #include "esp_check.h" #include "esp_log.h" @@ -9,16 +7,15 @@ static const char *TAG = "relay_ctrl"; typedef struct { bool inited; - bool active_high; - gpio_num_t pins[RELAY_CTRL_ID_MAX]; + relay_config_t config[RELAY_CTRL_ID_MAX]; bool states[RELAY_CTRL_ID_MAX]; } relay_ctx_t; static relay_ctx_t s_ctx; -static inline int relay_level_from_state(bool on) +static inline int relay_level_from_state(int id, bool on) { - return (on == s_ctx.active_high) ? 1 : 0; + return (on == s_ctx.config[id].active_high) ? 1 : 0; } static esp_err_t relay_validate_id(relay_ctrl_id_t relay_id) @@ -28,30 +25,16 @@ static esp_err_t relay_validate_id(relay_ctrl_id_t relay_id) return ESP_OK; } -esp_err_t relay_ctrl_init(gpio_num_t relay1_gpio, - gpio_num_t relay2_gpio, - gpio_num_t relay3_gpio, - gpio_num_t relay4_gpio, - bool active_high) +esp_err_t relay_ctrl_init(const relay_config_t config[RELAY_CTRL_ID_MAX]) { - ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(relay1_gpio), ESP_ERR_INVALID_ARG, TAG, "relay1 gpio invalid"); - ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(relay2_gpio), ESP_ERR_INVALID_ARG, TAG, "relay2 gpio invalid"); - ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(relay3_gpio), ESP_ERR_INVALID_ARG, TAG, "relay3 gpio invalid"); - ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(relay4_gpio), ESP_ERR_INVALID_ARG, TAG, "relay4 gpio invalid"); - - const gpio_num_t relay_gpios[RELAY_CTRL_ID_MAX] = { - relay1_gpio, - relay2_gpio, - relay3_gpio, - relay4_gpio, - }; - - s_ctx.active_high = active_high; - uint64_t pin_bit_mask = 0; + for (int i = 0; i < RELAY_CTRL_ID_MAX; ++i) { - s_ctx.pins[i] = relay_gpios[i]; - pin_bit_mask |= (1ULL << relay_gpios[i]); + ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(config[i].pin), + ESP_ERR_INVALID_ARG, TAG, "relay gpio invalid"); + + s_ctx.config[i] = config[i]; + pin_bit_mask |= (1ULL << config[i].pin); } const gpio_config_t io_cfg = { @@ -63,22 +46,15 @@ esp_err_t relay_ctrl_init(gpio_num_t relay1_gpio, }; ESP_RETURN_ON_ERROR(gpio_config(&io_cfg), TAG, "relay gpio config failed"); - // 默认上电全部断开 + // 根据每个继电器的配置设置初始电平(默认关闭) for (int i = 0; i < RELAY_CTRL_ID_MAX; ++i) { s_ctx.states[i] = false; - ESP_RETURN_ON_ERROR(gpio_set_level(relay_gpios[i], relay_level_from_state(false)), - TAG, - "relay set init level failed"); + ESP_RETURN_ON_ERROR(gpio_set_level(s_ctx.config[i].pin, relay_level_from_state(i, false)), + TAG, "relay set init level failed"); } s_ctx.inited = true; - ESP_LOGI(TAG, - "继电器初始化完成: relay1=GPIO%d relay2=GPIO%d relay3=GPIO%d relay4=GPIO%d active_high=%d", - relay1_gpio, - relay2_gpio, - relay3_gpio, - relay4_gpio, - active_high); + ESP_LOGI(TAG, "继电器初始化完成(独立电平配置已应用)"); return ESP_OK; } @@ -87,15 +63,14 @@ esp_err_t relay_ctrl_set(relay_ctrl_id_t relay_id, bool on) ESP_RETURN_ON_FALSE(s_ctx.inited, ESP_ERR_INVALID_STATE, TAG, "relay not initialized"); ESP_RETURN_ON_ERROR(relay_validate_id(relay_id), TAG, "invalid relay id"); - ESP_RETURN_ON_ERROR(gpio_set_level(s_ctx.pins[relay_id], relay_level_from_state(on)), - TAG, - "relay set level failed"); + ESP_RETURN_ON_ERROR(gpio_set_level(s_ctx.config[relay_id].pin, relay_level_from_state(relay_id, on)), + TAG, "relay set level failed"); s_ctx.states[relay_id] = on; + ESP_LOGI(TAG, "继电器%d -> %s (GPIO%d level=%d)", - relay_id + 1, - on ? "ON" : "OFF", - s_ctx.pins[relay_id], - relay_level_from_state(on)); + relay_id + 1, on ? "ON" : "OFF", + s_ctx.config[relay_id].pin, + relay_level_from_state(relay_id, on)); return ESP_OK; } @@ -103,7 +78,6 @@ esp_err_t relay_ctrl_toggle(relay_ctrl_id_t relay_id) { ESP_RETURN_ON_FALSE(s_ctx.inited, ESP_ERR_INVALID_STATE, TAG, "relay not initialized"); ESP_RETURN_ON_ERROR(relay_validate_id(relay_id), TAG, "invalid relay id"); - return relay_ctrl_set(relay_id, !s_ctx.states[relay_id]); } @@ -112,14 +86,12 @@ esp_err_t relay_ctrl_get(relay_ctrl_id_t relay_id, bool *on_out) ESP_RETURN_ON_FALSE(s_ctx.inited, ESP_ERR_INVALID_STATE, TAG, "relay not initialized"); ESP_RETURN_ON_FALSE(on_out != NULL, ESP_ERR_INVALID_ARG, TAG, "on_out is null"); ESP_RETURN_ON_ERROR(relay_validate_id(relay_id), TAG, "invalid relay id"); - *on_out = s_ctx.states[relay_id]; return ESP_OK; } esp_err_t relay_ctrl_set_all(bool relay1_on, bool relay2_on, bool relay3_on, bool relay4_on) { - ESP_RETURN_ON_FALSE(s_ctx.inited, ESP_ERR_INVALID_STATE, TAG, "relay not initialized"); ESP_RETURN_ON_ERROR(relay_ctrl_set(RELAY_CTRL_ID_1, relay1_on), TAG, "set relay1 failed"); ESP_RETURN_ON_ERROR(relay_ctrl_set(RELAY_CTRL_ID_2, relay2_on), TAG, "set relay2 failed"); ESP_RETURN_ON_ERROR(relay_ctrl_set(RELAY_CTRL_ID_3, relay3_on), TAG, "set relay3 failed"); diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 8c0d933..79e8ee3 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "main.cpp" INCLUDE_DIRS "." - REQUIRES nvs_flash esp_wifi sntp_time esp_event esp_system wifi-connect ui lvgl_st7789_use efuse) + REQUIRES nvs_flash esp_wifi sntp_time esp_event esp_system wifi-connect ui lvgl_st7789_use efuse relay_ctrl) diff --git a/main/main.cpp b/main/main.cpp index 7817e5a..bdb2364 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,12 +1,12 @@ #include #include #include - #include "wifi-connect.h" #include "esp_lvgl_port.h" #include "lvgl_st7789_use.h" #include "ui.h" #include "vars.h" +#include "relay_ctrl.h" #include "esp_err.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" @@ -20,21 +20,18 @@ #define TAG "MAIN" -/** - * @brief 系统环境数据结构体 - */ typedef struct { char time_str[32]; + char mac_str[20]; + char uid_str[20]; float temp; float humidity; } env_data_t; -// 定义全局变量和锁 static env_data_t s_env_data; static SemaphoreHandle_t s_env_data_lock = NULL; -// 等待 Wi-Fi 连接成功 static bool wait_for_wifi_connected(TickType_t timeout_ticks) { const TickType_t start_ticks = xTaskGetTickCount(); @@ -49,15 +46,11 @@ static bool wait_for_wifi_connected(TickType_t timeout_ticks) return wifi_connect_get_status() == WIFI_CONNECT_STATUS_CONNECTED; } -/** - * @brief 更新系统状态到结构体,并同步到 UI - */ static void env_data_update_system_info(void) { if (s_env_data_lock == NULL) return; - // 获取当前时间 time_t now; struct tm timeinfo; time(&now); @@ -65,11 +58,11 @@ static void env_data_update_system_info(void) char time_buf[32]; strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &timeinfo); - // 更新结构体 (线程安全) xSemaphoreTake(s_env_data_lock, portMAX_DELAY); strncpy(s_env_data.time_str, time_buf, sizeof(s_env_data.time_str)); xSemaphoreGive(s_env_data_lock); + set_var_local_time(s_env_data.time_str); } @@ -79,33 +72,31 @@ static void ui_task(void *arg) for (;;) { env_data_update_system_info(); - lvgl_port_lock(0); ui_tick(); lvgl_port_unlock(); - vTaskDelay(pdMS_TO_TICKS(20)); + vTaskDelay(pdMS_TO_TICKS(30)); } } extern "C" void app_main(void) { - printf("\n\n--- APP START ---\n\n"); + vTaskDelay(pdMS_TO_TICKS(100)); + ESP_LOGI(TAG, "--- APP STARTING ---"); - // 创建结构体互斥锁 s_env_data_lock = xSemaphoreCreateMutex(); - // 初始化 Wi-Fi + // 2. 初始化 Wi-Fi ESP_ERROR_CHECK(wifi_connect_init()); - // 初始化屏幕和 LVGL + // 3. 初始化显示屏和 LVGL start_lvgl_demo(); - // 初始化 UI - lvgl_port_lock(0); + // 4. 初始化 UI + lvgl_port_lock(100 / portTICK_PERIOD_MS); ui_init(); lvgl_port_unlock(); - // 设置初始状态变量 (常量) set_var_door_status("关闭"); set_var_food_status("良好"); set_var_hum_status("有人"); @@ -114,18 +105,20 @@ extern "C" void app_main(void) set_var_fan_status("开"); set_var_light_status("开"); - // 创建 UI 刷新任务 - xTaskCreate(ui_task, "ui_task", 4096, NULL, 10, NULL); + xTaskCreate(ui_task, "ui_task", 8192, NULL, 5, NULL); - // 等待网络并对时 - if (wait_for_wifi_connected(pdMS_TO_TICKS(60000))) + if (wait_for_wifi_connected(pdMS_TO_TICKS(15000))) { - printf("Wi-Fi connected, IP address: %s\n", wifi_connect_get_ip()); + ESP_LOGI(TAG, "IP: %s", wifi_connect_get_ip()); set_var_system_ip(wifi_connect_get_ip()); - esp_err_t sntp_ret = sntp_timp_sync_time(12000); - if (sntp_ret != ESP_OK) - { - ESP_LOGW(TAG, "SNTP sync failed"); - } } + + // 1. 初始化继电器 (避开 Octal PSRAM/Flash 所占用的引脚) + // ESP32-S3 N16R8 使用 8线 PSRAM,占用 GPIO 33-37 + static const relay_config_t relay_cfg[RELAY_CTRL_ID_MAX] = { + {.pin = GPIO_NUM_38, .active_high = true}, // 示例改为常用 GPIO + {.pin = GPIO_NUM_39, .active_high = false}, + {.pin = GPIO_NUM_40, .active_high = false}, + }; + ESP_ERROR_CHECK(relay_ctrl_init(relay_cfg)); }