ESP32系列--第三篇 GPIO操作(IO中断)
一、目的在上一篇《ESP32系列--第三篇 GPIO操作(基本输入输出)》我们介绍了GPIO的基本操作,本篇在此基础上介绍GPIO的中断操作。上一篇的示例代码我们初始化GPIO4作为输入,然后代码里每隔一秒钟检查一次引脚状态,这种做法会有很多弊端,最致命的问题就是输入信号丢失,故一般场景中要么减小轮询时间,要么采用中断的方式实现。下面让我们介绍一下ESP32 GPIO的中断功能二、介绍ESP32
一、目的
在上一篇《ESP32系列--第三篇 GPIO操作(基本输入输出)》我们介绍了GPIO的基本操作,本篇在此基础上介绍GPIO的中断操作。
上一篇的示例代码我们初始化GPIO22作为输入,然后代码里每隔一秒钟检查一次引脚状态,这种做法会有很多弊端,最致命的问题就是输入信号丢失,故一般场景中要么减小轮询时间,要么采用中断的方式实现。
下面让我们介绍一下ESP32 GPIO的中断功能
二、介绍
ESP32 GPIO支持上升沿中断、下降沿中断、任意边沿中断、低电平中断以及高电平中断。
首先让我们看一下ESP-IDF中GPIO中断相关的API
GPIO & RTC GPIO - ESP32 - — ESP-IDF Programming Guide latest documentation (espressif.com)https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html 使用GPIO的中断功能,首先需要安装GPIO的全局中断服务
esp_err_t gpio_install_isr_service(int intr_alloc_flags)
接着我们需要初始化我们需要使用的GPIO,设置触发方式
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)
关于gpio_config_t此结构体各个字段的含义请查看上一篇博文。
IO初始化完成后,我们需要注册IO中断服务函数并且添加进芯片全局IO中断服务中,这样当对应的IO产生相应的事件后,就会触发我们注册的函数。
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args)
第一个参数就是引脚号(GPIO_NUM_X(X是对应的数字)),gpio_isr_t是函数指针类型,当gpio_num对应的引脚触发了对应的中断事件后,isr_handler这个函数就会被调用,args是回调函数的入参。
如果某个时刻我们想将某个IO中断关闭可以使用下面的函数
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num);
三、实战
我们以实际工程为例,给大家从源代码层面演示一下GPIO的使用
下面的代码我们初始化GPIO18为上拉输入上升沿触发,并且创建了一个线程gpio_task_example用于接收中断触发后给出的信号量gpio_sem,这种做法是线程和中断之间同步的标准做法;当然本示例中也可以使用消息队列来处理,这样就不会丢失事件了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define TAG "app"
#define ESP_INTR_FLAG_DEFAULT 0
static SemaphoreHandle_t gpio_sem;
#define GPIO_DEMO_PIN GPIO_NUM_18
static void IRAM_ATTR gpio_isr_handler(void* arg) {
xSemaphoreGiveFromISR(gpio_sem, NULL);
}
static void gpio_task_example(void* arg) {
for(;;) {
if (xSemaphoreTake(gpio_sem, portMAX_DELAY)) {
ESP_LOGI(TAG, "GPIO[%d] intr, val: %d\n", GPIO_DEMO_PIN, gpio_get_level(GPIO_DEMO_PIN));
}
}
}
void app_main(void) {
//install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
//zero-initialize the config structure.
gpio_config_t io_conf = {};
//interrupt of rising edge
io_conf.intr_type = GPIO_INTR_POSEDGE;
io_conf.pin_bit_mask = 1ULL << GPIO_DEMO_PIN;
//set as input mode
io_conf.mode = GPIO_MODE_INPUT;
//enable pull-up mode
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
gpio_sem = xSemaphoreCreateBinary();
//start gpio task
xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
gpio_isr_handler_add(GPIO_DEMO_PIN, gpio_isr_handler, NULL);
//如果某个时刻不想产生中断可以将其从中断服务中删除
//gpio_isr_handler_remove(GPIO_DEMO_PIN);
}
下面是实际运行日志
由于中断检测的精度很高,我们用杜邦线触碰GPIO18时会有抖动,所以可能一次触发会有很多打印。
以上,关于ESP32 GPIO中断的内容基本讲完;当然GPIO还有很多功能以及API,这个大家可以查看官网文档进行学习,就不一一讲解了。
更多推荐
所有评论(0)