ESP32学习笔记( VSCode + ESP-IDF环境) 2 —— GPIO学习和官方GPIO示例解读

文章介绍了ESP32在ESP-IDF框架下GPIO的配置方法,包括中断类型的设置、输入输出模式的选择以及上拉下拉模式的设定。同时,详细阐述了GPIO中断的使用,包括中断消息的发送、中断处理任务的实现,并提供了一个官方示例,展示了如何创建中断服务驱动、绑定中断服务函数以及处理中断事件。
摘要由CSDN通过智能技术生成

1、ESP32 GPIO介绍

在之前使用Arduino IDE 通过ESP32进行各模块单独测试的时候就已经接触过了,但是在Arduino IDE的环境下只需要进行一下pinMode,设置一下端口引脚是输入输出即可。在ESP-IDF中对于GPIO的设置就较为复杂了,但复杂带来的是更加全面的功能。
如果想理解ESP32所有GPIO的功能以及使用参数可以参考ESP32-GPIO引脚参考大全
在这片文章中可以看到ESP32所有的GPIO信息以及相关保留或是特殊GPIO的解读,写的非常详细。
关于GPIO中断的介绍,其实和51单片机以及其他单片机相似,总的来说看起来会相当乏味,本篇文章主要记录如何使用GPIO的中断,至于理论性的东西,还请移步至乐鑫官方对GPIO中断的介绍,其中也包括了GPIO的参数介绍,毕竟官方文档写出来的肯定是最全面(最啰嗦 最看不懂 最看不下去)的。乐鑫官方GPIO说明

1. GPIO的配置

  1. 引入头文件
    如果需要对GPIO进行配置,就需要引用driver/gpio的头文件。
#include "driver/ledc.h"
  1. 对GPIO进行配置
	//方法1
	gpio_config_t io_conf;  //创建GPIO控制结构体
    //对GPIO进行专项设置
    io_conf.intr_type      //设置GPIO中断类型
    io_conf.mode           //设置GPIO是输出还是输入模式
    io_conf.pin_bit_mask   //表明设置的是哪一个GPIO 通过 1ULL << GPIOx进行位计算告知
    io_conf.pull_down_en   //设置下拉模式 0:否 1:是
    io_conf.pull_up_en     //设置上拉模式 0:否 1:是
    gpio_config(&io_conf); //将上述配置进行生效
	
	//方法2 与方法1几乎一致,只是写法不同
	gpio_config_t io_conf1 = {	//创建GPIO控制结构体
    	.intr_type, 			//设置GPIO中断类型
    	.mode,					//设置GPIO是输出还是输入模式
    	.pin_bit_mask,			//表明设置的是哪一个GPIO 通过 1ULL << GPIOx进行位计算告知
    	.pull_down_en,			//设置下拉模式 0:否 1:是
    	.pull_up_en,			//设置上拉模式 0:否 1:是
    };
    gpio_config(&io_conf1);		//将上述配置进行生效

	//方法3 单个设置
	gpio_reset_pin(gpio_num_t gpio_num);//重置某个GPIO的配置							
	gpio_set_direction(gpio_num_tgpio_num, gpio_mode_tmode);//设置GPIO是输出还是输入模式
	gpio_set_level(gpio_num_t gpio_num, uint32_t level);//设置GPIO输出高低电平
	gpio_get_level(gpio_num_t gpio_num);//读取GPIO获取到的高低电平
	gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);//设置GPIO上拉还是下拉
	gpio_pullup_en();
	gpio_pullup_dis();
	gpio_pulldown_en();
	gpio_pulldown_dis();

2. GPIO中断官方示例详解

GPIO的中断流程可以简单概括为以下7个步骤:

  • 编写中断消息发出函数 gpio_isr_handler
    作用:向消息队列中发送中断消息。
  • 编写中断消息处理函数
    作用:在接收到消息队列中的中断消息后,按照传递来的参数和编写的中断语句执行对应的中断任务。
  • 通过GPIO设置是否开启中断,以及中断方式说明
  • 创建一个队列用于发送中断信息
  • 创建中断任务处理
  • 安装中断服务驱动
  • 给指定的GPIO绑定中断服务函数

