按键驱动--链表方式

1.按键.h文件

#include <stdint.h>
#include <string.h>


#define BTN_NAME_MAX 		10

/* 按键循环20ms */
#define BTN_DEBOUNCE_TIME 	1 		// 消抖周期
#define BTN_DOUBLE_TIME 	15   	// 双击间隔周期
#define BTN_LONG_TIME 		50     	// 长按检测周期

typedef void (*BTN_CALLBACK)(void *);

//初始化按键电平
typedef enum
{
    BTN_LEVEL_LOW = 0,				// 低电平
    BTN_LEVEL_HIGH,					// 高电平
} BTN_LEVEL;

//按键状态
typedef enum
{
    BTN_DOWM = 0, 					// 按下
    BTN_UP,       					// 松开
    BTN_NONE,						// 无事件
} BTN_STATE;

//按键事件
typedef enum
{
    BTN_EV_CLICK_RISE = 0,    		// 单击弹起
	BTN_EV_CLICK_DROP,				// 单机按下
    BTN_EV_DOUBLE_CLICK, 			// 双击弹起
    BTN_EV_LONG_CLICK_RISE,   		// 长按弹起
	BTN_EV_LONG_CLICK_DROP,			// 长按按下
    BTN_EV_CNT,          			// 辅助用于统计事件个数
    BTN_EV_NULL,         			// 无事件发生
} BTN_EVENT;


typedef struct __BTN_HandleTypedef
{
    uint8_t (*read_btn_level)(void);  	/* 读取按键电平函数 */
    char name[BTN_NAME_MAX];          	/* 按键名称 */
    uint8_t button_state : 2;         	/* 按键状态 */
    uint8_t button_last_state : 2;    	/* 上一次的按键状态,判断双击 */
    uint8_t button_trigger_level : 2; 	/* 按键触发电平 */
    uint8_t button_last_level : 2;    	/* 上一次按键电平 */

    BTN_EVENT event;                  	/* 按键触发事件,单击,双击,长按 */
	BTN_EVENT last_event;
    BTN_CALLBACK callback[BTN_EV_CNT];	/* 按键函数指针 */

    uint8_t button_trigger_cnt; 		/* 双击检测周期内按键触发次数 */
    uint16_t timer_count;       		/* 计数值 */
    uint16_t debounce_count;    		/* 消抖计数值 */
    struct __BTN_HandleTypedef *next;	/* 链表指针 */

} BTN_HandleTypedef;

2.按键.c文件

static struct __BTN_HandleTypedef *button_head = NULL;
/*********************************************************************
 * @fn      Driver_Button_List_Process
 *
 * @brief   按键链表进程.
 *
 * @param   none
 *
 * @return  none
 */
void Driver_Button_List_Process(void)
{
    struct __BTN_HandleTypedef *pass_btn;
	
    for(pass_btn = button_head; pass_btn != NULL; pass_btn = pass_btn->next)
    {
        Driver_Button_List_Cycle_Process(pass_btn);
    }
}


/*********************************************************************
 * @fn      Driver_Button_List_Delete
 *
 * @brief   按键初链表删除.
 *
 * @param 	btn:按键句柄
 *
 * @return  none
 */
void Driver_Button_List_Delete(BTN_HandleTypedef *btn)
{
    struct __BTN_HandleTypedef **curr;
    struct __BTN_HandleTypedef *entry;
    
    if(btn == NULL)
        return;

    curr = &button_head;
    while(*curr != NULL)
    {
        entry = *curr;
        if (entry == btn)
            *curr = entry->next;
        else
            curr = &entry->next;
    }
}


/*********************************************************************
 * @fn      Driver_Button_List_Add
 *
 * @brief   按键链表添加.
 *
 * @param   none
 *
 * @return  none
 */
static void Driver_Button_List_Add(BTN_HandleTypedef *btn)
{
    btn->next = button_head;
    button_head = btn;
}


/*********************************************************************
 * @fn      Driver_Button_List_Create
 *
 * @brief   按键初链表创建.
 *
 * @param   name:按键名称
 *
 * @param 	btn:按键句柄
 *
 * @param 	read_btn_level:读取按键电平
 *
 * @param 	btn_trigger_level:电平初始化状态
 *
 * @return  none
 */
static void Driver_Button_List_Create(const char *name, BTN_HandleTypedef *btn, uint8_t (*read_btn_level)(void), uint8_t btn_trigger_level)
{
    if(btn == NULL)
    {
        return;
    }

    memset(btn, 0, sizeof(struct __BTN_HandleTypedef));
    strncpy(btn->name, name, BTN_NAME_MAX);

    btn->button_state = BTN_NONE;                  
    btn->button_last_state = BTN_NONE;             
    btn->event = BTN_EV_NULL;
	btn->last_event = BTN_EV_NULL;
    btn->read_btn_level = read_btn_level;           
    btn->button_trigger_level = btn_trigger_level;     
    btn->button_last_level = btn->read_btn_level(); 
    btn->debounce_count = 0;
    btn->timer_count = 0;
    btn->button_trigger_cnt = 0;

    Driver_Button_List_Add(btn);
}


