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)!
上传不了视频就放个动态图吧…:在这里插入图片描述

版权声明:本文为CSDN博主「《CHANGE》」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43698771/article/details/122565480

最近在准备蓝桥杯,虽然以前也写过按键函数,但是没保存,每次写的时候思路都不一样。这里把现在想到的思路记录一下,为大家提供参考。

使用的开发板是蓝桥杯嵌入式的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)!
上传不了视频就放个动态图吧…:在这里插入图片描述

版权声明:本文为CSDN博主「《CHANGE》」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43698771/article/details/122565480

生成海报
点赞 0

《CHANGE》

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

基于STM32的指纹密码锁

设计简介: 本设计是基于单片机的指纹密码锁,主要实现以下功能: 矩阵按键输入密码,并通过按键显示*号可通过按键或手机开门密码可通过按键进行开门可通过蓝牙模块连接手机进行开门可通过指纹进