FPGA基础入门篇(六) 按键防抖电路实现(三)

FPGA基础入门篇(六) 按键防抖电路实现(三)
本节继续介绍关于按键防抖的电路介绍,电路的防抖其实是加一个延时模块。本节将简化程序的设计,并且介绍debug的方法。

一、参数传递

verilog可以使用# 进行参数的传递
具体参数传递的方式:
1、module_name #( parameter1, parameter2) inst_name( port_map);
2、module_name #( .parameter_name(para_value), .parameter_name(para_value)) inst_name (port map);

二、设计思路
  1. 首先让时钟分频,产生10ms的使能信号。然后将过程分为四个状态:
    KEY_S0:判断按键是否按下,如果是,则进入下一状态KEY_S1;
    KEY_S1:10ms延时后,再次判断按键是否按下,如果是,则进入KEY_S3,否则进入KEY_S0;
    KEY_S2:判断按键是否抬起,如果是,则进入下一状态KEY_S3;
    KEY_S3:10ms延时后,再次判断按键是否抬起,如果是,则进入KEY_S0,否则进入KEY_S2;

  2. 当状态由KEY_S1进入KEY_S2时,表明按键key_cap被按下,并且输出一个高电平。

  3. debug信号:
    格式:(mark_debug = “true”) 信号名,用于后面在线debug信号。

三、设计代码
  1. Verilog HDL
//top模块
module Key_Jitter(
input clk_i,
input rst_n_i,
input key_i,
output [3:0] led_o
);
(*mark_debug = "true"*) reg [3:0] led_o;  		//用于debug的信号端口。
(*mark_debug = "true"*) wire key_cap;

always @(posedge clk_i)begin
    if(!rst_n_i)begin
        led_o <= 4'b0000;
    end
    else if(key_cap)begin
        led_o <= ~led_o;  
    end
end

key #( .CLK_FREQ(100000000) )			//	参数传递的其中一种方法2,并调用key模块。
key0(
.clk_i(clk_i),
.key_i(key_i),
.key_cap(key_cap)
);

