OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 31|回复: 0

《ESP32-P4开发指南— V1.0》第十三章 EXIT实验

[复制链接]

1215

主题

1229

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5232
金钱
5232
注册时间
2019-5-8
在线时间
1321 小时
发表于 11 小时前 | 显示全部楼层 |阅读模式
第十三章 EXIT实验

1)实验平台:正点原子DNESP32P4开发板

2)章节摘自【正点原子】ESP32-P4开发指南— V1.0

3)购买链接:https://detail.tmall.com/item.htm?id=873309579825

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子DNESP32S3开发板技术交流群:132780729


2.jpg

3.png

本章将详细介绍如何将GPIO引脚配置为外部中断输入,帮助开发者掌握GPIO中断的基础使用方法。这部分内容对处理按键输入、传感器信号等外部事件至关重要,通过中断方式可以有效提高系统的响应效率。
本章分为如下几个小节:
13.1 外部中断介绍
13.2 硬件设计
13.3 程序设计
13.4 下载验证


13.1 外部中断介绍
在上一章节中,我们虽然实现了GPIO口输入功能的读取,但代码始终在检测IO输入口的变化,导致在代码量增加时,按键检测部分的轮询效率降低。尤其在某些特定场合,如按键可能一天才被按下一次,实时检测将造成大量时间浪费。为优化此问题,我们引入了外部中断的概念。外部中断即在按键被按下(触发中断)时执行相关功能,从而显著节省CPU资源,因此在实际项目中应用广泛。

13.1.1 什么是中断
外部中断属于硬件中断,由微控制器外部事件触发。微控制器的特定引脚被设计为对特定事件(如按钮按压、传感器信号变化等)作出响应,这些引脚通常称为“外部中断引脚”。一旦外部中断事件发生,当前程序执行将立即暂停,并跳转到相应的中断服务程序(ISR)进行处理。处理完毕后,程序会恢复执行,从被中断的地方继续。下图是CPU中断处理过程。

第十三章 EXIT实验530.png
图13.1.1 CPU中断处理过程

对于嵌入式和实时系统而言,外部中断的使用至关重要,它能使系统对外部事件作出即时响应,极大提升系统效率和实时性。

13.1.2 ESP32-P4外部中断介绍
ESP32-P4的HP IO MUX和HP GPIO矩阵提供了强大的中断处理能力,允许开发者配置GPIO引脚以响应外部事件。这些事件可以是按键按下、传感器信号变化等。ESP32-P4的HP IO MUX和HP GPIO矩阵可以生成以下中断信号,供中断矩阵处理。中断矩阵的相关知识请看第二章节的内容。
1)GPIO_INTR0
2)GPIO_INTR1
3)GPIO_INTR2
4)GPIO_INTR3
5)GPIO_PAD_COMP_INTR
ESP32-P4的中断矩阵为开发者提供了灵活的外部事件响应机制。ESP32-P4的55个GPIO引脚可以通过任意一个内部中断信号(GPIO_INTR0、GPIO_INTR1、GPIO_INTR2、GPIO_INTR3)来响应外部事件。这些中断信号通过中断矩阵传递和处理,确保系统可以快速响应和执行。其中,GPIO_PAD_COMP_INTR 是一种特殊的中断信号,与模拟电压比较器相关。详细信息可以参考《ESP32-P4技术参考手册》中的模拟电压比较器(Analog Voltage Comparator)章节。
根据本书籍第二章的2.4.5小节中的图2.4.5.2所示位置,可以找到GPIO_INTR0、GPIO_INTR1、GPIO_INTR2和GPIO_INTR3这些内部中断源的中断号,它们分别对应中断号74至77号,如下图所示。

第十三章 EXIT实验1221.png
图13.1.2.1 GPIO_INTR0等CPU外设中断源映射和状态寄存器

这些中断信号由ESP32-P4的GPIO引脚触发,并通过中断矩阵传递给处理器核心以响应外部事件。至于如何配置这55个GPIO的触发条件,实际上笔者在LED实验时已经讲解过,GPIO管脚支持外部中断配置。外部中断具备两种主要的触发类型:电平触发和边沿触发。电平触发指的是高电平和低电平触发,而边沿触发则包含上升沿、下降沿和任意沿的触发。
下图展示了配置这四个内部中断源(GPIO_INTR0、GPIO_INTR1、GPIO_INTR2、GPIO_INTR3)触发条件的寄存器。


