简介
这份是我在实际工作中摸索并逐步形成的一个比较好与可扩展性比较稳定的按键驱动框架,自己已经在51和ARM中都运行过,无论是普通实体按键还是触摸按键皆可采用,主要实现了长按和短按功能,按键是嵌入式中一个不可忽视和必须掌握的功能,故分享之。
参考代码
//1.实体按键,以STM32F0(Cotex_M0)芯片为例
//api function:
void Button_getValue(keyEvent_st *keyEvent_me);//键值获取函数
void Button_scanEvent(keyEvent_st *keyEvent_me);//按键扫描函数
void Button_trigEvent(keyEvent_st *keyEvent_me);//按键单按事件
void Button_holdEvent(keyEvent_st *keyEvent_me);//按键长按事件
//----------------------------按键相关数据结构---------------------------------
typedef enum
{
KEY_NULL=0,
KEY_1,
KEY_2,
//...
}keyId_em;
typedef struct
{
unsigned char now; //按键当前状态
unsigned char last;//按键前次状态
}keyStatus_st;
typedef struct
{
keyStatus_st status; //按键状态
keyId_em tirg_id; //按键触发量id(唯一性)
keyId_em hold_id; //按键保持量id(唯一性)
unsigned char value; //按键键值(包含组合键值)
unsigned int hold_rtimer; //按下计时器(公共性)
}keyEvent_st;
keyEvent_st keyEvent;
//--------------------------按键硬接口宏定义---------------------------------
#define BUTTON_PORT GPIOA
#define BUTTON_1_PIN GPIO_Pin_1
#define BUTTON_1_PIN GPIO_Pin_2
#define KEY1() GPIO_ReadInputDataBit(BUTTON_PORT,BUTTON_1_PIN)
#define KEY2() GPIO_ReadInputDataBit(BUTTON_PORT,BUTTON_2_PIN)
#define KEY_ACTION (KEY1()&&KEY2())
//---------------------------按键运行元时间---------------------------------
#define KEY_SLICE_TIME 10
//---------------------------键值获取函数-------------------------------------
void Button_getValue(keyEvent_st *keyEvent_me)
{
if(RESET==KEY_ACTION) //有按键按下(在本硬件上,RESET:按下;SET:弹起)
{
if(RESET==KEY1())
{
keyEvent_me->value=1; //键值1
}
else if(RESET==KEY2())
{
keyEvent_me->value=2;//键值2
}
//....以此类推
}
else //无按键按下
{
keyEvent_me->value=NULL;//无键值
}
}
//-----------按键扫描函数-------
void Button_actionEvent(keyEvent_st *keyEvent_me)
{
Button_getValue(keyEvent_me);//扫描按键
if(NULL!=keyEvent_me->value)//有键值
{
keyEvent_me->status.now=1;//状态置位
}
else
{
keyEvent_me->status.now=NULL;
}
//-----------------按键动作--------------
if(keyEvent_me->status.now)//有按下
{
keyEvent_me->hold_rtimer++;//长按计时
if(keyEvent_me->status.last!=keyEvent_me->status.now)//按键有变化
{
if(keyEvent_me->status.now)//为按下动作
{
keyEvent_me->hold_id=(keyId_em)keyEvent_me->value;
keyEvent_me->trig_id=(keyId_em)keyEvent_me->value;
}
}
}
else //没有按下
{
keyEvent_me->hold_rtimer=0;//
}
keyEvent_me->status.last=keyEvent_me->status.now;//记录当前按键末态状态
}
//-----------触发型处理函数【用于点(短)按事件处理】-----
void Button_trigEvent(keyEvent_st *keyEvent_me)
{
switch(keyEvent_me->trig_id)
{
case KEY_1:
//相关处理函数
break;
case KEY_2:
//相关处理函数
break;
//...以此类推
default:
break;
}
keyEvent_me->tirg_id=NULL;//用完立即释放
}
//-----------保持型处理函数【用于按住不放事件的处理】-----
void Button_holdEvent(keyEvent_st *keyEvent_me)
{
#define KEY1_HOLD_TIME1 (100/KEY_SLICE_TIME) //长按时间数
#define KEY2_HOLD_TIME1 (300/KEY_SLICE_TIME) //长按时间数
switch(keyEvent_me->hold_id)
{
case KEY_1:
//for example
if(KEY1_HOLD_TIME1<keyEvent_me->hold_rtimer)
{
//相关处理函数
}
break;
case KEY_2:
if(KEY2_HOLD_TIME1<keyEvent_me->hold_rtimer)
{
//相关处理函数
}
break;
//...以此类推
default:
break;
}
}
//----------------放置在定时时间片内运行----------------------
void Button_Thread(void)
{
Button_actionEvent(&keyEvent);
Button_trigEvent(&keyEvent);
Button_holdEvent(&keyEvent);
}
该驱动框架结构多有不合理之处,为此做了优化,可移步该文按键驱动框架优化鉴阅。