用户登录
用户注册

分享至

FPGA入门五

  • 作者: XX4763430
  • 来源: 51数据库
  • 2021-06-28

按键消抖实验


按键消抖四种状态:
1.高脉冲稳定状态 2.按下消抖状态 3.低电平稳定状态 4.键起消抖状态

边沿检测电路:两个寄存器

编写主逻辑文件

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 

仿真结果


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

仿真模型概念


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

仿真结果

异步信号处理

在输入信号之前添加两级寄存器。减少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 

顶层文件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 

仿真结果


Key_flag0信号使LED自增,Key_flag1信号使LED自减。led取反。

软件
前端设计
程序设计
Java相关