一个简单的GPIO中断例程就用官方所给的例程来演示即可,规范例程注释都是英语,我听过机器翻译和自己浅薄的英语只是将其翻译成中文,相信看完这个例程,大家也都会对GPIO的中断有一个基本的理解。

/**
 * 演示效果:
 *  两个输出GPIO口不断输出高低电平
 *  两个输入GPIO口任意上下沿会触发中断
 *  为了对比GPIO5只支持上升沿中断,而GPIO4上下沿都可以触发
 *  最终GPIO4 每秒触发一次中断 GPIO5 每2秒触发一次中断
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"

#define GPIO_OUTPUT_IO_0    18
#define GPIO_OUTPUT_IO_1    19
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))  //表示此配置对 GPIO 0 和 GPIO 1 生效,采用位运算
#define GPIO_INPUT_IO_0     4
#define GPIO_INPUT_IO_1     5
#define GPIO_INPUT_PIN_SEL  ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))     //表示此配置对 GPIO 0 和 GPIO 1 生效,采用位运算
#define ESP_INTR_FLAG_DEFAULT 0

static xQueueHandle gpio_evt_queue = NULL;

/*中断处理函数程序*/
/*任务:负责发出中断消息*/
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    /*向消息队列中发送消息,消息内容就是需要处理的GPIO号*/
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

/*中断消息处理任务*/
/*负责处理中断*/
static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    for(;;) {
        /*只要接收到了消息就开是对应任务处理*/
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            /*这里的任务就是打出一行话*/
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

void app_main(void)
{
    gpio_config_t io_conf;  //创建GPIO控制结构体
    //对GPIO进行专项设置
    io_conf.intr_type = GPIO_INTR_DISABLE;      //禁用GPIO中断
    io_conf.mode = GPIO_MODE_OUTPUT;            //设置GPIO为输出模式
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //表明设置的GPIO内容是谁 这里是对GPIO_OUTPUT_IO_0 18和GPIO_OUTPUT_IO_1 19起作用
    io_conf.pull_down_en = 0;                   //不设置为下拉模式
    io_conf.pull_up_en = 0;                     //不设置为上拉模式
    gpio_config(&io_conf);                      //将上述配置进行生效

    //开始下一项GPIO的配置
    io_conf.intr_type = GPIO_INTR_POSEDGE;      //设置GPIO上升沿中断
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;  //表明设置的GPIO内容是谁 这里是对GPIO_INPUT_IO_0 4和GPIO_INPUT_IO_1 5起作用
    io_conf.mode = GPIO_MODE_INPUT;             //设置GPIO为输入模式
    io_conf.pull_up_en = 1;                     //设置为上拉模式
    gpio_config(&io_conf);                      //将上述配置生效

    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); //配置中断类型(中断引脚: GPIO4, 中断类型:任意边沿中断)

    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));    //创建一个队列用于发送中断信息 xQueueCreate参数:队列中包含最大项目数量, 队列中每个项目所要的字节数
    //开始中断任务处理 传入参数(具体处理中断任务的函数, 任务函数名, 任务栈大小, 任务参数, 任务优先级, 任务句柄)
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);  

    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);    //安装中断服务驱动(默认为参数优先级)
    //给指定的GPIO绑定中断服务函数 参数(需要设置的GPIO号, 对应GPIO端口的中断消息产生函数, 传递给中断消息产生函数需要的参数)
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1);

    //一下两行,官方例程纯属为了展示gpio_isr_handler_remove的用法
    gpio_isr_handler_remove(GPIO_INPUT_IO_0);   //删除对应GPIO号的中断服务函数
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);   //重新添加回来

    int cnt = 0;
    while(1) {
        printf("cnt: %d\n", cnt++);
        vTaskDelay(1000 / portTICK_RATE_MS);
        gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2);
        gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2);
    }
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值