有限状态机实现按键防抖动电路

有限状态机实现按键防抖动电路

简要
由于金属弹性形变的原因,按键/开关在状态切换过程中总是会有或多或少的抖动情况,有时这种抖动会导致电路误动作,甚至无法正常工作。比如在设置参数时,按一下“加 1”可能会加 4~5 个数;生活中常见的情况是鼠标单击变成了双击等。因此,在很多时候,输入电路的信号需要经过防抖动处理之后才会送到后级电路。
按键抖动的电压波形如图 1 如示,tjitter 是抖动时间,通常在 1ms~30ms 之间。

图1

设计要求
用 Verilog HDL 设计一个按键防抖动电路,要求用有限状态机实现。防抖动电路的输入接开发板的拨动开关,输出接 1 位十进制计数译码显示电路的时钟输入,实现每拨动一次开关计数器加 1,多次测试不出现抖动现象。
状态定义

parameter IDLE = 4'b0001;//闲置状态
parameter key1 = 4'b0010;//按下按键存在抖动的状态
parameter key2 = 4'b0100;//按下按键的稳定状态
parameter key3 = 4'b1000;//松开按键存在抖动的状态

状态转化图
在这里插入图片描述

程序代码
顶层模块:

module TYXS(
input clk,//clk时钟信号,rst清零信号,低电平清零,key为输入信号
input rst,
input key,
output  key_out,//输出的防抖动之后的波形
output  [6:0]codeout
);
digital a(
key_out,
rst,
codeout);
key_sh b(
clk,
rst,
key,
key_out
);
endmodule 

十进制译码器显示模块

module digital(key_out,rst,codeout);
input key_out,rst;
output reg[6:0]codeout;
reg[3:0] keyout10;//寄存器用于十进制译码器显示,每按一次按键计数器加一
always@(posedge key_out,negedge rst)//十进制译码器显示,原有波形上升沿触发,即每按一次按键计数器加一
begin
  if(!rst) keyout10 <= 4'd0;
  else begin
    if(keyout10==4'd9) keyout10 <= 4'd0;//置零
	 else keyout10 <= keyout10 + 4'd1;
  end
end
always@(*)
  begin
  case(keyout10)
4'b0000: codeout<= 7'b1000000;  //0
4'b0001: codeout<= 7'b1111001;  //1
4'b0010: codeout<= 7'b0100100;  //2
4'b0011: codeout<= 7'b0110000;  //3
4'b0100: codeout<= 7'b0011001;  //4
4'b0101: codeout<= 7'b0010010;  //5
4'b0110: codeout<= 7'b0000010;  //6
4'b0111: codeout<= 7'b1111000;  //7
4'b1000: codeout<= 7'b0000000;  //8
4'b1001: codeout<= 7'b0010000;  //9

endcase
end
endmodule 

按键防抖动模块

module key_sh(
input clk,//clk时钟信号,rst清零信号,低电平清零,key为输入信号

input rst,
input key,
output reg key_out//输出的防抖动之后的波形
);
reg cnt_en;    //控制计数信号工作状态的使能信号
reg [18:0] cnt;//设置一个计数信号
reg [3:0] ns;  //nextstate,状态信号

parameter IDLE = 4'b0001;//闲置状态
parameter key1 = 4'b0010;//按下按键存在抖动的状态
parameter key2 = 4'b0100;//按下按键的稳定状态
parameter key3 = 4'b1000;//松开按键存在抖动的状态

always@(posedge clk,negedge rst)//计数器
begin
  if(!rst) cnt <= 0;
  else if(cnt_en) cnt <= cnt + 1'b1;//计数器使能为1时,开始计数,否则清零
  else cnt <= 0;
end
always@(posedge clk,negedge rst)
begin
  if(!rst) 
   begin
    ns <= IDLE;
	 cnt_en <= 0;
	 key_out <= 0;
	end
  else 
  begin
    case(ns)
	   IDLE:begin
		  key_out <= 1'b0;//初始输出波形为低电平
		  if(key==1&&cnt_en==0) 
		   begin
		    ns <= key1;//满足条件后进入下一状态key1
			 cnt_en <= 1'b1;//使能信号变为1,计数器开始工作
			end
		  else
		  ns <= IDLE;//不满足条件,回归初始状态
		end
		
		key1:begin
		  key_out <= 1'b0;//按下按键时输出波形为低电平
		  if(cnt >= 19'd50_0000&&key==1) //因为testbench中设置了时间单位为10ns时钟周期为20ns,而设置的抖动波形不超过10ms,所以这里计数50万次
		   begin
		    ns <= key2;//满足条件后进入下一状态key2,即延时了10ms
			 cnt_en <= 1'b0;//使能信号变为0,计数器停止工作且清零
			end
			else if (cnt >= 19'd50_0000&&key==0)//防止出现一按下又松开的情况
			begin
		    ns <= IDLE;//回归初始状态
			 cnt_en <= 1'b0;//使能信号变为0,计数器停止工作且清零
			end
		  else 
		  ns <= key1;//不满足计数条件则保持当前状态
		end
		
		key2:begin
		  key_out <= 1'b1;
		  if(key==0&&cnt_en==0) 
		   begin
		    ns <= key3;//满足条件后进入下一状态key3
			 cnt_en <= 1'b1;//使能信号变为1,计数器开始工作
			end
		  else 
		  ns <= key2;//不满足计数条件则保持当前状态
		end
		
		key3:begin
		  key_out <= 1'b1;
		  if(cnt >= 19'd50_0000&&key==0) 
		   begin
		    ns <= IDLE;//处理完成,回归初始状态
			 cnt_en <= 1'b0;//使能信号变为0,计数器停止工作且清零
			end
			else if (cnt >= 19'd50_0000&&key==1)//防止出现一松开又按下的情况
			begin
			 ns <= key2;//回归上一状态
			 cnt_en <= 1'b0;//使能信号变为0,计数器停止工作且清零
			end
		  else 
		  ns <= key3;//不满足计数条件则保持当前状态
		end
		default :ns <= IDLE;
	 endcase
  end
end
endmodule

仿真结果
在这里插入图片描述

  • 19
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值