欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

FPGA入门五

程序员文章站 2021-12-30 07:19:03
按键消抖实验按键消抖四种状态:1.高脉冲稳定状态 2.按下消抖状态 3.低电平稳定状态 4.键起消抖状态边沿检测电路:两个寄存器...

按键消抖实验

FPGA入门五
按键消抖四种状态:
1.高脉冲稳定状态 2.按下消抖状态 3.低电平稳定状态 4.键起消抖状态
FPGA入门五
边沿检测电路:两个寄存器
FPGA入门五

编写主逻辑文件

module Key_shake(Clk,Rst_n,Key_in,Key_flag,Key_data);
   input Clk;
	input Rst_n;
	input Key_in;
	output reg Key_flag; //当按键按下20ms消除抖动成功后产生一个脉冲flag信号,检测到产生flag信号后产生按键按下低电平。
	output reg Key_data;
	
   reg [3:0]state; 
   reg  [19:0]count; //寄存器计数	
	reg   count_start;//时能计时
	reg  count_full;//计满脉冲信号
	reg reg0,reg1;
	wire rise,fall;
	
	localparam 
	High_pulse      =   4'b0001, //高电平稳定状态
	Low_eliminate   = 4'b0010, //键下降沿稳定状态
	Low_pulse       = 4'b0100, //低电平稳定状态
	High_eliminate  = 4'b1000; //键上升沿稳定状态
	
	always @(posedge Clk or negedge Rst_n)    //脉冲边沿检测   两个寄存器
	 if(!Rst_n) begin
       reg0 <= 1'b0;
		 reg1 <=1'b0;
		 end
      else   begin 
		 reg0 <= Key_in;
	    reg1 <= reg0; 	
	end
	
	assign fall = !reg0 & reg1;  //检测到下降沿
	assign rise = reg0 & !reg1;  //检测到上升沿  
	
	 always @(posedge Clk  or negedge Rst_n)    //20ms计数器
       if(!Rst_n)
          count <= 20'b0;            	
	      else  if(count_start)
			  count <= count + 20'b1;
             else  count <= 20'b0;		  	
				 
	 always @(posedge Clk  or negedge Rst_n)     //20ms计数器计数满标志脉冲信号
       if(!Rst_n)
          count_full <= 1'b0;            	
	      else  if(count == 99_9999)
			  count_full <= 1'b1;
             else  count_full <= 1'b0;	
				 
	always @(posedge Clk or negedge Rst_n)
	 if(!Rst_n) begin
	  Key_data <= 1'b1;
	  state <= High_pulse;
	  Key_flag <= 1'b0;
	  count_start <= 1'b0;
         end		
	  else  case(state) 
	          High_pulse : begin  Key_flag <= 0;  
				                     Key_data <= 1'b1;
				   if(fall) begin
					    state <= Low_eliminate;
						 count_start <= 1'b1;   //使能开始20ms计数
	              end
					  else   state <= High_pulse;
					      end
				 Low_eliminate :  
   				if(count_full) begin
					     state <= Low_pulse;
						  Key_flag <= 1'b1;
				        Key_data <= 1'b0;
						  count_start <= 1'b0;   //关闭使能20ms计数
						 end
					 else begin  
					     if(rise) begin
						 state <= High_pulse;
						 count_start <= 1'b0;   //关闭使能20ms计数
						               end
					      else 
							 state <= Low_eliminate;
						         end
              
              Low_pulse:  begin Key_flag <= 1'b0;
                 if(rise) begin
					    state <= High_eliminate;
						 count_start <= 1'b1; //开始计时
						 end
					  else  state <= Low_pulse;
				            end
			     High_eliminate : 
				     if(count_full) begin
					   Key_data <= 1'b1;
						Key_flag <= 1'b1;
						state <= High_pulse;
					  end
					   else begin
						  if(fall) begin
						   state <= Low_pulse;
							count_start <= 1'b0;
							   end else 
								 state <= High_eliminate;
						            end		
		
		default : begin 
		               state <= High_pulse; //默认状态
							count_start <= 1'b0;
							Key_data <= 1'b1;
					    	Key_flag <= 1'b0;
		     end
	  endcase 

endmodule 

主逻辑文件仿真

`timescale 1ns/1ns
`define period_clock 20
module Key_shake_tb;
   
	reg Clk;
	reg Rst_n;
	reg Key_in;  //高电平为按键默认状态
	wire Key_flag; 
	wire Key_data;
   reg  [15:0]random_time; //寄存器存储不超过20ms的随机时间