1.png
表13.1.2.1 HP IO MUX和HP GPIO Matrix提供了内部中断源

上表13.1.2.1展示了ESP32-P4的HP IO MUX和HP GPIO Matrix中GPIO内部中断源的配置寄存器。针对GPIO_INTR0、GPIO_INTR1、GPIO_INTR2和GPIO_INTR3,可以通过配置不同的寄存器对GPIO的中断触发条件进行设置。
下面笔者以GPIO_INTR0为例讲解:
1)GPIO_STATUS_INTERRUPT[n] & GPIO_PINn_INT_ENA[0] (n: 0 ~ 31):用于配置GPIO0到GPIO31号引脚的启动中断。
2)GPIO_STATUS1_INTERRUPT[n] & GPIO_PINn+32_INT_ENA[0] (n: 0 ~ 22):用于配置GPIO32到GPIO54号引脚的中断触发类型。
其他内部中断(如GPIO_INTR1、GPIO_INTR2、GPIO_INTR3)的配置方式与GPIO_INTR0类似。下图为GPIO_STATUS_INTERRUPT和GPIO_PINn_INT_ENA[0] (n: 0 ~ 31)描述内容。


第十三章 EXIT实验2704.png

第十三章 EXIT实验2706.png
图13.1.2.2 GPIO_STATUS_INTERRUPT和GPIO_PINn_INT_ENA[0] (n: 0 ~ 31)描述

其他寄存器的详细描述,请参阅《ESP32-P4技术参考手册》中的7.18 节 “Interrupts”。
上述的内容是HP系统的外部中断相关内容,在低功耗(LP)系统下,ESP32-P4的LP IO MUX和GPIO矩阵可以生成LP_GPIO_INTR0中断信号(中断号为10),并通过中断矩阵发送至处理器。低功耗模式时,GPIO0~GPIO15由LP系统管理,允许将这些GPIO配置为外部中断,并由LP_GPIO_INTR0统一管理,如下图所示。


第十三章 EXIT实验3000.png
图13.1.2.3 LP IO MUX和LP GPIO矩阵内部中断源

在低功耗(LP)系统下,要开启GPIO0~GPIO15的中断,可以使用上图的LP_GPIO_STATUS_DATA[n](n: 0 ~ 15)寄存器开启中断。同时,使用LP_GPIO_PINn_INT_TYPE(n: 0 ~ 15)寄存器配置每个 GPIO 引脚的中断触发类型,包括高电平、低电平、上升沿、下降沿和任意沿触发。这些配置可以实现低功耗系统中对 GPIO 引脚的外部中断响应,有效支持低功耗操作模式下的外部事件监控需求。

13.2 硬件设计

13.2.1 例程功能
通过将BOOT按键配置为外部中断触发,可以在每次按下BOOT按键时触发中断处理程序,从而实现LED0的电平翻转效果。

13.2.2 硬件资源
1)LED灯
        LED        0        - IO51
2)KEY按键
        BOOT        - IO35

13.2.3 原理图
KEY原理图已在12.2.3小节中详细阐述,为避免重复,此处不再赘述。

13.3 程序设计

13.3.1 GPIO的IDF驱动
接下来,笔者将介绍常用的GPIO EXIT函数,这些函数的描述及其作用如下:
1,注册中断函数gpio_install_isr_service
该函数用于注册中断服务,其函数原型如下:
  1. esp_err_t gpio_install_isr_service(int intr_alloc_flags);
复制代码
函数参数:

2.png
表13.3.1.1 gpio_install_isr_service函数形参描述

返回值:
ESP_OK表示操作成功。
ESP_ERR_NO_MEM表示内存不足,无法安装服务。
ESP_ERR_INVALID_STATE表示ISR服务已安装,不能重复安装。
ESP_ERR_NOT_FOUND表示未找到符合指定标志的空闲中断。
ESP_ERR_INVALID_ARG表示GPIO参数错误。
2,分配中断函数gpio_isr_handler_add
该函数用于注册某个管脚的中断服务函数,其函数原型如下:
  1. esp_err_t gpio_isr_handler_add(        gpio_num_t gpio_num, gpio_isr_t isr_handler,
  2.                                                                 void *args);
