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