STM32定时器实现不加延时的三种独立按键获取函数——返回1次,多次和长短按键

STM32定时器实现不加延时的三种独立按键获取函数——返回1次,多次和长短按键


最近在准备蓝桥杯,虽然以前也写过按键函数,但是没保存,每次写的时候思路都不一样。这里把现在想到的思路记录一下,为大家提供参考。
使用的开发板是蓝桥杯嵌入式的STM32G431RBT6,开发环境是用的keil5+STM32CubeMX(HAL库)。

连续按键

这里的连续按键是指,按键按下后会在按下期间一直返回,可以用在快速计算中。主要思路是用定时器定10ms后改变标志位来实现去抖动。
首先定义了两个标志位的存放寄存器:

u8 key_contr=0;	//0位控制10ms,1位控制单独按键,2位控制500ms,3位控制长短按键
u8 key_tims=0;	//0位代表10ms,2位代表500ms,3位控制长短按键

定时器7(周期1ms)回调函数的内容:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)		//定时器中断里面不能加hal延时
{
	if(htim->Instance==TIM7)			//1ms进一次
	{
		static u8 tmp_10ms=0;
		static u16 tmp_500ms=0;
		
		(key_contr & 0x01)?(tmp_10ms++):(tmp_10ms = 0);//10ms计时
		if(tmp_10ms>10)
		{
			tmp_10ms = 0;
			key_tims |= 0x01;
		}
		
		(key_contr & 0x04)?(tmp_500ms++):(tmp_500ms = 0);//10ms计时
		if(tmp_500ms>500)	//用于流水灯控制
		{
			tmp_500ms = 0;
			key_tims |= 0x04;
		}
		
		
	}
}

按键扫描函数如下:

/*********************连续按键,返回多次键值(10ms)******************************/
u8 Key_Scan1(void)		 
{
	u8 key=0;			//保存键值
	
	key = (GPIOB->IDR&0x0007)|(GPIOA->IDR&0x0001)<<3;	//读取A0,B0,B1,B2,B3四个按键状态
	key ^= 0x0f;										//按键是低电平有效所以取反一下
	
	if(key)
	{
		key_contr |= 0x01;			//按下后标志位置1
		if(key && key_tims&0x01)	//按下且定时器记到10ms后进入
		{
			key_contr &= 0xfe;		//一次按键监测完成,清零标致位返回键值
			key_tims &= 0xfe;
			return key;
		}
		else						//没到10ms,程序不等待继续往下运行
			return 0;
	}
	else
	{
		key_contr &= 0xfe;			//松开或按键抖动期间,清零标致位
		return 0;
	}
}
/*************************************************************************/

单独按键

这里的单独按键是指,按下松手后返回一次键值。可用在一般的按键控制逻辑中。主要思路:结合前面的连续按键定时器去抖动,增加一个标志位控制只返回一次键值。

/*********************单独按键,松手后返回一次键值******************************/
u8 Key_Scan2(void)		//单独按键,返回键值
{
	u8 key=0;			//保存键值
	static u8 key_temp=0;		//储存获取到的次数,用于标记按下的时间,理论上是10ms加一
	
	key = (GPIOB->IDR&0x0007)|(GPIOA->IDR&0x0001)<<3;	//读取A0,B0,B1,B2,B3四个按键状态
	key ^= 0x0f;							//按键是低电平有效所以取反一下
	
	if(key)
	{
		key_contr |= 0x01;			//按下后10ms判断标志位置1
		if(key && key_tims&0x01)	//按下且定时器记到10ms后进入
		{
			key_contr &= 0xfe;		//获取到一次有效按键,清零10ms判断标志位
			key_tims &= 0xfe;
			key_contr |= 0x02;		//打开单独按键控制标志位
			key_temp = key;			//储存键值,松手后返回
		}
		else
			return 0;
	}
	else 						
	{	
		if(key_contr&0x02)		//按下后松开
		{
			key_contr &= ~0x03;	//清除单独按键控制标志位
			return key_temp;	//松手后返回键值
		}
		else					//未按下
		{
			key_contr &= 0xfe;	//松开或按键抖动期间,清零标致位
			return 0;
		}
	}
	return 0;
}
/*************************************************************************/

长短按键

这里的长短按键指,按下时间少于2S只返回一次键值,大于两秒后和连续按键一样,可用在输入比较大的数字的时候。主要思路:通过检测到的连续按键次数,大于设定值后一直检测到一次连续按键返回一次键值,小于的时候用标志位控制只返回一次键值。

/*********************长短按(用于实现长按2s以上连续加,2s以下加一次),返回按键值******************************/
u8 Key_Scan3(void)
{
	static u16 key_num=0;
	u8 key1=0,key2=0;
	
	key1 = (GPIOB->IDR&0x0007)|(GPIOA->IDR&0x0001)<<3;	//读取A0,B0,B1,B2,B3四个按键状态
	key1 ^= 0x0f;			//按键是低电平有效所以取反一下
	
	if(!key1)			//未按下清除计数和标志位
	{
		key_contr &= ~0x08;
		key_num = 0;
	}
	key2 = Key_Scan1();		//检测是否有有效按键
	if(key2)				//按下
	{
		key_num++;			//计数
		if(key_num>100)		//超过100后一直返回键值
			return key2;
		else if(!(key_contr & 0x08))	//小于100时,只返回1次键值
		{
			key_contr |= 0x08;		//标志已返回过键值
			return key2;
		}
		else				//按下返回过一次键值后一直返回0
			return 0;
	}
	else					//未按下
		return 0;
}
/*************************************************************************/

总结

感觉写的比较冗余,还可以在改进一下,欢迎大家批评指正!(0_0)!
上传不了视频就放个动态图吧…:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值