/*********************************************************************
 * @fn      Driver_Button_List_Create_Callback
 *
 * @brief   按键链表创建事件回调函数.
 *
 * @param   btn:按键句柄
 *
 * @param	btn_event:按键事件名称
 *
 * @param	btn_callback:按键回调函数
 *
 * @return  none
 */
static void Driver_Button_List_Create_Callback(BTN_HandleTypedef *btn, BTN_EVENT btn_event, BTN_CALLBACK btn_callback)
{
	if(btn == NULL)
	{
		return;
	}
	
	btn->callback[btn_event] = btn_callback;
}


/*********************************************************************
 * @fn      Driver_Button_List_Process
 *
 * @brief   按键链表进程.
 *
 * @param   btn:按键句柄
 *
 * @return  none
 */
static void Driver_Button_List_Cycle_Process(BTN_HandleTypedef *btn)
{
    uint8_t current_level = (uint8_t)btn->read_btn_level();

    if((current_level != btn->button_last_level) && (++btn->debounce_count >= BTN_DEBOUNCE_TIME))
    {
        btn->button_last_level = current_level;
        btn->debounce_count = 0;

        if(btn->button_trigger_level == current_level)
        {
            btn->button_state = BTN_DOWM;
			btn->event = BTN_EV_CLICK_DROP;
            btn->timer_count = 0;
        }
        else
        {
            btn->button_state = BTN_UP;
        }
    }

    btn->timer_count++;
    switch(btn->button_state)
    {
		case BTN_DOWM:
			if(btn->timer_count > BTN_LONG_TIME && btn->button_last_level == current_level)
			{
				if(btn->timer_count % 4 == 0)
				{
					btn->event = BTN_EV_LONG_CLICK_DROP;
					btn->last_event = BTN_EV_LONG_CLICK_DROP;
					btn->button_state = BTN_NONE;
					goto button_even;
				}
			}
			if(btn->event == BTN_EV_CLICK_DROP)
			{
				goto button_even;
			}
			break;

		case BTN_UP:
			if(btn->last_event == BTN_EV_LONG_CLICK_DROP)
			{
				btn->last_event = BTN_EV_NULL;
				btn->event = BTN_EV_LONG_CLICK_RISE;
				goto button_even;
			}

			if(btn->timer_count < BTN_DOUBLE_TIME)
			{
				if(btn->button_last_state == BTN_DOWM)
				{
					btn->button_trigger_cnt++;
					btn->timer_count = 0;
				}
			}

			if(btn->timer_count > BTN_DOUBLE_TIME)
			{
				btn->timer_count = 0;

				if (btn->button_trigger_cnt == 1)
				{
					btn->event = BTN_EV_CLICK_RISE;
				}
				else if (btn->button_trigger_cnt > 1)
				{
					btn->event = BTN_EV_DOUBLE_CLICK;
				}
				btn->button_trigger_cnt = 0;
				btn->timer_count = 0;
			}
			break;
		
		case BTN_NONE:
			break;
			
		default:
			break;
	}
	
	button_even:
	btn->button_last_state = btn->button_state;
	if(btn->event < BTN_EV_CNT && btn->callback[btn->event] != NULL)
	{
		btn->callback[btn->event](btn);
		btn->event = BTN_EV_NULL;
	}
}

3.例程

重写读按键口函数

static uint8_t read_ok_key(void)
{
	return HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_7);
}

 创建按键事件回调函数(每个事件可以单独创建回调函数,这里省事就公用一个了)

static void key_ok_callback(void *btn)
{
	BTN_HandleTypedef *button = (BTN_HandleTypedef *)btn;
	
	switch(button->event)
	{
		case BTN_EV_CLICK_RISE:
			if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
			{
				//Debug("click rise");
			}
			break;
				
		case BTN_EV_CLICK_DROP:
			if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
			{
				//Debug("click drop");
			}
			break;
				
		case BTN_EV_DOUBLE_CLICK:
			if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
			{
				//Debug("click double");
			}
			break;
		
		case BTN_EV_LONG_CLICK_RISE:
			if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
			{
				//Debug("click long rise");
			}
			break;
		
		case BTN_EV_LONG_CLICK_DROP:
			if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
			{
				//Debug("click long drop");
			}
			break;
		
		default:
			//Debug("click error");
			break;
	}
}

初始化按键

void Driver_Button_List_Init(void)
{
	static BTN_HandleTypedef OK_key;
	
	Driver_Button_List_Create("ok_key", &OK_key, read_ok_key, BTN_LEVEL_HIGH);
	Driver_Button_List_Create_Callback(&OK_key, BTN_EV_CLICK_RISE, key_ok_callback);
	Driver_Button_List_Create_Callback(&OK_key, BTN_EV_CLICK_DROP, key_ok_callback);
	Driver_Button_List_Create_Callback(&OK_key, BTN_EV_DOUBLE_CLICK, key_ok_callback);
	Driver_Button_List_Create_Callback(&OK_key, BTN_EV_LONG_CLICK_RISE, key_ok_callback);
	Driver_Button_List_Create_Callback(&OK_key, BTN_EV_LONG_CLICK_DROP, key_ok_callback);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值