按键检测状态机与按键消抖

独立按键检测的方法有:
1、轮询法
2、外部中断法
3、定时器中断法
4、定时器中断加状态机

按键消抖:
一、软件消抖
1、延时消抖与二次判断,延时一般用10ms即可。轮询法与外部中断法使用。外部中断边沿触发不消抖的话会有多次触发的现象。
2、利用定时器中断间隔来实现消抖。
二、硬件消抖
最简单的就是并联一个电容,一般使用104(0.1uf)电容。

使用定时器中断的方法,不用使用延时或者死循环,减少了CPU的占用,适用于大程序。定时器中断取10ms。

下面是状态机的程序,实际使用时,在定时器中断中调用,每10ms进行一次调用来检测判断。

(1)按键抬起时返回键值

 u8 key_state_0 = 0;     //初始状态
 u8 key_state_1 = 1;     //键按下确认状态
 u8 key_state_2 = 2;     //等待释放状态

//按键抬起时返回键值
unsigned char read_key(void)
{
    static u8 key_state=key_state_0;   //状态
	u8 key_press0;   //按键0电平              
	u8 key_press1;   //按键1电平
	u8 key_press2;   //按键2电平
    u8 key_return = 0;  //返回键值
	//读取电平值
    key_press0 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3);         // 读按键0电平
	key_press1 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4);         // 读按键1电平
	key_press2 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_5);         // 读按键2电平
	//判断
    switch (key_state)
    {
        case key_state_0:                 // 按键初始态
			if (!key_press0 || !key_press1 || !key_press2)        //如果检测到任意一个按键按下,转为按键确认状态       
            {
                 key_state = key_state_1;
            }	
            break;
                                
        case key_state_1:                   // 按键确认态
            if (!key_press0)   //如果是按键0按下
            {
                key_return = 1;         // 更新键值 
            }
            else if(!key_press1)//如果是按键1按下
            {
				key_return = 2;         // 更新键值
             }
			else if(!key_press2)//如果是按键2按下
			{
				key_return = 3;         // 更新键值
			}
			key_state = key_state_2;// 状态转换到键释放状态
            break;
                                
        case key_state_2:               //键释放状态  // 如果按键还在按下,还保留在该状态,直到释放时返回键值并返回初始状态      
			if (key_press0 && key_press1 && key_press2)  //如果都抬起了
            {
				key_state = key_state_0;    //返回初始状态
				return key_return;          //抬起时返回按键值
            }
            break;
   }
	return 0; 
}

(2)按键按下时返回键值,并且只触发一次

u8 key_state_0 = 0;     //按键的初始状态
 u8 key_state_1 = 1;     //按键按下确认状态
 u8 key_state_2 = 2;     //待释放状态
//按键按下时返回键值
unsigned char read_key(void)
{
    static u8 key_state=0;   //状态位 
	u8 key_press0;   //按键0电平              
	u8 key_press1;   //按键1电平
	u8 key_press2;   //按键2电平
    u8 key_return = 0;  //按键返回值

	//读取电平值
    key_press0 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3);         // 读按键0电平
	key_press1 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4);         // 读按键1电平
	key_press2 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_5);         // 读按键2电平
	//判断
    switch (key_state)
    {
        case key_state_0:                 // 按键初始态
			if (!key_press0 || !key_press1 || !key_press2)        //如果检测到任意一个按键按下,转为按键确认状态       
            {
                 key_state = key_state_1;
             }	
            break;
                                
        case key_state_1:                   // 按键确认态
            if (!key_press0)   //如果是按键0按下
            {
                key_return = 1;         //更新键值
                return key_return;      //立即返回键值
            }
            else if(!key_press1)//如果是按键1按下
            {
				key_return = 2;         
				return key_return;
             }
			else if(!key_press2)//如果是按键2按下
			{
				key_return = 3;        
				return key_return;
			}
			key_state = key_state_2;// 状态转换到键释放态
            break;
                                
        case key_state_2:               //键释放态  // 如果按键还在按下,还保留在该状态    
			if (key_press0 && key_press1 && key_press2) //如果抬起了则返回初始状态
            {
				key_state = key_state_0;
            }
            break;
   }
	return 0;
}

(3)具有长按和短按检测功能,达到长按要求立即返回键值,没有达到长按要求则返回短按键值,只触发一次

u8 key_state_0 = 0;     //按键的初始状态(状态1)
 u8 key_state_1 = 1;     //按键的按下确认状态(状态2)
 u8 key_state_2 = 2;     //按键的抬起状态或者长按状态(状态3)

//没有达到长按要求时,返回短按键值,达到长按要求时,返回长按键值
unsigned char read_key(void)
{
    static u8 key_state=0;   //状态位 
	static u8 i=0;    //长按计数值
	u8 key_return;   //键值
	u8 key_press0;   //按键0电平              
	u8 key_press1;   //按键1电平
	u8 key_press2;   //按键2电平
	//读取当前电平
    key_press0 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3);         // 读按键0电平
	key_press1 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4);         // 读按键1电平
	key_press2 = GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_5);         // 读按键2电平
	//判断
    switch (key_state)
    {
        case key_state_0:   // 按键初始态
			if(!key_press0 || !key_press1 || !key_press2)        //如果检测到任意一个按键第一次按下,则转为按键确认状态       
            {
                 key_state = key_state_1;
             }	
            break;
                                
        case key_state_1:    // 按键确认态
            if (!key_press0)   //如果确认按键0按下
            {
                key_return = 1;  //设置键值 
            }
            else if(!key_press1)//如果确认按键1按下
            {
				key_return = 2;  // 设置键值
             }
			else if(!key_press2)//如果确认按键2按下
			{
				key_return = 3;    //设置键值
			}
			key_state = key_state_2;// 状态转换到第三状态
            break;
                                
        case key_state_2:   //该状态可以实现长按和短按不同的功能
			if (!key_press0)   //如果按键0还在按下
            {
                i++;           //计数
				if(i==2)   //达到长按要求,则返回初始状态并直接返回按键值
				{
					key_return=4; 
					return key_return;   
				} 
            }
            else if(!key_press1)//如果是按键1按下
            {
				i++;
				if(i==2)
				{
					key_return=5;
					return key_return;
				}
             }
			else if(!key_press2)//如果是按键2按下
			{
				i++;
				if(i==2)
				{
					key_return=6;
					return key_return;
				}
			}
            else  //抬起了【一次按键完成】,处理长按过时与没有达到长按要求
            { 
				key_state = key_state_0;  //返回初始状态
				if(i<2)  //没有达到长按要求,则返回短按键值;  
				{
					i=0;
					return key_return;
				}
				else//大于2说明长按时间过长,返回0即可
				{
					i=0;
				}
            }
            break;
	}
	return 0;
}

如果不使用状态机,只使用定时器中断记录符合要求电平的次数,也可以实现检测按键长按与短按。当检测到符合电平时就连加1,当检测到不符合要求的电平时就清零。

有不对的或者好的方法欢迎指正,谢谢啦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值