Key driven based on event driven (support single double click long press)

Keywords: Spring

As the simplest way of human-computer interaction, keys can be driven simply by reading the level of keys in polling or interruption and adding a delay to eliminate chattering. However, if key resources are limited and multiple functions need to be realized at the same time, we need to optimize the key drivers. With reference to some codes on the Internet, we have recently written a key based on event driven Drive (support single double click and long press).

I have added comments in the code, which is easy to understand. At the same time, it is not completely written by independent c. It can be easily ported to various platforms without any platform. Here I take stm32 as an example to illustrate the calling procedure.

example

button_t button1;   //Define key 1
uint8_t  GET_BUTTON1_LEVEL(void);   //Get level function of key 1 (self realization)

/*******Define yourself***********/
void button1_pressdown(void * par);  //Press key 1 to press the callback function
void button1_longpress(void * par);  //Press key 1 to press and hold the callback function
void button1_doublepress(void * par);  //Key 1 long double click callback function

void main()
{
	button_init(&button1,0,GET_BUTTON1_LEVEL);   //Initialize key 1
	button_start(&button1);   //Turn on key task
	register_callback(&button1,singleclick,button1_pressdown);   //Register click callback function
	register_callback(&button1,longclick,button1_longpress);    //Register long press callback function
	register_callback(&button1,doubleclick,button1_doublepress);   //Register double click callback function

}


uint8_t  GET_BUTTON1_LEVEL()   //Get button 1 level function
{
	return HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3);
}

//Safety key 1 press callback function
void button1_pressdown(void * par)
{
	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
}
//Long press callback function of safety key 1
void button1_longpress(void * par)
{
	//HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_7);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);
}
//Safety key 1 double click callback function
void button1_doublepress(void * par)
{
	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_7);
	//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);
}




/***************Timer cycle callback function**************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	
  /* Prevent unused argument(s) compilation warning */
  if(htim==&htim1)
  {
     button_process();   //Just add this function to timer interrupt
		
  }


}

Key driven c file

#include "button.h"

//Head of key list
button_t *head_handle=NULL;

/**
  * @brief  Key initialization function
  * @param  button: Key handle
  * @param  trigerlevel: Trigger level
  * @param  get_button_Level: Obtain the current level function pointer
  * @retval None
  */
void button_init(button_t* button,uint8_t trigerlevel,uint8_t  (*get_button_Level)())
{
	memset(button,0,sizeof(button_t));
	button->event=nopress;
	button->trigerlevel=trigerlevel;
	button->get_button_Level=get_button_Level;
	button->nowlevel=button->get_button_Level();	
}

/**
  * @brief  Register key callback function
  * @param  button: Key handle
  * @param  click_type_t: Click type
  * @param  cb: Callback function
  * @retval None
  */
void register_callback(button_t* button,click_type_t type,callback cb){
	
	button->cb[type]=cb;
}

/**
  * @brief  Gets the event type of the current key
  * @param  button: Key handle
  * @retval Event type
  */
click_type_t  get_button_event(button_t* button)
{
	return button->event;	
}

/**
  * @brief  Key handling function
  * @param  button: Key handle
  * @retval none
  */
