按键单击,双击,长按开关机,定时器消抖

当发生电平变化中断(外部中断)产生一个中断触发标志。然后去定时器中进行处理。

因为我当前所做的项目对运行时间要求不高,我将按键的处理放置在定时器中断中处理,如果对运行时间有要求,可以把对按键的判断放置在主程序中。例: 按键长按开关机,单击功能切换

按键长按开关机,单击功能切换

中断中处理

 主程序中处理

双击开关机

单击开关机,功能切换

两个按键控制同一个LED

按键长按开关机,单击功能切换

中断中处理

void isr(void) __interrupt(0)
{
	if(INTFbits.PBIF)					//电平变化中断与睡眠唤醒中断
	{	
		PBIF_Trigger = 1;				//中断触发标志		
		Flag_Time=0;					//消抖清零
		INTFbits.PBIF=0;				//中断标志位清零
	}
	
	if(INTFbits.T0IF)					//1MS定时器
	{
		Flag_Time++;					//消抖累加
		if(PBIF_Trigger)
		{
			if(Flag_Time>=30)			//30ms消抖
			{
				if(!KEY_DOWN)			//按键触发判断
				{
					Flag_Time=0;		//消抖清零
					Hold_Time++;		//按键按下持续时间
					if(Hold_Time>=60)	//持续时间超过1.8S
					{
						Hold_Time=0;	//清零
						//Long_Press=1;	//长按标志位,在主程序中处理
					}	
				}
				else
				{
					if(Hold_Time)		//保持时间小于1.8S,算为单击
					{
						//Function_M1++;	//功能切换
					}
					Hold_Time=0;		
					PBIF_Trigger=0;		//中断触发标志清零
				}
			}
		}
		TMR0 = 0XC4;					
		INTFbits.T0IF=0;
	}
}

 主程序中处理

void isr(void) __interrupt(0)
{
	if(INTFbits.PBIF)					//电平变化中断与睡眠唤醒中断
	{	
		PBIF_Trigger = 1;				//中断触发标志		
		Flag_Time=0;					//消抖清零
		INTFbits.PBIF=0;				//中断标志位清零
	}
	if(INTFbits.T0IF)					//1MS定时器
	{
		Flag_Time++;					//消抖累加
		TMR0 = 0XC4;					
		INTFbits.T0IF=0;
	}
}
void main()
{
    Systen_Initial();
    while(1)
    {
        if(PBIF_Trigger)
        {
            if(Flag_Time>=30)			//30ms消抖
	        {
		    	if(!KEY_DOWN)			//按键触发判断
		    	{
		    		Flag_Time=0;		//消抖清零
		    		Hold_Time++;		//按键按下持续时间
		    		if(Hold_Time>=60)	//持续时间超过1.8S
		    		{
		    			Hold_Time=0;	//清零
		    			if(Flag_Run_Sleep == 1)
						{
							Flag_Run_Sleep=0;
							LED=0;	
							Flag_ON_OFF=0;	
						}
						else 
						{				
							Inital_Sleep();	
							LED=1;
						}
                        PBIF_Trigger=0;
		    		}	
		    	}
		    	else
		    	{
		    		if(Hold_Time)		//保持时间小于1.8S,算为单击
		    		{
		    			//Function_M1++;	//功能切换
		    		}
		    		Hold_Time=0;		
		    		PBIF_Trigger=0;		//中断触发标志清零
		    	}
		    }
        }
        else
            Flag_Time = 0;  
    }
}

双击开关机