复制代码
函数形参:

3.png
表13.3.1.2 gpio_isr_handler_add函数形参描述

返回值:
ESP_OK表示操作成功。
ESP_ERR_INVALID_STATE表示ISR服务未初始化或状态错误。
ESP_ERR_INVALID_ARG表示参数错误。
这里需要注意ISR处理程序函数的格式,如下所示。
  1. void (*gpio_isr_t)(void *arg);
复制代码
在编写中断回调函数时,需要注意。

13.3.2 程序流程图

第十三章 EXIT实验4711.png
图11.3.2.1 EXIT实验程序流程图

13.3.3 程序解析
在03_exit例程中,作者在03_exit\components\BSP路径下新建EXIT文件夹,并且需要更改CMakeLists.txt内容,以便在其他文件上调用。

1,EXIT驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。EXIT驱动源码包括两个文件:exit.c和exit.h。
下面先解析exit.h的程序。对EXIT引脚做了相关定义以及功能实现。
  1. <font size="3">/* 引脚定义 */</font>
  2. <font size="3">#define BOOT_INT_GPIO_PIN   GPIO_NUM_35</font>

  3. <font size="3">/* IO操作 */</font>
  4. <font size="3">#define BOOT_INT    gpio_get_level(BOOT_INT_GPIO_PIN)</font>
复制代码
上述源码,定义了BOOT按键所使用的GPIO 脚编号为 GPIO_NUM_35,即GPIO35,通过宏定义BOOT_INT,直接调用gpio_get_level(BOOT_INT_GPIO_PIN),用于读取GPIO_NUM_35引脚的电平状态。如果BOOT按键连接到GPIO35,可以直接使用BOOT_INT来判断引脚电平,从而检测 BOOT 按键的按下或释放状态。
下面我们再解析exit.c的程序,看一下初始化函数exit_init,代码如下:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief             外部中断初始化程序</font>
  3. <font size="3"> * [url=home.php?mod=space&uid=271674]@param[/url]             无</font>
  4. <font size="3"> * @retval            无</font>
  5. <font size="3"> */</font>
  6. <font size="3">void exit_init(void)</font>
  7. <font size="3">{</font>
  8. <font size="3">    gpio_config_t gpio_init_struct;</font>
  9. <font size="3">    /* 配置BOOT引脚和外部中断 */</font>
  10. <font size="3">    gpio_init_struct.mode = GPIO_MODE_INPUT;                    /* 输入模式 */</font>
  11. <font size="3">    gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE;           /* 上拉使能 */</font>
  12. <font size="3">    gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE;      /* 下拉失能 */</font>
  13. <font size="3">    gpio_init_struct.intr_type = GPIO_INTR_NEGEDGE;             /* 下降沿触发 */</font>
  14. <font size="3">    gpio_init_struct.pin_bit_mask = 1ull << BOOT_INT_GPIO_PIN;  /* 引脚位掩码 */</font>
  15. <font size="3">    ESP_ERROR_CHECK(gpio_config(&gpio_init_struct));            /* 配置使能 */</font>
  16. <font size="3">    </font>
  17. <font size="3">    /* 注册中断服务 */</font>
  18. <font size="3">    ESP_ERROR_CHECK(gpio_install_isr_service(0));</font>
  19. <font size="3">    /* 设置BOOT的中断回调函数 */</font>
  20. <font size="3">ESP_ERROR_CHECK(gpio_isr_handler_add(BOOT_INT_GPIO_PIN,</font>
  21. <font size="3">                                     exit_gpio_isr_handler, </font>
  22. <font size="3">(void*)BOOT_INT_GPIO_PIN));</font>
  23. <font size="3">}</font>