Key_shake  Key_shake0(
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Key_in(Key_in),
  .Key_flag(Key_flag),
  .Key_data(Key_data)
  );

initial Clk = 1;
always #(`period_clock/2) Clk = ~Clk;
initial begin
    Rst_n = 0;
	 Key_in = 1;
	 #(`period_clock*10);
	 Rst_n = 1;
    #(`period_clock*10);
	 press_key;
	 Key_in = 0;
	 #(`period_clock*1000010);
     press_key;
	  Key_in = 1;
	 #(`period_clock*1010010); 
	 $stop;
	 
	 end

task press_key;  //任务
begin
   repeat(50) begin
  	 random_time = {$random}%65535;   //无{}表示取值范围-65535~65535
 	 #random_time  Key_in = ~ Key_in; 
	end
end 
 endtask

endmodule 

仿真结果

FPGA入门五
在消抖稳定后20m产生Key_flag信号和Key_state信号。

仿真模型概念

FPGA入门五
Key_shake_tb0模块应为Key_shake0模块,写错。

Key_shake_tb仿真模型模块

`timescale 1ns/1ns
`define period_clock 20
module Key_shake_tb;
   
	reg Clk;
	reg Rst_n;
	wire Key_in;  //高电平为按键默认状态 两个寄存器连接wire型
	wire Key_flag; 
	wire Key_data;
   reg  [15:0]random_time; //寄存器存储不超过20ms的随机时间
Key_shake  Key_shake0(
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Key_in(Key_in),
  .Key_flag(Key_flag),
  .Key_data(Key_data)
  );
Key_model  Key_model(
  .Key(Key_in)
      );
initial Clk = 1;
always #(`period_clock/2) Clk = ~Clk;
initial begin
    Rst_n = 0;
	 #(`period_clock*10);
	 Rst_n = 1;
    #(`period_clock*10+1); 
	 end

endmodule 

Key_model模块

模拟产生按键抖动信号

`timescale 1ns/1ns
`define period_clock 20
module Key_model(Key); //按键模型
output  reg  Key;
reg  [15:0]random_time; //寄存器存储不超过20ms的随机时间
initial begin
       Key = 1'b1;
	   press_key;
	 #(`period_clock*1000);
     press_key;
	 #(`period_clock*1010); 
	 $stop; 
	 end

task press_key;  //任务
begin
   repeat(50) begin
  	 random_time = {$random}%65535;   //无{}表示取值范围-65535~65535
 	 #random_time  Key = ~ Key; 
	end
	 Key = 0;
	 #(`period_clock*1000010);
	
	repeat(50) begin
  	 random_time = {$random}%65535;   //无{}表示取值范围-65535~65535
 	 #random_time  Key = ~ Key; 
	end
	Key = 1;
	#(`period_clock*2000010);
end 
 endtask
 
endmodule

仿真结果

FPGA入门五

异步信号处理

在输入信号之前添加两级寄存器。减少D触发器震荡。按键事件对响应时间要求不高,可以使用多级触发器。

module Key_shake(Clk,Rst_n,Key_in,Key_flag,Key_data);
   input Clk;
	input Rst_n;
	input Key_in;
	output reg Key_flag; //当按键按下20ms消除抖动成功后产生一个脉冲flag信号,检测到产生flag信号后产生按键按下低电平。
	output reg Key_data;
	
   reg [3:0]state; 
   reg  [19:0]count; //寄存器计数	
	reg   count_start;//时能计时
	reg  count_full;//计满脉冲信号
	reg reg0,reg1;
	reg key_in_now0,key_in_now1;
	wire rise,fall;
	
	localparam 
	High_pulse      =   4'b0001, //高电平稳定状态
	Low_eliminate   = 4'b0010, //键下降沿稳定状态
	Low_pulse       = 4'b0100, //低电平稳定状态
	High_eliminate  = 4'b1000; //键上升沿稳定状态
	
		always @(posedge Clk or negedge Rst_n)    //对输入按键信号做同步处理,消除异步信号亚稳态的影响。
	 if(!Rst_n) begin
       key_in_now0 <= 1'b0;
		 key_in_now1 <=1'b0;
		 end
      else   begin 
		 key_in_now0 <= Key_in;
	    key_in_now1 <= key_in_now0; 	
	end
	
	
	always @(posedge Clk or negedge Rst_n)    //脉冲边沿检测   两个寄存器
	 if(!Rst_n) begin
       reg0 <= 1'b0;
		 reg1 <=1'b0;
		 end
      else   begin 
		 reg0 <= key_in_now1;
	    reg1 <= reg0; 	
	end
	
	assign fall = !reg0 & reg1;  //检测到下降沿
	assign rise = reg0 & !reg1;  //检测到上升沿  
	
	 always @(posedge Clk  or negedge Rst_n)    //20ms计数器
       if(!Rst_n)
          count <= 20'b0;            	
	      else  if(count_start)
			  count <= count + 20'b1;
             else  count <= 20'b0;		  	
				 
	 always @(posedge Clk  or negedge Rst_n)     //20ms计数器计数满标志脉冲信号
       if(!Rst_n)
          count_full <= 1'b0;            	
	      else  if(count == 99_9999)
			  count_full <= 1'b1;
             else  count_full <= 1'b0;	
				 
   状态机(同上)