if(INTFbits.PABIF)
{
    Delay_Time = 0;                 
    // 消抖清零
    Key_Delay_Time = 0;
    User_Flag.PABIF_Trigger = 1;	
    // 中断触发标志,在定时器中断中进行处理
    // 需要与进入睡眠互锁,标志不清除,进入不了睡眠,不然可能有BUG
    INTFbits.PABIF = 0;					
}

 if(INTFbits.T0IF)			        // 1MS定时器
    {
		TMR0  = 0x09;               
        // 无自动重载寄存器 需要软件置位
		if(User_Flag.PABIF_Trigger)    //电平变化产生标志
		{
			Delay_Time++;
			if( (Input_Key) || (User_Flag.Key_Trigger) )	
            // 按键按下与按键松开可进
				Key_Delay_Time++;   
                // 只有关于按键的标志才会自增
			if(Delay_Time >= 40)	
            // 防止充电器插拔与电池充满产生的中断,导致进入,产生误触发
			{
				if(Key_Delay_Time>30) // 30MS
				{
					if(Input_Key)     // 按键按下,高有效
					{
						User_Flag.Key_Trigger = 1;    
                        // 防止当按键松开时,进入不了
						if(User_Flag.Key_Up_Trigger)  // 是否第二次按下
						{
                            if(User_Flag.System_Sleep)// 系统现在是在休眠还是工作
							{
								User_Flag.System_Sleep = 0;	// 清除睡眠标志,去工作
							}
							else 
							{	
								User_Flag.System_Sleep = 1;	// 在工作,去睡觉
							}
							User_Flag.Key_Up_Trigger = 0;   
                            // 标志触发过,清除
							User_Flag.System_Stuta_Change = 1; 
                            // 防止系统把第二次按键松开,判断为第一次按键松开
                            // 需要与进入睡眠互锁,标志不清除,进入不了睡眠,不然可能有BUG
                        }
					}
					else
					{
						if(User_Flag.System_Stuta_Change)    
                            // 第二次按键松开 跳过
							User_Flag.System_Stuta_Change=0;
						else
						{
							User_Flag.Key_Up_Trigger = 1;    
                            // 第一次按键松开标志
                            // 需要与进入睡眠互锁,标志不清除,进入不了睡眠,不然可能有BUG
							Double_Click_Waiting = 0;        
                            // 开始计数 第一次按键松开400MS内,无再触发,判断为无效
						}
						User_Flag.Key_Trigger = 0;
                        // 按下一次置一一次,松开一次执行一次清零一次					
                    }
				}
				User_Flag.PABIF_Trigger = 0;
                // 程序执行完毕,清零
				Key_Delay_Time = 0;    // 清零,等待下次计时	
				Delay_Time = 0;
			}
		}
    	if(User_Flag.Key_Up_Trigger)    // 按键第一次松开后,等待第二次按键按下
    	{
    		Double_Click_Waiting++;
    		if(Double_Click_Waiting >= 400)	// 标志位有效时间400ms
    		{
    			Double_Click_Waiting = 0;
    			User_Flag.Key_Up_Trigger = 0;
    		}
    	}
        INTFbits.T0IF = 0;					// 中断标志位软件清零
    }     

单击开关机,功能切换

void isr(void) __interrupt(0)
{
    if(INTFbits.PBIF)
    {
    	User_Flag.PBIF_Trigger=1;					//中断触发标志
    	Key_Delay_Time=0;							//消抖清零
        INTFbits.PBIF = 0;							// Clear PBIF(PortB input change interrupt flag bit)
    }
    if(INTFbits.T0IF)								//2ms定时器中断
    {
    	//PWM_Standard++;								//模拟PWM
    	Key_Delay_Time++;							
		if(User_Flag.PBIF_Trigger)
		{
    		if(Key_Delay_Time>12)					//24ms消抖
    		{
	    		if(!KEY_DOWN_Input)					//按键低有效
	    		{
	    			//User_Flag.System_Standby=0;		//退出睡眠模式
	    			//User_Flag.Function_Switch++;	//功能切换
	    			//PWM_Duty_Cycle=0;				//可能可以不写
	    			//PWM_Standard=0;					//基准清零,不写会导致第一个周期偏短
	    			//User_Flag.Variate_ADD=1;		//循环周期增加标志
	    			//User_Flag.Sound_Trigger=1;		//咪头触发标志,切换到模式3时,自动触发一次输出
	    		}
	    		Key_Delay_Time=0;					//消抖清零
	    		User_Flag.PBIF_Trigger=0;			//清除中断触发标志
    		}
    	}
    	TMR0 = 0X81;
        INTFbits.T0IF = 0;							// 清除定时器0中断标志位
    }      
}

两个按键控制同一个LED

