Bladeren bron

添加gpio中断回调类,暂时不使用

xuxinyi 4 maanden geleden
bovenliggende
commit
a483d497df
5 gewijzigde bestanden met toevoegingen van 173 en 73 verwijderingen
  1. 1 0
      main/CMakeLists.txt
  2. 8 0
      main/application.cc
  3. 2 73
      main/main.cc
  4. 123 0
      main/tianwen_wake_up_word/tianwen.cc
  5. 39 0
      main/tianwen_wake_up_word/tianwen.h

+ 1 - 0
main/CMakeLists.txt

@@ -15,6 +15,7 @@ set(SOURCES "audio_codecs/audio_codec.cc"
             "system_info.cc"
             "application.cc"
             "images/logo.c"
+            "tianwen_wake_up_word/tianwen.cc"
             "ota.cc"
             "settings.cc"
             "background_task.cc"

+ 8 - 0
main/application.cc

@@ -16,6 +16,7 @@
 #include <driver/gpio.h>
 #include <arpa/inet.h>
 #include <esp_app_desc.h>
+#include "tianwen_wake_up_word/tianwen.h"
 
 #define TAG "Application"
 
@@ -315,6 +316,13 @@ void Application::Start() {
     auto& board = Board::GetInstance();
     SetDeviceState(kDeviceStateStarting);
 
+    // 创建GPIO5中断处理器实例并初始化,暂时不用
+    // static Gpio5InterruptHandler gpio5_handler;
+    // if (gpio5_handler.init() != ESP_OK) {
+    //     ESP_LOGE("main", "GPIO5 interrupt initialization failed");
+    //     return;
+    // }
+
     /* Setup the display */
     auto display = board.GetDisplay();
 

+ 2 - 73
main/main.cc

@@ -17,37 +17,6 @@
 #include "freertos/task.h"
 #include "freertos/queue.h"
 
-// 使用GPIO_NUM_5替代直接整数,确保类型正确
-#define GPIO_INPUT_IO_0     GPIO_NUM_5
-#define GPIO_INPUT_PIN_SEL  (1ULL << GPIO_INPUT_IO_0)
-#define ESP_INTR_FLAG_DEFAULT 0
-
-// 使用QueueHandle_t替代xQueueHandle(FreeRTOS现代版本兼容)
-static QueueHandle_t gpio_evt_queue = NULL;
-
-static void IRAM_ATTR gpio_isr_handler(void* arg)
-{
-    uint32_t gpio_num = (uint32_t)arg;
-    // 优化中断处理:添加上下文切换判断
-    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
-    xQueueSendFromISR(gpio_evt_queue, &gpio_num, &xHigherPriorityTaskWoken);
-    if (xHigherPriorityTaskWoken) {
-        portYIELD_FROM_ISR();
-    }
-}
-
-static void gpio_task_example(void* arg)
-{
-    uint32_t io_num;
-    for (;;) {
-        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
-            // 修复格式符和类型转换
-            printf("GPIO[%u] intr, val: %d\n", 
-                   (unsigned int)io_num, 
-                   gpio_get_level((gpio_num_t)io_num));
-        }
-    }
-}
 
 extern "C" void app_main(void)
 {
@@ -63,46 +32,6 @@ extern "C" void app_main(void)
     }
     ESP_ERROR_CHECK(ret);
 
-    // 配置GPIO
-    gpio_config_t io_conf = {};
-    io_conf.intr_type = GPIO_INTR_POSEDGE;       // 上升沿触发
-    io_conf.mode = GPIO_MODE_INPUT;              // 输入模式
-    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;   // 引脚掩码
-    io_conf.pull_up_en = GPIO_PULLUP_ENABLE;     // 使用枚举值替代整数1
-    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;// 显式禁用下拉
-    gpio_config(&io_conf);
-
-    // 创建事件队列
-    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
-    if (gpio_evt_queue == NULL) {
-        ESP_LOGE(TAG, "Failed to create GPIO event queue!");
-        return;
-    }
-
-    // 创建GPIO处理任务
-    xTaskCreate(gpio_task_example, 
-                "gpio_task_example", 
-                2048, 
-                NULL, 
-                10, 
-                NULL);
-
-    // 安装GPIO中断服务
-    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT));
-    
-    // 注册中断处理函数
-    ESP_ERROR_CHECK(gpio_isr_handler_add(GPIO_INPUT_IO_0, 
-                                         gpio_isr_handler, 
-                                         (void*)GPIO_INPUT_IO_0));
-
-    ESP_LOGI(TAG, "GPIO5 interrupt (rising edge) configured successfully");
-    
-    // 主循环
-    while (1) {
-        // 修复宏定义名称(portTICK_RATE_MS已废弃)
-        vTaskDelay(pdMS_TO_TICKS(1000));
-    }
-
-    // 应用程序启动代码(如需启用请取消注释)
-    // Application::GetInstance().Start();
+    // 启动应用程序(如果有)
+    Application::GetInstance().Start();
 }

+ 123 - 0
main/tianwen_wake_up_word/tianwen.cc

@@ -0,0 +1,123 @@
+#include "tianwen.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "esp_event.h"
+#include "driver/gpio.h"  // 确保包含此头文件(定义了ESP_INTR_FLAG_DEFAULT)
+#define TAG "Application"
+
+// 静态成员初始化
+QueueHandle_t Gpio5InterruptHandler::s_gpio_evt_queue = nullptr;
+
+// 构造函数
+Gpio5InterruptHandler::Gpio5InterruptHandler() 
+    : m_gpio_num(GPIO_NUM_5), m_task_handle(nullptr) {
+    // 初始化成员变量
+}
+
+// 析构函数:清理资源
+Gpio5InterruptHandler::~Gpio5InterruptHandler() {
+    // 删除任务(如果存在)
+    if (m_task_handle != nullptr) {
+        vTaskDelete(m_task_handle);
+        m_task_handle = nullptr;
+    }
+
+    // 删除队列(如果存在)
+    if (s_gpio_evt_queue != nullptr) {
+        vQueueDelete(s_gpio_evt_queue);
+        s_gpio_evt_queue = nullptr;
+    }
+
+    // 移除中断处理函数并卸载中断服务
+    gpio_isr_handler_remove(m_gpio_num);
+    gpio_uninstall_isr_service();
+}
+
+// 中断服务程序(ISR):将事件放入队列
+void IRAM_ATTR Gpio5InterruptHandler::isr_handler(void* arg) {
+    uint32_t gpio_num = (uint32_t)arg;
+    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+    // 向队列发送中断事件
+    xQueueSendFromISR(s_gpio_evt_queue, &gpio_num, &xHigherPriorityTaskWoken);
+    // 如果需要,触发任务切换
+    if (xHigherPriorityTaskWoken) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+// 任务包装函数:转发到成员函数
+void Gpio5InterruptHandler::task_wrapper(void* arg) {
+    // 将void*转换为类实例指针,调用成员函数
+    static_cast<Gpio5InterruptHandler*>(arg)->task_handler();
+}
+
+// 实际的任务处理逻辑:从队列接收事件并处理
+void Gpio5InterruptHandler::task_handler() {
+    uint32_t io_num;
+    for (;;) { // 无限循环,等待中断事件
+        if (xQueueReceive(s_gpio_evt_queue, &io_num, portMAX_DELAY)) {
+            // 打印中断信息和当前电平
+            ESP_LOGI(TAG, "GPIO[%u] interrupt, value: %d",
+                     (unsigned int)io_num,
+                     gpio_get_level((gpio_num_t)io_num));
+        }
+    }
+}
+
+// 初始化函数:配置GPIO和中断
+esp_err_t Gpio5InterruptHandler::init() {
+    // 配置GPIO参数
+    gpio_config_t io_conf = {};
+    io_conf.intr_type = GPIO_INTR_POSEDGE;       // 上升沿触发
+    io_conf.mode = GPIO_MODE_INPUT;              // 输入模式
+    io_conf.pin_bit_mask = (1ULL << m_gpio_num); // 引脚掩码(仅GPIO5)
+    io_conf.pull_up_en = GPIO_PULLUP_ENABLE;     // 启用上拉电阻
+    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;// 禁用下拉电阻
+
+    // 应用GPIO配置
+    esp_err_t ret = gpio_config(&io_conf);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "GPIO configuration failed: %s", esp_err_to_name(ret));
+        return ret;
+    }
+
+    // 创建中断事件队列(容量10,每个元素为uint32_t)
+    s_gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
+    if (s_gpio_evt_queue == nullptr) {
+        ESP_LOGE(TAG, "Failed to create GPIO event queue");
+        return ESP_FAIL;
+    }
+
+    // 创建中断处理任务
+    ret = xTaskCreate(
+        task_wrapper,          // 任务函数(静态包装函数)
+        "gpio5_intr_task",     // 任务名称
+        2048,                  // 任务栈大小
+        this,                  // 传递给任务的参数(类实例指针)
+        10,                    // 任务优先级
+        &m_task_handle         // 任务句柄输出
+    );
+    if (ret != pdPASS) {
+        ESP_LOGE(TAG, "Failed to create interrupt task");
+        vQueueDelete(s_gpio_evt_queue); // 回滚:删除已创建的队列
+        s_gpio_evt_queue = nullptr;
+        return ESP_FAIL;
+    }
+
+    // 安装GPIO中断服务
+    ret = gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to install ISR service: %s", esp_err_to_name(ret));
+        return ret;
+    }
+
+    // 为GPIO5注册中断处理函数
+    ret = gpio_isr_handler_add(m_gpio_num, isr_handler, (void*)m_gpio_num);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to add ISR handler: %s", esp_err_to_name(ret));
+        return ret;
+    }
+
+    ESP_LOGI(TAG, "GPIO5 rising edge interrupt initialized successfully");
+    return ESP_OK;
+}

+ 39 - 0
main/tianwen_wake_up_word/tianwen.h

@@ -0,0 +1,39 @@
+#ifndef GPIO5_TIANWEN_H
+#define GPIO5_TIANWEN_H
+
+#include "esp_err.h"
+#include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include "freertos/task.h"
+#include "driver/gpio.h"  // 确保包含此头文件(定义了ESP_INTR_FLAG_DEFAULT)
+#define ESP_INTR_FLAG_DEFAULT 0
+
+class Gpio5InterruptHandler {
+private:
+    static QueueHandle_t s_gpio_evt_queue;   // 中断事件队列(静态,供ISR使用)
+    
+    gpio_num_t m_gpio_num;                   // GPIO引脚号
+    TaskHandle_t m_task_handle;              // 中断处理任务句柄
+
+    // 中断服务程序(ISR),必须为静态函数
+    static void IRAM_ATTR isr_handler(void* arg);
+
+    // 任务包装函数(静态),用于转发到成员函数
+    static void task_wrapper(void* arg);
+
+    // 实际的中断事件处理任务(成员函数)
+    void task_handler();
+
+public:
+    // 构造函数:初始化GPIO引脚为GPIO5
+    Gpio5InterruptHandler();
+
+    // 析构函数:释放资源
+    ~Gpio5InterruptHandler();
+
+    // 初始化函数:配置GPIO和中断服务
+    esp_err_t init();
+};
+
+#endif // GPIO5_INTERRUPT_H