|
|
@@ -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;
|
|
|
+}
|