FPGA之按键消抖

按键默认状态为高电平,当按键被按下并稳定后,为低电平,如图1所示:

 图1

 按键在被按下过程中的电平变化如图2所示:

 图2 

据统计,按键单次抖动时间小于20ms,此处可用计数器 进行计时;根据图2,按键被按下过程可以分解为4中状态:

1、当按键被按下抖动期间;

2、按键被按下;

3、按键被释放抖动y

4、按键释放后恢复高电平。

因此,可以采用状态机进行设计,可分为4个状态:

IDEL:等待按键被按下,即下降沿的来临,跳转到FILTER0;

FILTER0:计数按键被按下后单次抖动所耗时间,当时间大于20ms时,跳转到DOWN;

DOWN:按键确定被按下,等待上升沿来临,跳转到FILTER1;

FILTER1:计数按键被释放后单次抖动所耗时间,当时间大于20ms时,按键被释放,按键的整个过程结束,跳转到IDEL,等待下一轮按键被按下;

图3 状态图 

按键消抖工程代码如下所示:

module key_filter(
  input clk,
  input rst_n,
  input key,
  output reg key_flag,
  output reg key_state);
  
  reg[2:0] key_shift;
  always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	   key_shift <= 3'b111;
	 end
	 else begin
	   key_shift <= {key_shift[1:0],key};
	 end
  end
  
  wire key_pos;
  assign key_pos = key_shift[1] && (!key_shift[2]);
  wire key_neg;
  assign key_neg = (!key_shift[1]) && key_shift[2];
  
  localparam IDEL = 4'b0000;
  localparam FILTER0 = 4'b0001;
  localparam DOWN = 4'b0011;
  localparam FILTER1 = 4'b0010; 
  
  reg cnt_en;
  reg[22:0] cnt;
  always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	   cnt <= 23'd0;
	 end
	 else begin
	   if(cnt_en)begin
		  cnt <= cnt + 23'd1;
		end
		else begin
		  cnt <= 23'd0;
		end
	 end
  end
  
  reg cnt_full;
  always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	   cnt_full <= 1'b0;
	 end
	 else begin
	   if(cnt == 23'd399999)begin
		  cnt_full <=1'b1;
		end
		else begin
		  cnt_full <= 1'b0;
		end
	 end
  end
  
  reg[3:0] state;
  always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	   cnt_en <= 1'b0;
		key_flag <= 1'b0;
		key_state <= 1'b1;
	   state <= IDEL;
	 end
	 else begin
	   case(state)
		  IDEL:begin
		    key_flag <= 1'b0;
		    if(key_neg)begin
			   cnt_en <= 1'b1;
			   state <= FILTER0;
			 end
			 else begin
			   state <= IDEL;
			 end
		  end
		  FILTER0:begin
		    if(cnt_full)begin
			   cnt_en <= 1'b0;
				key_flag <= 1'b1;
				key_state <= 1'b0;
			   state <= DOWN;
			 end
			 else begin
			   if(key_pos)begin
				  cnt_en <= 1'b0;
				  state <= IDEL;
				end
			   else begin
				  state <= FILTER0;
				end
			 end
		  end
		  DOWN:begin
		    key_flag <= 1'b0;
		    if(key_pos)begin
			   cnt_en <= 1'b1;
			   state <= FILTER1;
			 end
			 else begin
			   state <= DOWN;
			 end
		  end
		  FILTER1:begin
		    if(cnt_full)begin
			   cnt_en <= 1'b0;
				key_flag <= 1'b1;
				key_state <= 1'b1;
				state <= IDEL;
			 end
			 else begin
			   if(key_neg)begin
				  cnt_en <= 1'b0;
				  state <= DOWN;
				end
				else begin
				  state <= FILTER1;
				end
			 end
		  end
		  default:begin
	       cnt_en <= 1'b0;
		    key_flag <= 1'b0;
		    key_state <= 1'b1;
	       state <= IDEL;
		  end
		endcase
	 end
  end

endmodule

此处对输入的信号key打了三拍,第一拍实现异步信号转同步,后两拍实现处理亚稳态;本工程还采用用来沿触发技术。

模拟真实按键被按下的过程,其模块代码如下所示:

`timescale 1ns/1ps

module key_mode(
  output reg key);
  
  initial begin
    key = 1'b1;
	 press_key;
	 #10000;
	 press_key;
	 #10000;
	 press_key;
	 #10000;
	 $stop;

  end
  
  reg[15:0] myrand;
  task press_key;
  begin
  
	 repeat(50)begin
	   myrand = {$random} % 65535;
		# myrand key = ~key;
	 end
	 key = 1'b0;
	 #25000000;
	 
	 repeat(50)begin
	   myrand = {$random} % 65535;
		# myrand key = ~key;
	 end
	 key = 1'b1;
	 #25000000;
	 
  end
  endtask
  
endmodule

仿真代码如下所示:

`timescale 1ns/1ps
`define clk_period 20

module key_filter_tb;
  
  reg clk;
  reg rst_n;
  wire key;
  wire key_flag;
  wire key_state;
  
  key_mode key_mode_inst(
    .key(key));
  
  key_filter key_filter_inst(
    .clk(clk),
    .rst_n(rst_n),
    .key(key),
    .key_flag(key_flag),
    .key_state(key_state));

  initial clk = 1'b0;
  always #(`clk_period / 2) clk = ~clk;
  
  initial begin
    rst_n = 1'b0;
    #(`clk_period*10);
	 rst_n = 1'b1;
    #(`clk_period*10 + 1);		
  end

endmodule

工程代码可百度网盘下载 

链接:https://pan.baidu.com/s/1Vb-7TB-SeIbt6Zq84TsBSA 
提取码:foge

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值