一、GPIO介绍
-
IO数量及功能
关于esp8266的板子上的引脚,是这样子的,ESP芯片一共33个个引脚,其中包括电源,使能引脚、深度睡眠唤醒引脚、SPI引脚以及连接晶振和作为烧写Flash的引脚。所谓的GPIO(General-purpose input/output)引脚一共有17个,esp8266的SDK把其放进了一个枚举类型里。源码如下:typedef enum { GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ GPIO_NUM_2 = 2, /*!< GPIO2, input and output */ GPIO_NUM_3 = 3, /*!< GPIO3, input and output */ GPIO_NUM_4 = 4, /*!< GPIO4, input and output */ GPIO_NUM_5 = 5, /*!< GPIO5, input and output */ GPIO_NUM_6 = 6, /*!< GPIO6, input and output */ GPIO_NUM_7 = 7, /*!< GPIO7, input and output */ GPIO_NUM_8 = 8, /*!< GPIO8, input and output */ GPIO_NUM_9 = 9, /*!< GPIO9, input and output */ GPIO_NUM_10 = 10, /*!< GPIO10, input and output */ GPIO_NUM_11 = 11, /*!< GPIO11, input and output */ GPIO_NUM_12 = 12, /*!< GPIO12, input and output */ GPIO_NUM_13 = 13, /*!< GPIO13, input and output */ GPIO_NUM_14 = 14, /*!< GPIO14, input and output */ GPIO_NUM_15 = 15, /*!< GPIO15, input and output */ GPIO_NUM_16 = 16, /*!< GPIO16, input and output */ GPIO_NUM_MAX = 17, /** @endcond */ } gpio_num_t;
-
初始化函数及结构体
众所周知,想使用一个东西之前,一定要先把其初始化,如果是使用C语言,又要初始化一个比较多参数的东东,那估计就要用结构体了,ESP82666 GPIO的初始化函数是esp_err_t gpio_config(const gpio_config_t * pGPIOConfig ) //参数是gpio_config_t 类型的指针
这个函数的返回值是esp_err_t,其值如果是ESP_OK就代表成功,如果是ESP_ERR_INVALID_ARG意思是参数错误,这个时候我们就要去检查一次参数了,参数是什么呢?参数是gpio_config_t 类型的指针
那我们再看一下gpio_config_t 的定义:
/** * @brief gpio_config函数的配置参数 */ typedef struct { uint32_t pin_bit_mask; /*!< 引脚: 32位的参数,每一位对应着一个GPIO*/ gpio_mode_t mode; /*!<模式:设置输入或者输出模式 */ gpio_pullup_t pull_up_en; /*!< GPIO上拉 */ gpio_pulldown_t pull_down_en; /*!< GPIO下拉 */ gpio_int_type_t intr_type; /*!< GPIO中断类型 */ } gpio_config_t;
每个参数我们再分析一下
类型 参数名 说明 uint32_t pin_bit_mask 32位的参数,参数的每一位对应着一个引脚,如果要使能哪一位,就把哪一位置为1,如果要使用若干位,可以让其同时为1 io_mode_t mode GPIO模式选择,gpio_mode_t 是一个枚举类型,其值有四个,分别代表着,不输入不输出;仅输入模式;仅输出模式;仅开漏输出; io_pullup_t pull_up_en GPIO_PULLUP_DISABLE(0x0)不使用上拉电阻,GPIO_PULLUP_ENABLE(0x1)使用上拉电阻 io_pulldown_t pull_down_en GPIO_PULLDOWN_DISABLE(0x0)关闭下拉电阻,GPIO_PULLDOWN_ENABLE(0x1)使能下拉电阻 io_int_type_t intr_type 一共有6中模式, 关闭中断(GPIO_INTR_DISABLE =0),上升沿触发(GPIO_INTR_POSEDGE =1),下降沿触发(GPIO_INTR_NEGEDGE =2),上升沿和下降沿触发(GPIO_INTR_ANYEDGE =3) ,输入低电平触发(GPIO_INTR_LOW_LEVEL =4),输入高电平触发(GPIO_INTR_HIGH_LEVEL =5) 关于gpio_int_type_t 的这个中断配置枚举类,我们再看一下其定义:
typedef enum { GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt 关闭中断*/ GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge 上升沿触发*/ GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge 下降沿触发*/ GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge 上升沿和下降沿触发 */ GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger 输入低电平触发 */ GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger 输入高电平触发*/ GPIO_INTR_MAX, } gpio_int_type_t;
-
设置中断类型函数
gpio_set_intr_type这个函数用来设置gpio中断类型的设置,参数有两个,一个是GPIO的编号枚举类gpio_num_t和中断类型枚举类gpio_int_type_t。
再来看一下函数定义:``` /** * @brief GPIO set interrupt trigger type 设置中断触发类型 * * @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO12, gpio_num should be GPIO_NUM_12 (12); * @param intr_type Interrupt type, select from gpio_int_type_t * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type); ```
同样的这个函数的返回值也有两个,要么设置成功,要么返回参数无效,不成功,便成仁。
-
GPIO电平设置
使用gpio_set_level()函数就可以对其进行高低电平的设置。这个函数一共有两个参数,一个参数是gpio的编号,另外一个是电屏的高低,其中0代表低电平,1代表高电平。
如果设置失败返回ESP_ERR_INVALID_ARG代表 GPIO number error ,成功返回ESP_OK/** * @brief GPIO的输出电平 * * @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param level Output level. 0: low ; 1: high * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG GPIO number error */ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
-
安装GPIO中断服务函数
gpio_isr_register()安装驱动程序的GPIO ISR处理程序服务,用这个函数会为说有GPIO中断注册单个全局ISP/** * @brief 安装驱动程序的GPIO ISR处理程序服务,该服务允许每个引脚的GPIO中断处理程序。 * *此函数与gpio_isr_register()不兼容 - 如果使用该函数,则会为所有GPIO中断注册单个全局ISR。 如果使用此功能,则ISR服务提供全局GPIO ISR,并通过gpio_isr_handler_add()函数注册各个引脚处理程序。 * * @param no_use为了与esp32兼容,该参数没有实际意义,可以用0填充。 * * @return * - ESP_OK成功 * - ESP_ERR_NO_MEM没有内存来安装此服务 * - ESP_ERR_INVALID_STATE 已安装ISR服务。 * - ESP_ERR_NOT_FOUND 未找到指定标志的空闲中断 * - ESP_ERR_INVALID_ARG GPIO错误 */ esp_err_t gpio_install_isr_service(int no_use);
6.为指定GPIO引脚添加/删除ISR
使用函数gpio_isr_handler_add()和gpio_isr_handler_remove()进行中断服务函数的创建与删除
/ **
* @brief为相应的GPIO引脚添加ISR处理程序。
*
*使用gpio_install_isr_service()后调用此函数
*安装驱动程序的GPIO ISR处理程序服务。
*
*将从ISR调用此ISR处理程序。所以有一个堆栈
*大小限制(可在menuconfig中配置为“ISR堆栈大小”)。这个
*与全局GPIO中断处理程序相比,限制较小
*到额外的间接水平。
*
* @param gpio_num GPIO号
* @param isr_handler相应GPIO号的ISR处理函数。
* @param args参数用于ISR处理程序。
*
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_STATE错误的状态,ISR服务尚未初始化。
* - ESP_ERR_INVALID_ARG参数错误
* /
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num,gpio_isr_t isr_handler,void * args);
/ **
* @brief删除相应GPIO引脚的ISR处理程序。
*
* @param gpio_num GPIO号码
*
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_STATE错误的状态,ISR服务尚未初始化。
* - ESP_ERR_INVALID_ARG参数错误
* /
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num);
二、点亮一颗小灯程序
点亮一个小灯是多么的困难的一件事呢?接下来让我们体验一下。
注:nodemcu的小灯在GPIO2
第一步宏定义一些参数:
#define GPIO_OUTPUT_IO_0 2`在这里插入代码片`
#define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0))
第二步定义初始化结构体:
gpio_config_t io_conf;
//关闭中断
io_conf.intr_type = GPIO_INTR_DISABLE;
//输出模式
io_conf.mode = GPIO_MODE_OUTPUT;
//GPIO2
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(GPIO_OUTPUT_IO_0, 0); //灯采用灌点流的方式进行连接的,所以当把引脚置为低电平的时候可以点亮小灯。
成功点亮小灯,恭喜你成功啦~
三、让灯闪起来
这个不得不提一下,RTOS(实时操作系统),ESP8266_RTOS的内核是FreeRTOS,是一种实时性操作系统,主要运行机制是任务的调度。具体的可以参考一下我的其他文章,有对RTOS进行细致的讲解。
话不多说直接上代码:
int cnt = 0;
while (1) {
cnt++;
vTaskDelay(1000 / portTICK_RATE_MS); //延时1s
gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2); //设置电平
}
四、总结
从配置好环境,到真正意义上的看懂(today),差不过花了20天的时间,最主要的是不能静下心来去看文档,分析代码,畏难心里吧,始终要记得迎难而上~