图12.3.1.1 EXIT实验程序流程图
12.3.2 EXIT函数解析
接下来,作者将介绍一些常用的GPIO EXIT函数,这些函数的描述及其作用如下:
1,注册中断函数
该函数用来注册中断服务,该函数原型如下所示:
void gpio_install_isr_service(esp_intr_alloc_flag_t flags);
该函数的形参描述如下表所示:
参数 | 描述 |
| 中断标志位 |
| 使用 Level 1 中断级别。在中断服务程序执行期间禁用同级别的中断 |
| 使用 Level 2 中断级别。在中断服务程序执行期间禁用同级别和 Level 1 的中断 |
| 使用边沿触发方式。使能 GPIO 边沿触发中断 |
| 使用中低水平触发方式。使能 GPIO 中低电平触发中断。 |
| 使用高电平触发方式。使能 GPIO 高电平触发中断 |
表12.3.2.1 gpio_install_isr_service函数形参描述
返回值:无。
2,分配中断函数
该函数设置某个管脚的中断服务函数,该函数原型如下所示:
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num,
gpio_isr_t isr_handler, void* args);
该函数的形参描述如下表所示:
参数 | 描述 |
| GPIO 引脚号,指定要分配中断处理程序的 GPIO 引脚 |
| 指向中断处理函数的函数指针。中断处理函数是一个用户定义的回调函数,将在中断发生时执行 |
| 传递给中断处理程序的参数。这是一个指向用户特定数据的指针,可以在中断处理程序中使用 |
表12.3.2.2 gpio_isr_handler_add函数形参描述
返回值:ESP_OK表示设置成功,ESP_FAIL表示设置失败。
实现一个中断服务程序的回调函数,在函数中处理中断响应。(其中函数名可以随意起名,但是要符合C语言标准)中断处理函数需要声明为 IRAM_ATTR,以确保其运行在内存中的可执行区域。下面是中断函数的模板。
void IRAM_ATTR gpio_isr_handler(void* arg) {
/* 处理中断响应 */
}
3,开启外部中断函数
该函数用来配置某个管脚开启外部中断,该函数原型如下所示:
void gpio_intr_enable(gpio_num_t gpio_num)
该函数的形参描述如下表所示:
参数 | 描述 |
| GPIO 引脚号,指定要分配中断处理程序的 GPIO 引脚 |
表12.3.2.3 gpio_intr_enable函数形参描述
返回值:无。
注意:在使用gpio_intr_enable()函数之前,开发者需要先通过gpio_install_isr_service()函数和gpio_isr_handler_add()函数来安装和注册中断处理程序。
12.3.3 EXIT驱动解析
在IDF版的03_exit例程中,作者在03_exit \components\BSP路径下新增了一个EXIT文件夹,用于存放exit.c和exit.h这两个文件。其中,exit.h文件负责声明EXIT相关的函数和变量,而exit.c文件则实现了EXIT的驱动代码。下面,我们将详细解析这两个文件的实现内容。
1,exit.h文件
/* 引脚定义 */
#define BOOT_INT_GPIO_PIN GPIO_NUM_0
/*IO操作*/
#define BOOT gpio_get_level(BOOT_INT_GPIO_PIN)
/* 函数声明 */
void exit_init(void); /* 外部中断初始化程序 */
2,exit.c文件
/**
* @NOTE IRAM_ATTR: 这里的IRAM_ATTR属性用于将中断处理函数存储在内部RAM中, 目的在于减少延迟
* @retval 无
*/
static void IRAM_ATTR exit_gpio_isr_handler(void *arg) {
uint32_t gpio_num = (uint32_t) arg;
if (gpio_num == BOOT_INT_GPIO_PIN)
{
LED_TOGGLE();
}
}
/**
* @brief 外部中断初始化程序
* @param 无
* @retval 无
*/
void exit_init(void)
{
gpio_config_t gpio_init_struct;
/* 配置BOOT引脚和外部中断 */
gpio_init_struct.mode = GPIO_MODE_INPUT; /* 选择为输入模式 */
gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; /* 上拉使能 */
gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 下拉失能 */
gpio_init_struct.intr_type = GPIO_INTR_NEGEDGE; /* 下降沿触发 */
gpio_init_struct.pin_bit_mask = 1ull << BOOT_INT_GPIO_PIN;
gpio_config(&gpio_init_struct); /* 配置使能 */
/* 注册中断服务 */
gpio_install_isr_service(ESP_INTR_FLAG_EDGE);
/* 设置GPIO的中断回调函数 */
gpio_isr_handler_add(BOOT_INT_GPIO_PIN, exit_gpio_isr_handler,
(void*) BOOT_INT_GPIO_PIN);
/* 使能GPIO模块中断信号 */
gpio_intr_enable(BOOT_INT_GPIO_PIN);
}
开启管脚的外部中断操作相对简便。首先,需要将管脚配置为下降沿触发(GPIO_INTR_NEGEDGE)和输入模式(GPIO_MODE_INPUT)。完成配置后,需要调用gpio_install_isr_service函数来注册中断服务,并调用gpio_isr_handler_add函数来注册外部中断的回调函数。最后,调用gpio_intr_enable函数启用外部中断功能。其中,exit_gpio_isr_handler回调函数负责实现LED灯状态的切换。
12.3.4 CMakeLists.txt文件
打开本实验BSP下的CMakeLists.txt文件,其内容如下所示:
set(src_dirs
EXIT
LED)
set(include_dirs
EXIT
LED)
set(requires
driver)
idf_component_register(SRC_DIRS ${src_dirs}
INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
上述的红色EXIT驱动需要由开发者自行添加,以确保EXIT驱动能够顺利集成到构建系统中。这一步骤是必不可少的,它确保了EXIT驱动的正确性和可用性,为后续的开发工作提供了坚实的基础。
12.3.5 实验应用代码
打开main/main.c文件,该文件定义了工程入口函数,名为app_main。该函数代码如下。
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t ret;
ret = nvs_flash_init(); /* 初始化NVS */
if (ret == ESP_ERR_NVS_NO_FREE_PAGES
|| ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
led_init(); /* 初始化LED */
exit_init(); /* 初始化按键 */
while(1)
{
vTaskDelay(10);
}
}
本实验的应用代码很简单,在初始化完LED和外部中断后,就进入一个while循环,以便通过串口助手查看单片机运行状态。另外,按键控制LED亮灭状态翻转的操作都在对应EXTI的中断服务函数中完成了。 12.4 下载验证
在完成编译和烧录操作后,可以看到板子上的LED处于亮起状态,若此时按下KEY按键,则能够看到LED处于熄灭状态。如此往复该操作,将会看到LED处在熄灭与亮起的状态之间转换,与预期的实验现象效果相符。