按键状态机

 功能:实现按键的单机,双击,长按

采用定时器检测按键电平,判断按键触发方式


//假设10ms判断一次按键电平
#define SINGLE_PRESS_TIME       3     //30ms
#define LONG_PRESS_TIME         300   //3s
#define REPEAT_PRESS_TIME       50

#define KEY_NUM                 8
#define KEY_FIFO_SIZE           8

typedef enum
{
	KEY_NULL,
	KEY_PRESS,
	KEY_RELEASE
}KEY_STATU;

typedef enum
{
	DISABLE,
	ENABLE
}KEY_ENABLE_STATUS;

typedef enum
{
	NONE,
	SINGLE_CLICK,
	DOUBLE_CLICK,
	LONG_PRESS
}KEY_EVT;


typedef struct 
{
	KEY_ENABLE_STATUS enflag;           //按键使能标志
	KEY_STATU statu;                    //按键状态标志
	
	KEY_EVT key_evt;                    //按键产生的事件
	
	int repeatflag;                     //双击标志位
	int flag;                           //第一次单机标志位
	
	int repeat_press_time;              //双击间隔时间
	int press_time;                     //按键出发时间
	
	void (*is_key_down)(void);          //判断是否按键按下
	void (*long_press_evt)(void);       //长按事件
	void (*single_click_evt)(void);     //单击事件
	void (*double_click_evt)(void);     //双击事件
}KEY;


typedef struct
{
	int key_num;
	KEY_EVT key_evt;
}KEY_FIFO_T;


typedef struct 
{
	int read;
	int write;
	KEY_FIFO_T evt_fifo[KEY_FIFO_SIZE];
}KEY_FIFO;

KEY  key_buff[KEY_NUM];
KEY_FIFO key_fifo;

void API_PUTEVTS(int key_num, KEY_EVT key_evt)
{
	key_fifo.evt_fifo[key_fifo.write].key_num = key_num;
	key_fifo.evt_fifo[key_fifo.write].key_evt = key_evt;
	key_fifo.write = (key_fifo.write + 1) % KEY_FIFO_SIZE;
}

bool API_GETEVTS(KEY_FIFO_T *evt)
{
	bool ret = false;
	if(key_fifo.read == key_fifo.write)
		ret = false;
	else
	{
		ret = true;
		evt->key_num = key_fifo.evt_fifo[key_fifo.read].key_num;
		evt->key_evt = key_fifo.evt_fifo[key_fifo.read].key_evt;
		key_fifo.read = (key_fifo.read + 1) % KEY_FIFO_SIZE;
	}
	return ret;
}

void KEY_SCAN()
{
	for(int key_num = 0; key_num < KEY_NUM; key_num++)
	{
		if(key_buff[key_num].enflag)
		{
			switch(key_buff[key_num].statu)
			{
			    case KEY_NULL:
					if(key_buff[key_num].is_key_down())
					{	
						key_buff[key_num].statu = KEY_PRESS;
						key_buff[key_num].press_time = 0;
					}
					if(key_buff[key_num].repeat_press_time > 0)
					{
						key_buff[key_num].repeat_press_time--;
					}
					break;
					
				case KEY_PRESS:
					if(key_buff[key_num].is_key_down())
						key_buff[key_num].press_time++;
						
					if(key_buff[key_num].press_time < SINGLE_PRESS_TIME)
						key_buff[key_num].statu = KEY_NULL;
					else
					{
						if(key_buff[key_num].repeat_press_time > 0)
						{
							key_buff[key_num].repeatflag = 1;
						}
						key_buff[key_num].statu = KEY_RELEASE;
					}
						
					break;
					
				case KEY_RELEASE:
					if(key_buff[key_num].is_key_down())
					{	
						key_buff[key_num].press_time++;
					}
					else
					{
						if(key_buff[key_num].press_time < LONG_PRESS_TIME)
						{
							if(!key_buff[key_num].flag)
							{
								key_buff[key_num].repeat_press_time = REPEAT_PRESS_TIME;
								key_buff[key_num].flag = 1;
							}
							else
							{
								if(key_buff[key_num].repeatflag)
								{
									key_buff[key_num].key_evt = DOUBLE_CLICK;
									key_buff[key_num].repeatflag = 0;
								} 
								else
								{
									key_buff[key_num].key_evt = SINGLE_CLICK;
								}	
								key_buff[key_num].flag = 0;	
                                API_PUTEVTS(key_num, key_buff[key_num].key_evt);							
							}
						}
						else
						{
							key_buff[key_num].key_evt = LONG_PRESS;
                            API_PUTEVTS(key_num, key_buff[key_num].key_evt);
						}
						key_buff[key_num].statu = KEY_NULL;
					}
					break;
					
				default:
					break;
			}
		}
	}
}


void KEY_EVT()
{
	KEY_FIFO_T evt;
	if(API_GETEVTS(&evt))
	{
		switch(evt.key_evt)
		{
			case SINGLE_CLICK:
				key_buff[evt.key_num].single_click_evt();
				break;
			case DOUBLE_CLICK:
				key_buff[evt.key_num].double_click_evt();
				break;
			case LONG_PRESS:
				key_buff[evt.key_num].long_press_evt();
				break;
			default:
				break;
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值