FPGA密码锁-----verilog按键消抖模块的实现

## 密码锁-----按键消抖模块详解

在这里插入图片描述

  1. 如上图所示为按键原理图,当按键不按下的时候为高电平,按键按下的时候为低电平。于是通过检测key信号电平,就可以判断按键状态。
    但反作用弹簧会导致抖动现象,使得电平信号出现一段不确定波形
    在这里插入图片描述
    通过上图思考:如何判断是抖动?
    一般情况下,抖动的电平信号为1的持续时间不会超过20ms,文中假定抖动为10ms,那么就可以通过对抖动波形进行计数,小于10ms的情况下,又出现了高电平或者低电平,就认为是一次抖动,否则高低电平的持续时间超过了10ms,那么才是真正的按键按下或者释放动作。
  2. 状态机实现按键消抖
    2.1 状态分析
    在这里插入图片描述
    IDLE:空闲状态
    F0:按下消抖状态
    DOWN:按下稳定状态
    F1:释放消抖状态
    2.2 状态条件转换分析:
    在这里插入图片描述
  3. 文中需要判断下降沿和上升沿,从而进行条件的设置,所以就要进行边沿检测。边沿检测一个直接的方法:设置两个寄存器,对前一状态和后一状态进行寄存,若前后两个状态不同,则检测到了边沿,对于上升沿还是下降沿的确定可以用组合逻辑比较来确定。若前一状态为高电平,后面状态为低电平,则为下降沿,反之为上升沿。下图为边沿检测的原理图:

在这里插入图片描述
按键消抖模块设计:
//10ms按键消抖
//IDLE 未按下时的空闲状态
//FILTER0 按下抖动滤除状态
//DOWN 按下稳定状态
//FILTER1 释放抖动滤除状态

module key_filter(clk,rst_n,key_in,key_state,key_p_flag,key_r_flag,key_flag);

    input clk;
	 input rst_n;
	 input key_in;
	 

	 wire nedge; //下降沿
	 wire pedge; //上升沿
	 reg key_in0,key_in1; 
	 reg [3:0] state;    //四种状态,空闲,按下消抖,释放,释放消抖
	 reg [23:0] cnt;    //10ms
	 reg en_cnt;
	 reg cnt_full;
	 
	 output reg key_p_flag;  //按下标志
	 output reg key_r_flag;  //释放标志
	 output     key_flag;    //按键切换的标志(有按键按下或者释放)
	 output reg key_state;  //按键状态标志
	 
	 assign key_flag = key_p_flag || key_r_flag;
	 
	 
	 localparam   IDLE    =  4'd0001;
	 localparam   FILTER0 =  4'd0010;
	 localparam   DOWN    =  4'd0100;
	 localparam   FILTER1 =  4'd1000;
		  
//10ms计数器的设计
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		cnt <= 24'd0;
	else if(en_cnt) //计数使能信号
		cnt <= cnt + 1'b1;
	else
		cnt <= 24'd0;


