ESP8266 GPIO接口(按键中断,软件定时LED)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Mirchell1/article/details/86495762

GPIO接口

SDK使用ESP8266_NONOS_SDK V3.0
此文记录在使用GPIO口时,功能复用以及IO中断的问题。

GPIO复用

接口 位于 /ESP8266_NONOS_SDK/include/eagle_soc.h和gpio.h。
管脚功能选择宏定义:PIN_FUNC_SELECT(PIN_NAME,FUNC);对于不同的引脚,PIN_NAME不同,IO口复用的功能FUNC也不同。由于我在配置GPIO14时,不小心错写成FUNC_GPIO4,IO口电平死活不会反转。。。

以8266的MTMS为例,说明GPIO功能的选择。
功能选择寄存器PERIPHS_IO_MUX_MTMS_U(不同的GPIO,该寄存器不同)
配置的时候,请参考引脚配置表,如下图
在这里插入图片描述
需要注意的是,如果需要配置为FUNCTION3,应该往寄存器对应的位中写2,如果需要配置为FUNCTION2,应该往寄存器对应的位中写1,以此类推。

    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14);//led
    GPIO_OUTPUT_SET(GPIO_ID_PIN(14), 1);

在这里插入图片描述

GPIO中断

GPIO中断相关宏:
ETS_GPIO_INTR_ENABLE() //开 GPIO 中断
ETS_GPIO_INTR_DISABLE() //关 GPIO 中断
ETS_GPIO_INTR_ATTACH(func, arg) //注册 GPIO 中断处理函数

GPIO中断相关函数:gpio_pin_intr_state_set
在这里插入图片描述
0是失能; 1是上升沿触发; 2是下降沿; 3是边沿;4是低电平;5是高电平

中断加延时

参考:https://www.jianshu.com/p/ec424a87ded0
简单说下这种处理方式,在user_init()函数中加入按键初始化,注册中断处理函数以及设置为下降沿触发方式。然后在中断处理函数里面判断IO口状态,再delay延时后再去判断IO口状态,来最终判断是否按键按下。实际使用发现去抖效果并不好,会多次触发。而且个人也不喜欢这个延时方式。
于是在网上搜索发现sdk里面自带了按键的API,下面主要介绍这个以及遇到的问题。

中断加软件定时器

参考:https://blog.csdn.net/qq_15647227/article/details/52218376
相关API不再介绍,参考链接即可,里面说的很详细了。使用时只需要将key.c和key.h放入你工程目录app下面的相应位置即可。key.c里面改为#include “key.h”。
说下不一样的,我是一个按键既有短按功能,也有长按功能。按照sdk的流程是有点问题的,长按后松手也会触发短按程序。
先贴初始化代码:

void usr_key_init(void)//按键初始化
{
	switch_signle = key_init_single(GPIO_KEY_ID,
									GPIO_KEY_NAME,
									GPIO_KEY_FUNC,
									&usr_longkey_process,
									&usr_shortkey_process);
	switch_param.key_num = 1;
	switch_param.single_key = &switch_signle;
	key_init(&switch_param);
}

按键处理函数:

static void usr_shortkey_process()
{
    os_timer_disarm(&led_time);//定时器设置
    os_timer_setfn(&led_time, (os_timer_func_t *)led_callback, NULL);
    os_timer_arm(&led_time, 500, 1);//0.5s
    os_printf("shortkey press!!!\r\n");
}

static void usr_longkey_process()
{
    os_timer_disarm(&led_time);//定时器设置
    os_timer_setfn(&led_time, (os_timer_func_t *)led_callback, NULL);
    os_timer_arm(&led_time, 2000, 1);//2s
    os_printf("longkey press!!!\r\n");
}

针对长按触发后松手会触发短按的现象,我对key.c相关函数做了修改。
首先我在5s定时器回调函数中置位key_level=2;

LOCAL void ICACHE_FLASH_ATTR
key_5s_cb(struct single_key_param *single_key)
{
    os_timer_disarm(&single_key->key_5s);

    // low, then restart
    if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
    	single_key->key_level = 2;
        if (single_key->long_press) {
            single_key->long_press();
        }
    }
}

在key_intr_handler()函数中加入长按松手后检测判断。

else if (keys->single_key[i]->key_level == 2){
            	keys->single_key[i]->key_level = 1;
            	gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE);
            }

这样就实现了一个按键的短按和长按功能。

软件定时器

相对来说,软定时器没遇到什么问题。大家可以参考:https://blog.csdn.net/xh870189248/article/details/78155357
只要注意在初始化前先关闭该定时器,同一个定时器不能同时使用。还有就是设置好回调函数。我的回调函数如下:

void ICACHE_FLASH_ATTR
led_callback(void) // test
{
//	os_printf("What!\r\n");
	if (led_status == true)
	{
		GPIO_OUTPUT_SET(GPIO_ID_PIN(14), 0);
		led_status = false;
	}
	else
	{
		GPIO_OUTPUT_SET(GPIO_ID_PIN(14), 1);
		led_status = true;
	}
}

以上便是我使用gpio遇到的问题了,欢迎不妥之处给予指正。

展开阅读全文

没有更多推荐了,返回首页