按键防抖记录

本文介绍了按键防抖技术,包括硬件电容防抖和软件延时/计数防抖方法。重点讲述了状态机计数防抖的实现,以减少CPU阻塞,提高代码执行效率,适用于多键独立按键系统。
摘要由CSDN通过智能技术生成

按键防抖

自复位按键,在按下与弹起的时候,会有机械震荡产生,一般是毫秒级,所以高频的CPU采集数据时,会出现一次按键操作,识别为多次,造成按键多次触发的情况。
所以需要进行按键防抖操作。
按键防抖分软件防抖硬件防抖

硬件防抖

硬件防抖是就是在按钮上并上一个合适大小的电容(100nF),用来削峰。

软件防抖

延时防抖

不推荐
首先了解按键的抖动时间,然后采用延时的方式规避这个时间,简单易懂。
高频处理的业务中,会阻塞CPU,导致其他的代码执行效率低。

	uint8_t KeyNum = 0;
	if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET)
	{
		Delay_ms(10);
		while(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET);
		Delay_ms(10);
		KeyNum = 1;
	}

优点:代码简单
缺点:阻塞CPU

状态机 + 计数防抖

采用计数的方式,可以有效避免CPU的阻塞。
状态机的引入,可以有效管理按键的状态,避免误识别。
状态机流程:
0:初始 <-> 1:触发(抖动) -> 2:稳定 <-> 3:离开(抖动) -> 0:初始
注意抖动时期可以跳到上一个状态,也可以待其稳定(采用计数方式判断)切到下一个状态。
这里先按一个按键写代码:

uint16_t Key1_Cnt = 0; // 计数
uint8_t Key1_Sta = 0; // 状态
/**
  * @brief  扫描按键1的状态
  * @param  无
  * @retval 无
  */
void Key_Scan0(void)
{
	// 0:初始 1:触发 2:稳定 3:离开 0:初始
	switch(Key1_Sta)
	{
		case 0:
			if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET)
			{
				Key1_Sta = 1;
				Key1_Cnt = 0;
			}
			break;
		case 1:
			Key1_Cnt++;
			if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_SET)
			{
				Key1_Sta = 0;
			} else if(Key1_Cnt == 10)
			{
				Key1_Sta = 2;
				Key1_Cnt = 0;
				Debug_Printf("key1 pressed");
			}
			break;
		case 2:
			if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_SET)
			{
				Key1_Sta = 3;
				Key1_Cnt = 0;
			}
			break;
		case 3:
			Key1_Cnt++;
			if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == GPIO_PIN_RESET)
			{
				Key1_Sta = 2;
			} else if(Key1_Cnt == 10)
			{
				Key1_Sta = 0;
				Debug_Printf("key2 released");
			}
			break;
		default:
			
			break;
	}
}

如果是多个独立按键可以封装下代码:

#define KEY_NUM 2 // 按键个数
#define KEY_CNT 5 // 计数次数

uint16_t Key_Cnt[KEY_NUM + 1] = {0};
uint8_t Key_Sta[KEY_NUM + 1] = {0};

uint8_t Key_ReadPin(uint8_t n)
{
	uint8_t sta = 0;
	switch(n)
	{
		case 1:
			sta = HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN);
			break;
		case 2:
			sta = HAL_GPIO_ReadPin(KEY2_PORT, KEY2_PIN);
			break;
		default:
			sta = -1;
			break;
	}
	return (uint8_t)sta;
}

/**
  * @brief  扫描所有独立按键的状态
  * @param  无
  * @retval 无
  */
void Key_Scan(void)
{
	uint8_t i = 0;
	for(i = 1 ; i <= KEY_NUM; i++)
	{
		// 0:初始 1:触发 2:稳定 3:离开 0:初始
		switch(Key_Sta[i])
		{
			case 0:
				if(Key_ReadPin(i) == GPIO_PIN_RESET)
				{
					Key_Sta[i] = 1;
					Key_Cnt[i] = 0;
				}
				break;
			case 1:
				Key_Cnt[i]++;
				if(Key_ReadPin(i) == GPIO_PIN_SET)
				{
					Key_Sta[i] = 0;
				} else if(Key_Cnt[i] == KEY_CNT)
				{
					Key_Sta[i] = 2;
					Key_Cnt[i] = 0;
					Debug_Printf("key %d pressed",i);
				}
				break;
			case 2:
				if(Key_ReadPin(i) == GPIO_PIN_SET)
				{
					Key_Sta[i] = 3;
					Key_Cnt[i] = 0;
				}
				break;
			case 3:
				Key_Cnt[i]++;
				if(Key_ReadPin(i) == GPIO_PIN_RESET)
				{
					Key_Sta[i] = 2;
				} else if(Key_Cnt[i] == KEY_CNT)
				{
					Key_Sta[i] = 0;
					Debug_Printf("key %d released", i);
				}
				break;
		}		
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值