04_ESP8266 NONOS_SDK GPIO
相关资料准备:
(1)GPIO相关API请查看2c-esp8266_non_os_sdk_api_reference_cn手册
(2)GPIO相关寄存器请查看 esp8266-technical_reference_cn 手册
(3)ESP8266 的 16 个通⽤ IO 的管脚位置和名称如下表所示:
图1.1-GPIO管脚定义
其中,在四线( QUAD)模式 Flash 下,有 6 个 IO 口用于 Flash 通讯。
在两线( DUAL)模式 Flash
下,有 4
个 IO
口用于与 Flash 通讯。
说明:
本说明如果对照以下资料阅读,会更有助理解:
• “附录 1 - GPIO 寄存器”
• 引脚功能复⽤表:《 ESP8266_Pin_List.xlsx》
https://www.espressif.com/sites/default/files/documentation/ESP8266_Pin_List.xls
一、GPIO口输出
目标:将GPIO2和GPIO4设置成IO口,将管脚设为输出模式,并输出对应电平,加入delay延时,使LED按照一定频率闪烁。步骤如下:
1、首先将添加两个头文件:
"eagle_soc.h"和 "gpio.h"
2、管脚功能选择:
将GPIO2定义为IO口,PIN_FUNC_SELECT( PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);
PIN_FUNC_SELECT(PIN_NAME, FUNC)为宏定义,宏定义原型为:
/*===================================================================
* 功能:管脚功能选择
* 宏: PIN_FUNC_SELECT(PIN_NAME,FUNC)
* 参数:【PIN_NAME】 管脚名 "PERIPHS_IO_MUX_"+ Pin name 管脚名
* 【FUNC】 管脚功能 功能序号-1
===================================================================*/
第一个参数PIN_NAME,可在"eagle_soc.h" 文件中查阅具体怎么填写实参。比如GPIO2设置为IO,PERIPHS_IO_MUX_GPIO2_U,文件中如下:
第二个参数FUNC,管脚功能,它的取值为:功能序号-1(Functionx,其中x就是功能序号),
查看如下表格,GPIO2功能设置为IO功能, GPIO2对应为Function1,则FUNC处填写的就是1-1=0
ESP8266_Pin_List.xls 表格
可我们填写的是FUNC_GPIO2,为什么呢?查看eagle_soc.h,发现已经有定义好的宏定义:
所以,填写0或者FUNC_GPIO2,只要根据ESP8266_Pin_List.xls 表格对应功能序号减1规则来即可:
3、将管脚设为输出模式,并输出对应电平:
//此处我们设置GPIO2为输出,输出高电平。
GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1);
宏定义原型为:
/*===================================================================
* 功能:将管脚设为输出模式,并输出对应电平
* 宏: GPIO_OUTPUT_SET ( gpio_no , bit_value )
* 参数:【gpio_no】 管脚名 GPIO_ID_PIN ( IO端口序列号 )
* 【bit_value】 输出电平
====================================================================*/
第一个参数gpio_no管脚名,填写格式为GPIO_ID_PIN(IO端口序列号 ),看第一个参数宏定义:
很明显已经帮我们定义好了,我们只需要在n这里填写端口序列号即可将GPIO设置为输出模式。
第二个参数bit_value为输出电平,1为高电平,0为低电平,此处我们填写1(由于我的GPIO2的LED灯是共阳的)
4、写毫秒级延时函数
void ICACHE_FLASH_ATTR delay_ms(u32 ms_time) { for(;ms_time>0; ms_time--) { os_delay_us(1000); } }
5、定义LED每500ms闪烁一次,并串口输出LED状态
结果:
串口打印正常,每隔500ms输出一次一次。
观察灯光情况:每隔500ms闪烁一次。
扩展:
//gpio_output_set(0,0,0,BIT4); //设置 GPIO12 为输入
/*===================================================================
* 功能:将管脚设为输出/输入模式,可以设置输出的位的高低电平,但是不可以设置输入的高低电平
* 函数: void gpio_output_set(
uint32 set_mask,
uint32 clear_mask,
uint32 enable_mask,
uint32 disable_mask
)
* 参数:
【set_mask】 设置输出为高的位 (假设GPIO2,则填BIT2,即GPIO2输出高电平;如果填写0,则不改变状态)
【clear_mask】 设置输出为低的位 (假设GPIO2,则填BIT2,即GPIO2输出低电平;如果填写0,则不改变状态)
【enable_mask】设置使能输出的位 (假设GPIO2,则填BIT2,即使能GPIO2输出)
【disable_mask】设置使能输入的位 (假设GPIO2,则填BIT2,即使能GPIO2输入)
* 示例:
gpio_output_set(BIT12,0,BIT12,0): 设置 GPIO12 输出高电平;
gpio_output_set(0,BIT12,BIT12,0): 设置 GPIO12 输出低电平;
gpio_output_set(BIT12,BIT13,BIT12|BIT13,0): 设置 GPIO12 输出高电平, GPIO13 输出低电平;
gpio_output_set(0,0,0,BIT12): 设置 GPIO12 为输入
* =================================================================*/
二、GPIO输入
目标:GPIO4作为按键IO ,GPIO5作为LED灯的IO,按键按下,灯亮,按键松开,灯灭。
1、管脚功能选择
//将LED对应的GPIO5设置为IO
PIN_FUNC_SELECT( PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);
//按键对应的GPIO4设置为IO口
PIN_FUNC_SELECT( PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);
//禁止GPIO4输出
GPIO_DIS_OUTPUT(4);
2、LED灯初始化
//将GPIO5设置为输出,电平为高电平
GPIO_OUTPUT_SET(GPIO_ID_PIN(5),1);
注意:如果某个GPIO已经内部上拉了,而你又外接上拉,此时可以
PIN_PULLUP_DIS(4); //关闭GPIO内部上拉
3、主函数下实现逻辑功能
while(1){ system_soft_wdt_feed(); //喂狗,防止复位 Get_Btn_Value = GPIO_INPUT_GET(GPIO_ID_PIN(4)); //获取到的按键电平值 if(Get_Btn_Value==0){ //若为低电平 GPIO_OUTPUT_SET(GPIO_ID_PIN(5),0); //点亮GPIO5对应的LED灯 } else{ GPIO_OUTPUT_SET(GPIO_ID_PIN(5),1); //熄灭 } }
三、GPIO中断
GPIO输入寄存器(可读可写)
寄存器名称 |
功能说明 |
寄存器大小 |
参数说明 |
GPIO_IN |
输入状态寄存器 |
16 Bit |
对应GPIO0-GPIO15 |
GPIO_PIN12 |
中断类型寄存器 |
16 Bit |
0:禁用该GPIO的中断 1:上升沿触发中断 2:下降沿触发中断 3:双边沿触发中断 4:低电平触发中断 5:高电平触发中断 |
GPIO_STATUS |
中断状态寄存器 |
16Bit |
位:BIT0 - BIT15 ( 对应GPIO0-GPIO15 ) BIT0 - BIT15对应位置1,表示该中断发生。 |
GPIO_STATUS_W1TC |
复位中断标志寄存器 |
16Bit |
位:BIT0 - BIT15 ( 对应GPIO0-GPIO15 ) 向BIT0 - BIT15对应位写1,对应GPIO的中断状态会被清除。 |
注:GPIO16不支持触发IO中断。因为如下:
GPIO中断相关宏:
ETS_GPIO_INTR_ENABLE() //开 GPIO 中断
ETS_GPIO_INTR_DISABLE() //关 GPIO 中断
ETS_GPIO_INTR_ATTACH(func, arg) //注册 GPIO 中断处理函数
GPIO中断相关函数:gpio_pin_intr_state_set
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_STATUS_ADDRESS: 中断状态寄存器地址
//GPIO_STATUS_W1TC_ADDRESS: 清中断寄存器地址
目标:GPIO4通过10K电阻上拉,作为按键触发中断;GPIO5作为LED指示灯。实现按键按下,GPIO5指示灯亮,串口输出相关信息。
(随便画一下记录一下)
1、管脚选择
//按键对应的GPIO4设置为IO口
PIN_FUNC_SELECT( PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);
//禁止GPIO4输出
GPIO_DIS_OUTPUT(4);
2、GPIO中断设置
ETS_GPIO_INTR_DISABLE(); //关闭GPIO中断
ETS_GPIO_INTR_ATTACH((ets_isr_t) gpio_intereupt ,NULL); // 注册中断回调函数
gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_NEGEDGE); // GPIO4下降沿触发中断
ETS_GPIO_INTR_ENABLE(); // 使能GPIO中断功能
3、写中断函数
//中断函数前面不能有ICACHE_FLASH_ATTR宏
void gpio_intereupt (void){
//1.清除该中断
u32 GPIO_STA=0; // 全部GPIO的中断状态
u32 GPIO4_STA; // GPIO_4的中断状态
GPIO_STA = GPIO_REG_READ(GPIO_STATUS_ADDRESS); //读取GPIO中断状态
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, GPIO4_STA); // 清除中断状态位(如果不清除状态位,会一直进入中断)
//2.判断是否是GPIO4口下降沿触发的中断
os_printf("最初获取的GPIO状态:%x\n",GPIO4_STA);
os_printf("\r\n-----------------------------------------------\r\n");
GPIO4_STA = GPIO_STA &(BIT(4));//读取GPIO4中断状态
//GPIO4_STA = GPIO_STA &(0x01<<4);
//读取GPIO4中断状态(这句和上面那个是一样的效果,原因如下图所示:)
os_printf("进入中断,GPIO状态:%x\n",GPIO4_STA);
os_printf("\r\n-----------------------------------------------\r\n");
//判断中断管脚是否是GPIO4,只有GPIO4触发中断,该值才不为0,即真,实际值为0x10
if(GPIO_STA){ os_printf("是下降沿触发中断!");
os_printf("\r\n-----------------------------------------------\r\n");
LED_Flag=!LED_Flag; // LED_Flag需要定义为全局变量
GPIO_OUTPUT_SET(GPIO_ID_PIN(5),LED_Flag);
//ETS_GPIO_INTR_DISABLE(); //关闭GPIO中断
}
4、效果:
(寒假,硬件上我现手头没按键,用杜邦线轻触GND代替按键按下)