【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任務中打印調試信息程序不會崩潰。問題待查,懷疑是棧的問題。

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