//调用的Key子模块
module key #(parameter CLK_FREQ = 100000000)(
input clk_i,
input key_i,
output key_cap
);
//10ms
parameter CNT_10MS = (CLK_FREQ/100 - 1'b1);
parameter KEY_S0 = 2'd0;		//四种状态
parameter KEY_S1 = 2'd1;
parameter KEY_S2 = 2'd2;
parameter KEY_S3 = 2'd3;

reg [24:0] cnt10ms = 25'd0;
(*mark_debug = "true"*) reg [1:0] key_s = 2'b0;
(*mark_debug = "true"*) reg [1:0] key_s_r = 2'b0;
(*mark_debug = "true"*) wire en_10ms ;
 
assign en_10ms = (cnt10ms == CNT_10MS);
assign key_cap = (key_s == KEY_S2) && (key_s_r == KEY_S1);    /*key_s 比key_s_r快一个时钟周期,则先进入KEY_S2状态。
这样每次10ms到来时,key_s与key_s_r只相差一个周期。用于输出一个高电平key_cap。
*/
always @(posedge clk_i)begin
    if(cnt10ms < CNT_10MS) 
        cnt10ms <= cnt10ms + 1'b1;
    else 
        cnt10ms <= 25'd0;
end

always @(posedge clk_i)begin
    key_s_r <= key_s;		//打慢一拍
end

always @(posedge clk_i)begin  //状态机块
    if(en_10ms)begin
        case(key_s)
        KEY_S0:begin
           if(!key_i)
               key_s <= KEY_S1; 
        end  
        KEY_S1:begin
           if(!key_i)
               key_s <= KEY_S2; 
            else 
               key_s <= KEY_S0; 
        end 
        KEY_S2:begin
           if(key_i)
               key_s <= KEY_S3; 
        end  
        KEY_S3:begin
           if(key_i)
              key_s <= KEY_S0;
            else   
              key_s <= KEY_S2; 
        end
        endcase                  
    end
end
endmodule
  1. 仿真测试文件:
module Key_Jitter_TB;

	// Inputs
	reg clk_i;
	reg rst_n_i;
	reg key_i;
	wire [3:0] led_o;


	// Instantiate the Unit Under Test (UUT)
	Key_Jitter uut (
		.clk_i(clk_i), 
		.rst_n_i(rst_n_i), 
		.key_i(key_i), 
		.led_o(led_o)
	);

initial
	begin
		// Initialize Inputs
		clk_i = 0;
		forever
		#5 clk_i=~clk_i;
	end
	
initial
	begin
		// Initialize Inputs
		rst_n_i = 0;
		#100;
		rst_n_i=1;
		key_i = 1;
		#10000;
		forever
			begin
				key_i = 0;
				// Wait 100 ns for global reset to finish
				#100;
				key_i=1; #1000;
				key_i=0; #1000;
				key_i=1; #2000;
				key_i=0; #5000;
				#50000000;
				key_i=1;
				key_i=0; #1000;
                key_i=1; #2000;
                key_i=0; #1000;
                key_i=1; #2000;
				#50000000;
				key_i=0;
				
			end
	end

endmodule
  1. RTL仿真结果:
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第1张图片
    可以看到每隔10ms,状态机模块刷新一次,20ms时,key_cap输出一个高电平具体可以看下面的分析。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第2张图片
    20ms时的计数使能为高电平,然后key_s在下一周期进入KEY_S2,再过一个时钟周期,key_s_r才进入KEY_S2。
    中间的空档期一个时钟内key_s为状态KEY_S2,key_s_r仍为KEY_S1,所以可以产生一个高电平key_cap。
四、Chipscope 在线逻辑分析仪仿真
一、RTL仿真后RTL并不一定完全正确执行,可以通过Xilinx自带的在线逻辑分析,在板子运行并查看我们想要的关键信号。

具体格式:
将(maek_debug = “true”)添加到需要观察的信号前面,如本次实验添加了如下信号:

(*mark_debug = "true"*) reg [3:0] led_o;  		
(*mark_debug = "true"*) wire key_cap;
(*mark_debug = "true"*) reg [1:0] key_s = 2'b0;
(*mark_debug = "true"*) reg [1:0] key_s_r = 2'b0;
(*mark_debug = "true"*) wire en_10ms ;
二、使用vivado2017.4 版本软件zynq-7000系列器件。其他版本均可兼容。

具体操作步骤:

  1. 先将测试过的代码进行综合:然后点击下面的Set Up Debug,设置需要debug的信号。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第3张图片
  2. 进入如下图
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第4张图片
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第5张图片
  3. 然后对采用的深度进行设置,以及Capture Control, 对于这种比较慢的信号,Xilinx的在线逻辑分析低于20M采样速度的,波形窗口不会显示波形。可以通过设置Capture Control,用en_10ms来作为捕捉控制,而采样时钟仍然为系统时钟。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第6张图片
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第7张图片
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第8张图片
  4. 完成后,一定要注意单击保存按钮,然后会出现下图的原理图。不保存,无法观察到调试信号。原理图中蚂蚁信号即为添加调试标记的信号。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第9张图片
  5. 然后编译、下载bit流,让开发板供电,接好JTAG后,如下。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第10张图片
  6. 如果信号没有在窗口的,可以手动按照下面进行添加。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第11张图片
  7. 设置触发,以及Capture信号。
    Capture一定要设置为BASE,Capture mode 设置为2048
    参数可以自己选定。
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第12张图片
  8. 以信号en_10ms作为Capture信号
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第13张图片
  9. 以信号key_cap为触发信号
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第14张图片
  10. 点击如下开始按钮,启动采集,并同时按下按键,可以连续多次按键,当所有信号触发玩后如下图所示,可以分析按键程序的状态机的工作以及LED等其他信号的输出变化。
    在这里插入图片描述
    FPGA基础入门篇(六) 按键防抖电路实现(三)_第15张图片

你可能感兴趣的:(数字IC设计-FPGA)