前言
最近在做一个按键检测,按键检测有两种方法,一种是轮询法,即在rtos中建立一个任务,然后在死循环中判断按键状态,还有一种方式是使用中断,注册一个事件,事件触发后,会向RTOS队列写入数据。
在官方示例examplesperipheralsgpio中有相关代码
流程
选定gpio
首先选定gpio,由于我使用4个按键,故需要四个gpio
#define INPUT_UP 34
#define INPUT_LEFT 35
#define INPUT_RIGHT 32
#define INPUT_DOWN 33
#define GPIO_INPUT_PIN_SEL ((1ULL<
#define ESP_INTR_FLAG_DEFAULT 0//设置一个flag标志位
static xQueueHandle gpio_evt_queue = NULL;//消息队列
gpio配置
首先初始化gpio结构体 gpio_config_t io_conf;
然后配置触发类型 io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
一共有一下类型
typedef enum {
GPIO_PIN_INTR_DISABLE = 0,//不使能
GPIO_PIN_INTR_POSEDGE = 1,//上升沿
GPIO_PIN_INTR_NEGEDGE = 2,//下降沿
GPIO_PIN_INTR_ANYEDGE = 3,//任何变化
GPIO_PIN_INTR_LOLEVEL = 4,//低电平触发
GPIO_PIN_INTR_HILEVEL = 5//高电平触发
} GPIO_INT_TYPE;
由于我将按键一端接在3.3v,所以这里选择下降沿触发。
然后选择io口
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
然后设置模式,由于是下降沿触发,故平常应该io口上拉,使能并配置
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
设置回调函数
首先初始化队列,然后创建一个接受函数
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
start gpio task
xTaskCreate(anjian, "get down", 2048, NULL, 10, NULL);
在接受函数中读取队列信息
static void anjian(void* arg)
{
uint32_t io_num;
for(;;) {
if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
printf("GPIO[%d] intr, val: %dn", io_num, gpio_get_level(io_num));
}
}
}
注册中断处理程序
注册中断函数,并将按键触发加入中断函数
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(INPUT_UP, gpio_isr_handler, (void*) INPUT_UP);
gpio_isr_handler_add(INPUT_DOWN, gpio_isr_handler, (void*) INPUT_DOWN);
gpio_isr_handler_add(INPUT_LEFT, gpio_isr_handler, (void*) INPUT_LEFT);
gpio_isr_handler_add(INPUT_RIGHT, gpio_isr_handler, (void*) INPUT_RIGHT);
按键触发后将进入gpio_isr_handler回调函数中,然后在中断函数中将按键标号写入队列。
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
然后就是在之前的按键函数中从队列中读取按键信息
前言
最近在做一个按键检测,按键检测有两种方法,一种是轮询法,即在rtos中建立一个任务,然后在死循环中判断按键状态,还有一种方式是使用中断,注册一个事件,事件触发后,会向RTOS队列写入数据。
在官方示例examplesperipheralsgpio中有相关代码
流程
选定gpio
首先选定gpio,由于我使用4个按键,故需要四个gpio
#define INPUT_UP 34
#define INPUT_LEFT 35
#define INPUT_RIGHT 32
#define INPUT_DOWN 33
#define GPIO_INPUT_PIN_SEL ((1ULL<
#define ESP_INTR_FLAG_DEFAULT 0//设置一个flag标志位
static xQueueHandle gpio_evt_queue = NULL;//消息队列
gpio配置
首先初始化gpio结构体 gpio_config_t io_conf;
然后配置触发类型 io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
一共有一下类型
typedef enum {
GPIO_PIN_INTR_DISABLE = 0,//不使能
GPIO_PIN_INTR_POSEDGE = 1,//上升沿
GPIO_PIN_INTR_NEGEDGE = 2,//下降沿
GPIO_PIN_INTR_ANYEDGE = 3,//任何变化
GPIO_PIN_INTR_LOLEVEL = 4,//低电平触发
GPIO_PIN_INTR_HILEVEL = 5//高电平触发
} GPIO_INT_TYPE;
由于我将按键一端接在3.3v,所以这里选择下降沿触发。
然后选择io口
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
然后设置模式,由于是下降沿触发,故平常应该io口上拉,使能并配置
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
设置回调函数
首先初始化队列,然后创建一个接受函数
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
start gpio task
xTaskCreate(anjian, "get down", 2048, NULL, 10, NULL);
在接受函数中读取队列信息
static void anjian(void* arg)
{
uint32_t io_num;
for(;;) {
if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
printf("GPIO[%d] intr, val: %dn", io_num, gpio_get_level(io_num));
}
}
}
注册中断处理程序
注册中断函数,并将按键触发加入中断函数
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(INPUT_UP, gpio_isr_handler, (void*) INPUT_UP);
gpio_isr_handler_add(INPUT_DOWN, gpio_isr_handler, (void*) INPUT_DOWN);
gpio_isr_handler_add(INPUT_LEFT, gpio_isr_handler, (void*) INPUT_LEFT);
gpio_isr_handler_add(INPUT_RIGHT, gpio_isr_handler, (void*) INPUT_RIGHT);
按键触发后将进入gpio_isr_handler回调函数中,然后在中断函数中将按键标号写入队列。
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
然后就是在之前的按键函数中从队列中读取按键信息
举报