void button_handle(button_t* button)
{
	if(button->get_button_Level()!=button->nowlevel)
	{
		if(++button->debuncetick>=DEBUNCETICK)    //Greater than buffeting times
		{
			button->nowlevel=button->get_button_Level();   //Update current level
			button->debuncetick=0;
			
		}	
	}else{
		
		button->debuncetick=0;
	}
	
	
	switch(button->state){
		
	case 0:     //Initial state
		if(button->nowlevel==button->trigerlevel)    //Press down
		{
			button->event=pressdown;
			button->state=1;
			if(button->cb[pressdown])   //If the press callback function is registered
			{
				button->cb[pressdown]((button_t*) button);
				
			}
			
		}
		break;
		
	
	case 1:    //Status after pressing
		if(button->nowlevel!=button->trigerlevel)  //Bounce up
		{
			button->event=pressup;
			button->state=2;
			button->longtick=0;
			if(button->cb[pressup])   //If the bounce callback function is registered
			{
				button->cb[pressup]((button_t*) button);
				
			}
		}else{
			
			if(++button->longtick>=LONGCLICK)     //Greater than long press count
			{
				button->event=longclick;
				button->state=3;
				button->longtick=0;
				if(button->cb[longclick])   //If the long press callback function is registered
				{
					button->cb[longclick]((button_t*) button);
				
				}
				
			}
		}
		break;
		
		
	case 2:    //Press and pop up
		if(button->nowlevel==button->trigerlevel)   //Second press
		{
			 
			button->doubletick=0;
			if(button->cb[pressdown])   //If the press callback function is registered
			{
				button->cb[pressdown]((button_t*) button);
				
			}
			
			if(button->cb[doubleclick])   //If the double click callback function is registered
			{
				button->event=doubleclick;
				button->state=3;
				button->cb[doubleclick]((button_t*) button);	
			}else{
				button->state=1; 
				button->event=pressdown;
				if(button->cb[singleclick])   //If the click callback function is registered
				{
					button->cb[singleclick]((button_t*) button);
				
				}
			}
			
		}else{
			
			if(++button->doubletick>=DOUBLETICK)
			{
				button->doubletick=0;
				button->state=0;
				if(button->cb[singleclick])   //If the click callback function is registered
				{
					button->cb[singleclick]((button_t*) button);
				
				}
			}
			
		}
		break;
		 
	case 3:    //Waiting to spring up
		if(button->nowlevel!=button->trigerlevel)  //Bounce up
		{
			
			if(button->cb[pressup])   //If the bounce callback function is registered
			{
				button->cb[pressup]((button_t*)  button);
				
			}
			
			button->state=0;
		}
		
		break;
	}
}


/**
  * @brief  Add the key to the list function
  * @param  button: Key handle
  * @retval 0:Success. - 1: already exists
  */
int button_start(button_t* button)
{
	button_t* target = head_handle;
	while(target) {
		if(target == button) return -1;	//already exist.
		target = target->next;
	}
	button->next = head_handle;
	head_handle = button;
	return 0;
}


/**
  * @brief  Remove the key from the list
  * @param  button: Key handle
  * @retval None
  */
void button_stop(button_t* button)
{
	button_t** curr;
	for(curr = &head_handle; *curr; ) {
		button_t* entry = *curr;
		if (entry == button) {
			*curr = entry->next;
//			free(entry);
		} else
			curr = &entry->next;
	}
}


/**
  * @brief  Key polling function
  * @param  None.
  * @retval None
  */
void button_process()
{
	button_t* target;
	for(target=head_handle; target; target=target->next) {
		button_handle(target);
	}
}

Key driver header file

#ifndef _BUTTON_H_
#define _BUTTON_H_

#include "stdint.h"
#include "string.h"



#define DEBUNCETICK  1       //Number of buffeting times
#define LONGCLICK    50      //Long press times
#define DOUBLETICK   30      //Double click times


typedef void (*callback)(void*); 


typedef enum  _click_type_t{
	
	pressdown=0,     //Press down
	pressup,       //Bounce up
	singleclick,    //Single click
	longclick,     //Long press
	doubleclick,    //double-click
	num_of_type,    //Type number	
	nopress         //No key pressed
}click_type_t;    //Key type

typedef struct _button_t button_t;
struct _button_t{
	uint8_t debuncetick;    //Dithering count
	uint8_t doubletick;    //Double click count
	uint8_t longtick;      //Long press count
	uint8_t state;         //state
	uint8_t event;         //Keystroke event
	uint8_t trigerlevel;   //Trigger level
	uint8_t nowlevel;     //Current level
    uint8_t  (*get_button_Level)(void);    //Get current level function pointer
	callback cb[num_of_type];               //Callback function array pointer
	button_t*next;                        //Next button
};    //Key

#ifdef __cplusplus  
extern "C" {  
#endif  

void button_init(button_t* button,uint8_t trigerlevel,uint8_t  (*get_button_Level)());
void register_callback(button_t* button,click_type_t type,callback cb);
click_type_t  get_button_event(button_t* button);
int button_start(button_t* button);
void button_stop(button_t* button);
void button_process(void);

#ifdef __cplusplus
} 
#endif

#endif


Published 2 original articles, praised 0 and visited 7
Private letter follow

Posted by NICKKKKK on Fri, 21 Feb 2020 06:12:52 -0800