您尚未登录。

楼主 #1 2018-05-18 17:07:42

半颗心脏
会员
注册时间: 2018-05-18
已发帖子: 1
积分: 1

认识基本esp32的GPIO接口,开始点亮您的第一盏 LED和中断回调实现按键功能

1、 爬坑学习新旅程,虚拟机搭建esp32开发环境,打印 “Hellow World”。https://blog.csdn.net/xh870189248/article/details/80208099

2、 巧用eclipes编辑器,官方教程在在Windows下搭建esp32开发环境,打印 “Hellow World”:https://blog.csdn.net/xh870189248/article/details/80304624

----------

一 、前言;


   - `GPIO`口一直是单片机的主要功能,今天小徐带来的是正是`GPIO`使用;本博文使用的是安信可的`esp32s`模组;
   - 本篇主要学习了怎么使用`esp32`的GPIO口,包括<font color=red>高低电平输入、高低电平输出和`GPIO`的中断使用;</font>
 

-----------

二 、输出低电平,点亮一盏`LED`;


- 电路图接法如下图:

![这里写图片描述](https://img-blog.csdn.net/20180517171706238?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoODcwMTg5MjQ4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

---------------------

- 第一种方法,较为简单:

```

gpio_pad_select_gpio(GPIO_NUM_16);//选择一个GPIO
gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT);//把这个GPIO作为输出
gpio_set_level(BLINK_GPIO, 0);//把这个GPIO输出低电平

```
---------------------
- 第二种方法,使用结构体来定义:

```
    gpio_config_t io_conf;
    //进制中断
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //选择为输出模式
    io_conf.mode = GPIO_MODE_OUTPUT;
    //配置GPIO_OUT寄存器
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //禁止下拉
    io_conf.pull_down_en = 0;
    //禁止上拉
    io_conf.pull_up_en = 0;
    //最后配置使能
    gpio_config(&io_conf);
```
---------------------
- 输出低电平:


```
gpio_set_level(BLINK_GPIO, 0); //第一个参数是GPIO,第二个是0或1
```

-----------

三 、获取某个`GPIO`的电平,并且打印出来;

----------
- 如果你要获取当前的电平状态,请把此配置`io_conf.mode`模式为`GPIO_MODE_INPUT`,表示为输入模式;见下面的源码可看到有多个输入输出模式,还有把此`GPIO`设置为不可用!可见`esp32`的`API`丰富啊!


下面的代码示范效果为:<font color= red> 每时隔 `500ms`读取`GPIO16`的输入电平状态,并且打印出来!
```
    //第一种方式配置
    //gpio_pad_select_gpio(BLINK_GPIO);
    //gpio_set_direction(BLINK_GPIO, GPIO_MODE_INPUT);

    //第二种方式配置
    gpio_config_t io_conf;
    //进制中断
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //选择为输出模式
    io_conf.mode = GPIO_MODE_INPUT;
    //配置GPIO_OUT寄存器
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //禁止下拉
    io_conf.pull_down_en = 0;
    //禁止上拉
    io_conf.pull_up_en = 0;
    //最后配置使能
    gpio_config(&io_conf);

    // 挂起500ms
    const portTickType xDelay = 500 / portTICK_RATE_MS;

    while (1) {
        printf(" Current Gpio16 Level is : %d \r\n\r\n",
                gpio_get_level(BLINK_GPIO));
        vTaskDelay(xDelay);
    }
```


-----------

四 、配置某个`GPIO`的低/高电平触发事件,并且打印出来;


------------------
4.1:下降沿触发中断:

![这里写图片描述](https://img-blog.csdn.net/2018051811292726?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoODcwMTg5MjQ4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

------------------

- 下面的代码实现的效果的是:中断触发按键按下来,触发中断,执行回调函数;
- 注意①:`中断触发按键`连接的是`GND`和`GPIO14`,因为是下降沿触发,所以必须一边接地!!
- 注意②:代码中要设置<font color=red>**输入模式,不下拉,内部上拉!**</font>原因在于内部上拉,就是高电平短脚,可以检测到下降沿。

------------------

```
    //GPIO口结构体定义
    gpio_config_t io_conf;
    //下降沿触发中断方式
    io_conf.intr_type = GPIO_INTR_NEGEDGE;
    //选择为输出模式
    io_conf.mode = GPIO_MODE_INPUT;
    //配置GPIO_OUT寄存器
    io_conf.pin_bit_mask = GPIO_SEL_4;
    //内部不下拉
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    //内部上拉
    io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
    //最后配置使能
    gpio_config(&io_conf);
```

-------------


####  4.2:上升沿触发中断:


![这里写图片描述](https://img-blog.csdn.net/20180518113613232?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoODcwMTg5MjQ4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)



------------------

- 下面的代码实现的效果的是:中断触发按键按下来,触发中断,执行回调函数;
- 注意①:`中断触发按键`连接的是`VCC`和`GPIO14`,因为是上升沿触发,所以必须一边接高电平!!
- 注意②:代码中要设置<font color=red>**输入模式,不上拉,内部下拉!**</font>原因在于内部下拉时候,就是低电平短脚输入,可以检测到上升沿。

------------------

```
    //GPIO口结构体定义
    gpio_config_t io_conf;
    //上升沿触发
    io_conf.intr_type = GPIO_INTR_POSEDGE;
    //选择为输出模式
    io_conf.mode = GPIO_MODE_INPUT;
    //配置GPIO_OUT寄存器
    io_conf.pin_bit_mask = GPIO_SEL_4;
    //内部下拉
    io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
    //禁止上拉
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    //最后配置使能
    gpio_config(&io_conf);
```

-------------

- 【其他】中断类型枚举:





```
GPIO_INTR_DISABLE //禁用GPIO中断
GPIO_INTR_POSEDGE //GPIO中断类型:上升沿
GPIO_INTR_NEGEDGE //下降沿
GPIO_INTR_ANYEDGE //上升沿和下降沿
GPIO_INTR_LOW_LEVEL //输入低电平触发
GPIO_INTR_HIGH_LEVEL //输入高电平触发
```
-----------

### 四 、配置某个`GPIO`的低/高电平触发事件,并且打印出来;


--------------

  -  嵌入式系统`rtos`的强大之处可以自行调度任务的优先级、任务的自由切换,最大程度的省下了`MCU`的空间资源。我也是初入`rtos`这趟深水,以上的图片是我个人的见解,如果有错,请留言,我立刻纠正!
  >**过程如下:**
   - ①:中断发生的中断,中断回调方法发送一个消息队列,消息队列包含了`GPIO`对应的端口号!
   - ②:另外一个任务不断从这个消息队列的句柄中获取消息并且可以做其他操作!
   - ③:上面可以看到,这是一个异步的操作,其中在串口中断的回调函数中,是加载在`IRAM_ATTR`中,注意连个简单的`printf()`函数调用都会报错。

-----------
- 以下为完整的代码:

```
#include <stdio.h>
#include "esp_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"

//宏定义一个中断端口
#define GPIO_INPUT_IO_0     4
static xQueueHandle gpio_evt_queue = NULL; //定义一个队列返回变量

void IRAM_ATTR gpio_isr_handler(void* arg) {
    //把中断消息插入到队列的后面,将gpio的io参数传递到队列中
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

//低电平触发的回调方法
void gpio_low_interrupt_callBack(void* arg) {
    printf(" \r\n into gpio_low_interrupt_callBack ...\r\n  ");
    uint32_t io_num;
    while (1) {
        //不断读取gpio队列,读取完后将删除队列
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            printf("GPIO[%d] 中断触发, 当前的电压: %d\n", io_num,
                    gpio_get_level(io_num));
        }
    }
}

void fun_set_gpio_low_interrupt() {

    //GPIO口结构体定义
    gpio_config_t io_conf;
    //下降沿触发
    io_conf.intr_type = GPIO_INTR_NEGEDGE;
    //选择为输出模式
    io_conf.mode = GPIO_MODE_INPUT;
    //配置GPIO_OUT寄存器
    io_conf.pin_bit_mask = GPIO_SEL_4;
    //设置下拉
    io_conf.pull_down_en = 0;
    //设置上拉
    io_conf.pull_up_en = 1;
    //最后配置使能
    gpio_config(&io_conf);

    //注册中断服务
    gpio_install_isr_service(1);
    //设置GPIO的中断回调函数
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler,
            (void*) GPIO_INPUT_IO_0);

    //创建一个消息队列,从中获取队列句柄
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));

    //新建队列的
    xTaskCreate(gpio_low_interrupt_callBack //任务函数
            , "gpio_task_example" //任务名字
            , 2048  //任务堆栈大小
            , NULL  //传递给任务函数的参数
            , 10   //任务优先级
            , NULL); //任務句柄

}

```

------------

- 本博文的代码工程下载:https://download.csdn.net/download/xh870189248/10423438

- ESP8266学习之旅代码汇总,欢迎`star`:https://github.com/xuhongv/StudyInEsp8266

- ESP32学习之旅代码汇总,欢迎`star`:https://github.com/xuhongv/StudyInEsp32

最近编辑记录 半颗心脏 (2018-05-18 17:10:51)

离线

#2 2018-05-18 17:50:46

晕哥
管理员
所在地: 微信 whycan_cn
注册时间: 2017-09-06
已发帖子: 9,233
积分: 9197

Re: 认识基本esp32的GPIO接口,开始点亮您的第一盏 LED和中断回调实现按键功能

感谢分享!





离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn