按键防抖记录

按键防抖

自复位按键,在按下与弹起的时候,会有机械震荡产生,一般是毫秒级,所以高频的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;
		}		
	}
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Verilog按键防抖可以通过状态机(Mealy型)实现。具体实现步骤如下: 1. 定义状态:定义按键的两个状态,即按下和弹起状态。 2. 状态转移:根据按键的两个状态,设计状态转移图,确定状态之间的转移条件。 3. 状态输出:根据状态转移图,确定状态输出,即消抖后的按键信号。 4. 编写Verilog代码:根据状态转移图和状态输出,编写Verilog代码实现按键消抖。 以下是一个Verilog按键消抖的代码示例,假设按键为高电平有效: ```verilog module debounce( input clk, // 时钟信号 input rst, // 复位信号 input key, // 按键信号 output reg out // 消抖后的按键信号 ); // 定义状态 parameter IDLE = 2'b00; // 空闲状态 parameter PRESS = 2'b01; // 按下状态 parameter RELEASE = 2'b10; // 弹起状态 // 定义状态寄存器和下一状态寄存器 reg [1:0] state, next_state; // 定义计数器 reg [3:0] cnt; // 初始化状态和下一状态 initial begin state = IDLE; next_state = IDLE; end // 状态转移和状态输出 always @(posedge clk or posedge rst) begin if (rst) begin state <= IDLE; cnt <= 0; end else begin state <= next_state; case (state) IDLE: begin if (key == 1'b0) begin next_state = PRESS; cnt <= 0; end else begin next_state = IDLE; cnt <= 0; end end PRESS: begin if (key == 1'b0) begin if (cnt == 4'd15) begin next_state = RELEASE; cnt <= 0; end else begin next_state = PRESS; cnt <= cnt + 1; end end else begin next_state = IDLE; cnt <= 0; end end RELEASE: begin if (key == 1'b1) begin next_state = IDLE; cnt <= 0; end else begin next_state = RELEASE; cnt <= cnt + 1; end end endcase end end // 输出消抖后的按键信号 always @(state or cnt) begin if (state == PRESS && cnt == 4'd15) begin out = 1'b1; end else if (state == RELEASE && cnt == 4'd15) begin out = 1'b0; end else begin out = 1'bZ; end end endmodule ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值