always @(posedge clk or negedge rst_n)begin
     if(!rst_n)
	    cnt_full <= 1'b0;
	 else if(cnt==24'd499999)  //加满10ms则产生一个高脉冲
	    cnt_full <= 1'b1;
	 else
	    cnt_full <= 1'b0;
end	


	 
	 //用两级寄存器实现边沿检测
always @(posedge clk or negedge rst_n)begin
     if(!rst_n)begin
	    key_in0 <=1'b0;
		 key_in1 <=1'b0;
		 end
	 else begin
	    key_in0 <= key_in;
	    key_in1 <= key_in0;
		end
end	
	assign nedge = ~key_in0 & key_in1;
	assign pedge = key_in0 & !key_in1;



always @(posedge clk or negedge rst_n)begin
     if(!rst_n)	begin
	    state <= IDLE;
		 en_cnt <= 1'b0;
		 key_p_flag <= 1'b0;
		 key_r_flag <= 1'b0;
		 key_state <= 1;    //没按下的时候高电平
		end
	  else begin
	    case(state)
		  IDLE:
		   begin
			 key_r_flag <= 1'b0;
		     if(nedge)begin
			    state <= FILTER0;
				 en_cnt <= 1'b1;
				end
			  else
			    state <= IDLE;
		   end
			
		  FILTER0:
			if(cnt_full)begin
				key_p_flag <= 1'b1;
				key_state <= 1'b0;
				en_cnt <= 1'b0;
				state <= DOWN;
			end
			else if(pedge)begin
				state <= IDLE;
				en_cnt <= 1'b0;
			end
			else
				state <= FILTER0;

			 
	  DOWN:
	  begin 
	  key_p_flag <= 1'b0;
	       if (pedge)begin
			   state <= FILTER1;
				en_cnt <= 1'b1;
			end
			 else
			   state <= DOWN;
   end

		FILTER1:
			if(cnt_full)begin
				key_r_flag <= 1'b1;
				key_state <= 1'b1;
				state <= IDLE;
				en_cnt <= 1'b0;
			end
			else if(nedge)begin
				en_cnt <= 1'b0;
				state <= DOWN;
			end
			else
				state <= FILTER1;

    default :   state <= IDLE;
endcase  
end    
end 
endmodule 

tb测试

module key_filter_tb;

reg clk;
reg rst_n;
reg key_in;

wire key_flag;
wire key_state;
wire [3:0] state; 
key_filter key_filter0(
	.clk(clk),
	.rst_n(rst_n),
	.key_in(key_in),
	.key_flag(key_flag),
	.key_p_flag(key_p_flag),
	.key_r_flag(key_r_flag),
	.state(state),
	.key_state(key_state)
);

initial clk= 1;
always#(`clk_period/2) clk = ~clk;

initial begin
	rst_n = 1'b0;
	key_in = 1'b1;
	#(`clk_period*10) rst_n = 1'b1;
    #(`clk_period*10 + 1); //与时钟边沿稍微延后1ns,减少门级仿真中亚稳态的产生
    
    //模拟按下抖动 20ms 内
	key_in = 1'b0;#1000;
	key_in = 1'b1;#2000;
	key_in = 1'b0;#1400;
	key_in = 1'b1;#2600;
	key_in = 1'b0;#1300;
	key_in = 1'b1;#200;
	key_in = 1'b0;#500100;
	#50000100;
	//产生一个低电平大于 20ms,代表按下稳定
    
    //模拟释放抖动 20ms 内
	key_in = 1'b1;#2000;
	key_in = 1'b0;#1000;
	key_in = 1'b1;#2000;
	key_in = 1'b0;#1400;
	key_in = 1'b1;#2600;
	key_in = 1'b0;#1300;
	key_in = 1'b1;#500100;
	#50000100;
	//产生一个高电平大于 20ms,代表释放稳定
    
    //模拟按下抖动 20ms 内
	key_in = 1'b0;#1000;
	key_in = 1'b1;#2000;
	key_in = 1'b0;#1400;
	key_in = 1'b1;#2600;
	key_in = 1'b0;#1300;
	key_in = 1'b1;#200;
	key_in = 1'b0;#500100;
	#50000100;
	//产生一个低电平大于 20ms,代表按下稳定
    
    //模拟释放抖动 20ms 内
	key_in = 1'b1;#2000;
	key_in = 1'b0;#1000;
	key_in = 1'b1;#2000;
	key_in = 1'b0;#1400;
	key_in = 1'b1;#2600;
	key_in = 1'b0;#1300;
	key_in = 1'b1;#500100;
	#50000100;
    //产生一个高电平大于 20ms,代表释放稳定
    
	$stop;		
end

endmodule

下降沿检测波形图:
在这里插入图片描述
上升沿检测波形图:
在这里插入图片描述
4. 按键消抖的测试
1ms = 1000000ns
在进行tb仿真的时候,需要下降沿或者上升沿持续至少10ms,(10ms = 10000000ns)(10000000 /20 = 500000) 所以就是至少#500000个周期才能得到真正的按键按下和释放
在这里插入图片描述
在tb里面加入状态的跳转切换进行测试
在这里插入图片描述

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FPGA密码锁程序是一种基于FPGA芯片的数字密码锁系统,使用Altera公司的Quartus软件进行程序设计和开发。 FPGA(现场可编程门阵列)是一类可编程逻辑器件,可以根据需要被重新编程以执行特定的功能。密码锁程序使用FPGA芯片作为主控制单元,通过对芯片中的逻辑单元进行重新配置,实现密码输入和验证的功能。 在Quartus软件中,首先需要进行逻辑设计,包括密码输入和密码验证的逻辑电路。可以使用硬件描述语言(HDL)如VHDL或Verilog,或者使用可视化编程工具如SOPC Builder进行设计。设计好的逻辑电路将被翻译成FPGA芯片所能理解的位流(bitstream)文件。 接下来,需要进行信号约束和时序分析。信号约束用于规定逻辑电路中各个信号的时间限制和电气约束,确保电路能够在规定的频率下正常工作。时序分析则用于检查逻辑电路的时序性能,发现潜在的时序违规问题。 完成信号约束和时序分析后,就可以进行编译和生成位流文件。编译过程包括逻辑综合、技术映射和布线。逻辑综合将逻辑电路转换成可用的逻辑门级网表,技术映射将逻辑门级网表映射到目标FPGA芯片的资源上,布线则将逻辑电路中的逻辑门和寄存器实际连线。 生成位流文件后,可以将其下载到FPGA开发板上进行验证和测试。通过输入密码,密码锁程序会根据设计好的逻辑电路进行密码验证,并控制开关等外设进行锁的开关操作。 总而言之,FPGA密码锁程序是基于FPGA芯片的数字密码锁系统,在Quartus软件中进行逻辑设计、信号约束、时序分析、编译和生成位流文件等步骤后,在FPGA开发板上进行验证和测试。这种程序设计方法的灵活性和可编程性使得密码锁具有更高的安全性和定制化程度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting_FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值