【51单片机学习】(2)定时器扫描实现按键长按和短按

        用Delay消抖时会导致主程序中的一些进程受到影响,所以在这里借鉴江科大使用定时器扫描按键状态进行消抖的方法。在实际使用中加入了长按功能

按键驱动代码key.c

#include <REGX52.H>


unsigned char Key_KeyNumber,KeyTime,KeyCount,i;
unsigned int times;


/**
  * @brief  获取按键键码
  * @param  无
  * @retval 返回值Temp暂存按下按键的键码,范围:0-6共七位   其中键码值为0时表示无按键按下
  */
unsigned char Key(void)
{
	unsigned char Temp=0;
	Temp=Key_KeyNumber;
	Key_KeyNumber=0;

	return Temp;
}


/**
  * @brief  获取当前按键的状态,无消抖及松手检测
  * @param  无
  * @retval 返回值KeyNumber表示按下按键的键码,范围:0-6共七位   其中键码值为0时表示无按键按下
  */
unsigned char MatrixKey_GetState()
{
	unsigned char KeyNumber=0;

	P3=0Xff;
	P3_4=0;			 
	if(P3_5==0){KeyNumber=6;}
	if(P3_6==0){KeyNumber=4;}
	if(P3_7==0){KeyNumber=5;}
	
	P3=0Xff;
	P3_3=0;
	if(P3_5==0){KeyNumber=3;}
	if(P3_6==0){KeyNumber=1;}
	if(P3_7==0){KeyNumber=2;}

	return KeyNumber;
}


/**
  * @brief  按键驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Key_Loop(void)
{
	static unsigned char NowState,LastState;
	LastState=NowState;				
	NowState=MatrixKey_GetState();   //更新键码值
	if(LastState==1 || LastState==2  || LastState==3  || LastState==4)  //1-4号键单击功能
	{
		if(NowState==0)
		{
			Key_KeyNumber=LastState;		
		}
	}
	if(LastState==5 || LastState==6)
	{
		i++;
		times++;
		if(NowState==0)
		{
			KeyCount=i;
			i=0;
			if(LastState==5 && KeyCount<=50){Key_KeyNumber=5;KeyCount=0;}//短按时间小于1s
			else if(LastState==6 && KeyCount<=50){Key_KeyNumber=6;KeyCount=0;}//长按时间大于1s
			if(LastState==5 && KeyCount>=100){Key_KeyNumber=9;KeyCount=0;}//短按时间小于1s
			else if(LastState==6 && KeyCount>=100){Key_KeyNumber=10;KeyCount=0;}//长按时间大于1s
		}
		if(NowState)
		{
			if(times>=50)
			{
			    KeyTime++; 
				if(KeyTime>=10)
				{
				    if(LastState==5 && NowState==5){Key_KeyNumber=7;KeyTime=0;}//检测长按松手,防止长按后又判定到短按
					else if(LastState==6 && NowState==6){Key_KeyNumber=8;KeyTime=0;}		
				}
			}
		}
		else 
		{
			times=0;
		}
	}
}

//定时器中断函数
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=20)
	{
		T0Count=0;
		Key_Loop();//每隔20ms扫描一次
	}
}

定时器0初始化代码(20ms扫描一次按键状态)

#include <REGX52.H>

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

主函数main.c

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"

unsigned char KeyNum;

void main()
{
	Timer1Init();
	while(1)
	{
		    KeyNum=Key();		//获取独立按键键码
			if(KeyNum==1)	//如果K1按键按下
			{
				//执行相应动作
			}
	}
}

  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,使用定时器也是一种实现按键按双击的方法。 具体实现方法可以参考以下步骤: 1. 初始化定时器。选择合适的定时器,并设置定时器的时钟源、计数模式、计数周期等参数。一般推荐使用定时器的计数模式为向上计数,并且设置一个合适的计数周期。 2. 初始化按键。选择合适的引脚作为按键输入,配置引脚的输入模式和上拉/下拉电阻。一般推荐使用上拉电阻,使按键默认为高电平。 3. 在定时器中断服务函数中实现按键状态的检测和处理。在定时器中断服务函数中,读取按键状态,并根据当前状态和前一次状态的变化,判断按键事件的类型。如果按键被按下,则记录按下时间;如果按键被释放,则记录释放时间,并根据时间间隔判断按键事件的类型。 4. 根据按键事件的类型,执行相应的操作。例如,按事件可以用于开启或关闭某个功能;按事件可以用于切换不同的模式;双击事件可以用于执行快速操作。 注意事项: 1. 在定时器中断服务函数中,需要注意防抖处理。对于按键输入信号,由于存在抖动现象,因此需要使用软件或硬件方式进行防抖处理,以确保检测到的按键状态是稳定的。 2. 在定时器中断服务函数中,需要注意按键状态的检测间隔。检测间隔过会导致系统负载过高,检测间隔过会影响按键检测的灵敏度,因此需要选择一个合适的检测间隔。 3. 在定时器中断服务函数中,需要注意定时器的溢出问题。如果定时器的计数周期比较,容易出现定时器溢出的情况,需要进行相应的处理。 总之,使用定时器实现按键按双击需要结合具体的硬件平台和软件环境进行综合考虑,根据实际需求选择合适的方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值