复制代码
该函数用于配置BOOT按键GPIO引脚为下降沿外部中断模式。通过设置GPIO为输入模式并启用弱上拉,在检测到按键从高电平切换为低电平时触发中断,并调用指定的中断处理函数,实现对按键按下事件的快速响应。如下代码为GPIO35外部中断服务函数exit_gpio_isr_handler。
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief             外部中断服务函数</font>
  3. <font size="3"> * @param             arg:中断引脚号</font>
  4. <font size="3"> * [url=home.php?mod=space&uid=60778]@note[/url]             IRAM_ATTR: 这里的IRAM_ATTR属性用于将中断处理函数存储在内部RAM中 </font>
  5. <font size="3"> * @retval           无</font>
  6. <font size="3"> */</font>
  7. <font size="3">static void IRAM_ATTR exit_gpio_isr_handler(void *arg)</font>
  8. <font size="3">{</font>
  9. <font size="3">    uint32_t gpio_num = (uint32_t) arg;</font>
  10. <font size="3">    </font>
  11. <font size="3">    if (gpio_num == BOOT_INT_GPIO_PIN)</font>
  12. <font size="3">    {</font>
  13. <font size="3">        /* 消抖 */</font>
  14. <font size="3">        esp_rom_delay_us(20000);</font>

  15. <font size="3">        if (BOOT_INT == 0)</font>
  16. <font size="3">        {</font>
  17. <font size="3">            LED0_TOGGLE();</font>
  18. <font size="3">        }</font>
  19. <font size="3">    }</font>
  20. <font size="3">}</font>
复制代码
exit_gpio_isr_handler函数是一个用于响应BOOT按键的外部中断处理程序。该函数利用IRAM_ATTR将中断服务函数加载到内部IRAM中,确保响应速度。通过传递的引脚号参数验证中断是否由BOOT引脚触发,若是,则执行20ms延迟以消除按键抖动。消抖后再次检测按键状态,若确认按键被按下(低电平),则切换LED的亮灭状态,达到按键控制LED的效果。

2,CMakeLists.txt文件
本例程的功能实现主要依靠EXIT驱动。要在main函数中,成功调用EXIT文件中的内容,就得需要修改BSP文件夹下的CMakeLists.txt文件,修改如下:
  1. <font size="3">set(src_dirs</font>
  2. <font size="3">                   LED</font>
  3. <font size="3">                   KEY</font>
  4. <font size="3">                   EXIT)</font>

  5. <font size="3">set(include_dirs</font>
  6. <font size="3">                  LED</font>
  7. <font size="3">                  KEY</font>
  8. <font size="3">                   EXIT)</font>

  9. <font size="3">set(requires</font>
  10. <font size="3">                  driver)</font>

  11. <font size="3">idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs}</font>
  12. <font size="3">                       REQUIRES ${requires})</font>

  13. <font size="3">component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)</font>
复制代码

3,main.c驱动代码
在main.c里面编写如下代码。
  1. <font size="3">void app_main(void)</font>
  2. <font size="3">{</font>
  3. <font size="3">    esp_err_t ret;</font>
  4. <font size="3">    </font>
  5. <font size="3">    ret = nvs_flash_init();     /* 初始化NVS */</font>
  6. <font size="3">if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)</font>
  7. <font size="3">    {</font>
  8. <font size="3">        ESP_ERROR_CHECK(nvs_flash_erase());</font>
  9. <font size="3">        ESP_ERROR_CHECK(nvs_flash_init());</font>
  10. <font size="3">    }</font>

  11. <font size="3">    led_init();     /* 初始化LED */</font>
  12. <font size="3">    exit_init();    /* 初始化EXIT */</font>

  13. <font size="3">    while(1)</font>
  14. <font size="3">    {</font>
  15. <font size="3">        vTaskDelay(pdMS_TO_TICKS(10));    /* 延时10ms */</font>
  16. <font size="3">    }</font>
  17. <font size="3">}</font>
复制代码
该函数调用了led_init和exit_init函数,分别用于初始化LED和配置BOOT按键外部中断。然后,通过一个无限循环和10ms的延时保持主任务的运行,使应用程序在后台持续待命,以便响应按键触发的中断事件。

13.4 下载验证
程序下载完之后,通过BOOT按键控制LED灯亮灭。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-12-16 20:45

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表