endmodule 

FPGA入门五

顶层文件Key_led_top

module Key_led_top(Clk,Rst_n,Key_in0,Key_in1,led);
  input Clk;
  input Rst_n;
  input Key_in0,Key_in1;
  output [3:0]led;
  wire Key_flag0,Key_flag1;
  wire Key_data0,Key_data1;
  
   Key_shake   Key_shake0(
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Key_in(Key_in0),
  .Key_flag(Key_flag0),
  .Key_data(Key_data0)
  );
     
   Key_shake   Key_shake1(
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Key_in(Key_in1),
  .Key_flag(Key_flag1),
  .Key_data(Key_data1)
  );
  
  Led_control Led_control0(
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Key_flag0(Key_flag0),
  .Key_state0(Key_data0),
  .Key_flag1(Key_flag1),
  .Key_state1(Key_data1),
  .Led(led)
  );

endmodule 

LED驱动文件Led_control

module Led_control(Clk,Rst_n,Key_flag0,Key_state0,Key_flag1,Key_state1,Led);
  input Clk,Rst_n;
  input Key_flag0,Key_flag1;
  input Key_state0,Key_state1;
  output   [3:0]Led;
  reg [3:0]Led_un;
  
  always @(posedge Clk  or negedge Rst_n)
   if(!Rst_n)
	  Led_un <= 4'b0000;
	  else  if(Key_flag0 && Key_state0)
       Led_un <= Led_un + 4'b1;
        else  if(Key_flag1 && Key_state1)
         Led_un <= Led_un - 4'b1;
	 else 
	   Led_un <= Led_un;
  
  assign Led = ~Led_un;
  
endmodule 

顶层仿真文件

`timescale 1ns/1ns
`define period_clock 20
module Led_top_tb;
  
  reg Clock;
  reg Rst_n;
  wire Key_in0;
  wire Key_in1;
  reg press0,press1;
  wire [3:0]led;
 

Key_led_top Key_led_top0(
  .Clk(Clock),
  .Rst_n(Rst_n),
  .Key_in0(Key_in0),
  .Key_in1(Key_in1),
  .led(led)
    );
Key_model  Key_model0( 
         .Press(press0),
			.Key(Key_in0)
			  ); 
Key_model  Key_model1( 
         .Press(press1),
			.Key(Key_in1)
			  ); 
initial Clock = 1;
always #(`period_clock/2) Clock = ~Clock;

initial begin
  Rst_n = 0;
  press0 = 0;
  press1 = 0;
  #(`period_clock*4);
   Rst_n = 1;
 #(`period_clock*10+1);
   press0 = 1;     //自加
 #(`period_clock*2);
   press0 = 0;
 #(`period_clock*4_000_000);
	press0 = 1;
 #(`period_clock*2);
   press0 = 0;
 #(`period_clock*4_000_000);
 
 
   press1 = 1;     //自加
 #(`period_clock*2);
   press1 = 0;
 #(`period_clock*4_000_000);
	press1 = 1;
 #(`period_clock*2);
   press1 = 0;
 #(`period_clock*4_000_000);
   $stop;
end
			  
			  
endmodule 

仿真结果

FPGA入门五
Key_flag0信号使LED自增,Key_flag1信号使LED自减。led取反。

本文地址:https://blog.csdn.net/qq_43485409/article/details/108103829

相关标签: FPGA