KEY_1: 0:空 1:声控模式 2~n:进入睡眠模式 KEY_2: 0:空 1:常亮 2:炫彩呼吸灯 3~n:进入睡眠模式

单击唤醒 单击切换功能

屏蔽一个按键按下不松开,导致当另一个按键按下产生误触发。

void isr(void) __interrupt(0)
{
	if(INTFbits.PABIF)		//电平变化中断与睡眠唤醒中断
    {
    	Key_Delay_Time=0;	//按键消抖时间清零
    	PABIF_Trigger=1;	//中断触发标志 
        INTFbits.PABIF = 0;	// 清除中断标志位
    }
    if(INTFbits.T0IF)		//4ms定时器中断
    {
		if(PABIF_Trigger)	//如果不在中断,可以换成按键输入引脚
		{
			Key_Delay_Time++;	
			if(Key_Delay_Time>5)	//20ms消抖
	    	{
	    		if(!Input_KEY_2)	//KEY_2是否按下 正常模式
	    		{
	    			if((KEY_1_FLAG)&&(KEY_2_FLAG))	//任意一个按键是否按下后未松开
	    			{
		    			//System_Standby=0;			//退出睡眠模式,防止程序未处理完,就进入睡眠模式,使程序卡死                  
						//Function_Switch_1=0;		//声控模式不执行
						//Function_Switch++;			//模式切换 0:空 1:常亮 2:炫彩呼吸灯 3~n:进入睡眠模式
					}
					KEY_2_FLAG=0;					//按键按下标志
	    		}
				else
	    			KEY_2_FLAG=1;	    			//按键松开
    		}
    		if(Key_Delay_Time>5)					//消抖。在我这个编译器中,不能和上面消抖合并。会导致程序出错									{
				if(!Input_KEY_1)					//KEY_1  声控模式
	    		{
	    			if((KEY_1_FLAG)&&(KEY_2_FLAG))	//任意一个按键是否按下后未松开
	    			{
		    			//System_Standby=0;			//退出睡眠模式
		    			//Mic_Trigger=0;				//声音触发标志位清零
						//Function_Switch=0;			//正常模式不执行
						//Function_Switch_1++;		//模式切换 0:空 1:声控模式 2~n:进入睡眠模式
					}
					KEY_1_FLAG=0;					//按键按下
	    		}
	    		else
	    			KEY_1_FLAG=1;					//按键松开
				Key_Delay_Time=0;					//消抖清零
	    		PABIF_Trigger=0;					//清除电平变化触发标志
	    	}
    	}
    	TMR0 = 0X00;
        INTFbits.T0IF = 0;					// Clear PBIF(PortB input change interrupt flag bit)
    }      
}

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
STM32是一种嵌入式微控制器,具有灵活的输入输出引脚。使用STM32可以方便地实现按键单击双击按功能。 实现按键单击功能的方法是,在程序中通过轮询检测按键引脚的电平状态。当检测到按键引脚的电平从高变低时,就可以认为发生了按键单击事件。在处理事件的代码中可以执行相应的操作,比如控制LED灯亮起或熄灭。 要实现按键双击功能,可以利用计时器和中断。当按键引脚由高电平变为低电平时,启动计时器,并设置一个适当的时间阈值。在计时器中断中断中,检查按键引脚的电平状态,如果在规定的时间内再次检测到低电平,就可以认为发生了双击事件。在处理双击事件的代码中,可以执行相应的操作,如切换LED灯的状态。 要实现按键按功能,也可以利用计时器和中断。当按键引脚由高电平变为低电平时,启动计时器,并设置一个较的时间阈值。在计时器中断中,检查按键引脚的电平状态,如果在规定的时间内仍然保持低电平,就可以认为发生了按事件。在处理按事件的代码中,可以执行相应的操作,如控制LED灯持续亮起或熄灭,或者是执行其他功能。 总结来说,通过对STM32的输入输出引脚进行轮询检测,并结合计时器和中断的使用,可以实现按键单击双击按功能。这种灵活和可编程性是STM32在嵌入式系统中广泛应用的原因之一。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c1278943913

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值