【ESP8266 笔记】ESP8266 RTOS SDK 3.0 按键长按短按功能实现

一、环境

硬件: NodeMcu DEVKIT
SDK: ESP8266 RTOS SDK 3.0

二、硬件原理

在这里插入图片描述

三、软件功能

通过按键S2长按的时间长度不同来实现调用软件上的功能。
1、当按键S2按下时间大于40ms,执行程序1
2、当按键S2按下时间大于2000ms,执行程序2
3、当按键S2按下时间大于6000ms,执行程序3

四、代码实现


/*********************************************************************
* INCLUDES
*/
#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"
	
#include "esp_log.h"
#include "esp_system.h"

#include "zlog.h"
#include "key.h"
/*********************************************************************
* MACROS
*/

/*********************************************************************
* CONSTANTS
*/
//定义事件类型
#define KEY_GPIO_LL_PRESS_EVT		0x01	//超长按事件
#define KEY_GPIO_L_PRESS_EVT		0x02	//长按事件
#define KEY_GPIO_S_PRESS_EVT		0x03	//短按事件

#define GPIO_INPUT_IO_0     GPIO_NUM_0
#define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_IO_0)


/*********************************************************************
* TYPEDEFS
*/

typedef void (*post_delay_call_t)(void *arg);
typedef void (*key_click_cb_t)(uint8_t event);

/*********************************************************************
* GLOBAL VARIABLES
*/

       
/*********************************************************************
* LOCAL VARIABLES
*/
static uint64_t  elink_time = 0;
static key_click_cb_t pfnKeyClickCallback = NULL;
static xQueueHandle key_evt_queue = NULL;


/*********************************************************************
* LOCAL FUNCTIONS
*/
//软件定时器实现定时调用指定函数
static void post_delayed_action(int ms, post_delay_call_t action, void *parg)
{
	static os_timer_t os_timer;
	os_timer_disarm(&os_timer);
	os_timer_setfn(&os_timer, action, parg);
	os_timer_arm(&os_timer, ms,0);
}

static void key_poll_func(void *arg)
{
	uint64_t diff;
	uint8_t events = 0;
	//获取引脚状态
	uint32_t level = gpio_get_level(GPIO_INPUT_IO_0);
	
	 //按键未松开
	if (level == 0) {
		post_delayed_action(10, key_poll_func, NULL);
	}
	//按键已经松开 
	else {
		//获取按下到松开的间隔时间
		diff = get_now_ms() - elink_time;
		if (diff > 6000) { /*long long press */
			elink_time = 0;
			events = KEY_GPIO_LL_PRESS_EVT;
		} else if (diff > 2000) { /* long press */
			elink_time = 0;
			events = KEY_GPIO_L_PRESS_EVT;
		} else if (diff > 40) { /* short press */
			elink_time = 0;
			events = KEY_GPIO_S_PRESS_EVT;
		} else {
			post_delayed_action(10, key_poll_func, NULL);
		}
	}
	//发送消息给task
	if(events)
	{
		xQueueSendFromISR(key_evt_queue, &events, NULL);
		events = 0;
	}
}

static void handle_elink_key()
{
    uint32_t level = gpio_get_level(GPIO_INPUT_IO_0);
    if ((level == 0) && (elink_time == 0)) {
        elink_time = get_now_ms();
        key_poll_func(NULL);
    }
}

//中断处理
static void gpio_isr_handler(void *arg)
{
	uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
	
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);

    if (gpio_status & GPIO_INPUT_PIN_SEL)
	{
        handle_elink_key();
	}
}


static void key_task_handler(void *arg)
{
    uint8_t event;
	zlog_debug("gpio_task_example");
    for (;;) {
        if (xQueueReceive(key_evt_queue, &event, portMAX_DELAY)) {
            ESP_LOGI("KEY", "%d\n", event);
            		//接收到消息,调用回调函数,在回调函数中对不同的按键类型进行处理
			if(pfnKeyClickCallback != NULL)
				pfnKeyClickCallback(event);	
        }
    }
}

/*********************************************************************
* GLOBAL FUNCTIONS
*/

/*********************************************************************
* @fn          funtion_name
*
* @brief       Add device to descovery list.
*
* @param       pSimpleDescRsp - SimpleDescRsp containing epInfo of new EP.
*
* @return      index of device or 0xFF if no room in list
*/
void key_gpio_init(key_click_cb_t cb)
{
	gpio_config_t io_conf;

	pfnKeyClickCallback = cb;
	
	memset(&io_conf,0,sizeof(gpio_config_t));

	//interrupt of falling edge
	io_conf.intr_type = GPIO_INTR_NEGEDGE;
	//bit mask of the pins
	io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
	//set as input mode
	io_conf.mode = GPIO_MODE_INPUT;
	//enable pull-up mode
	io_conf.pull_up_en = 1;
	gpio_config(&io_conf);

	key_evt_queue = xQueueCreate(10, sizeof(uint32_t));
	xTaskCreate(key_task_handle, "key_task_handle", 1024, NULL, 10, NULL);
	
	//install gpio isr service
    gpio_install_isr_service(0);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *) GPIO_INPUT_IO_0);
	
}

NOTE: 在调试的过程中,在这些函数中添加打印信息都会造成程序崩溃,只有在key_task_handler任务中打印调试信息程序不会崩溃。问题待查,怀疑是栈的问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章