软件版本:VIVADO2017.4
操作系统:WIN10 64bit
硬件平台:适用米联客 ZYNQ系列开发板
米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!
按键的消抖,是指按键在闭合或松开的瞬间伴随着一连串的抖动,这样的抖动将直接影响设计系统的稳定性,降低响应灵敏度。因此,必须对抖动进行处理,即消除抖动的影响。实际工程中,有很多消抖方案,如RS触发器消抖,电容充放电消抖,软件消抖。本章利用FPGA内部来设计消抖,即采取软件消抖。
按键的机械特性,决定着按键的抖动时间,一般抖动时间在5ms~10ms。消抖,也意味着,每次在按键闭合或松开期间,跳过这段抖动时间,再检测按键的状态。只要通过简单的延时就可实现按键的消抖动。
开发板底板中配套4个独立按键与FPGA相连,具体请参见底板原理图。本章使用了开发板按键和led。各个按键独立,消抖过程相同,因此使用底板上的SW1按键模拟实际使用。按键每按一次,对应的LED灯反转一次。即检测按键是否有闭合和断开的过程,如果有,第一次则LED灯点亮,第二次,则LED灯熄灭。
由于按键滤波是比较比较通用的一个程序,因此我们可以把一个通用的程序设置为一个模块,方便后面重复使用。
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);
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 |
|
以上代码中,首先把系统时钟做分频,产生10ms 的分配时钟使能信号。在设计的状态机中,分4个状态
KEY_S0:判断按键是否按下,如果是,转移到状态KEY_S1;
KEY_S1:10ms后再次判断按键是否按下,如果是,转移状态到KEY_S2,否则继续回到KEY_S0;
KEY_S2:判断按键是否抬起,如果是,转移状态到KEY_S3
KEY_S1:10ms后再次判断按键是否抬起,如果是,转移状态到KEY_S0,否则继续回到KEY_S2;
当状态从KEY_S1 转到KEY_S2代表依次按钮按下key_cap输出一次高电平。
以下代码中调用了key模块,并且每次key_cap有效,都会翻转一次LED的输出。
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; (*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) ) key0 ( .clk_i(clk_i), .key_i(key_i), .key_cap(key_cap) );
endmodule |
Setp1 :新建仿真文件,仿真文件源码如下所示。
`timescale 1ns / 1ps
// Company: // Engineer: // // Create Date: 17:05:52 08/01/2015 // Design Name: Key_Jitter // Module Name: // Project Name: Key_Jitter // Target Device: // Tool versions: // Description: // // Verilog Test Fixture created by ISE for module: Key_Jitter // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: //
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 |
Setp2:进入仿真界面:SIMULATION->单击 Run Simulation ->单击Run Behavioral Simulation。
Setp3:设置断点
之后再点击下图箭头所指
之后可以看到增加的内部信号,读者可以以这种方法去观察内部信号
右击框选的需要增加观察的信号选择添加到波形窗口,并且取消断点
Setp3:复位仿真波形
Setp4:重新仿真时间为1000ms
Setp5:观察仿真波形
Setp6:放大波形观察毛刺
很多时候软件仿真后的代码也不一定完全执行正确,这个时候我们可以通过XILINX 自带的在线逻辑分析,在板子上运行并且查看关键信号。
Setp1:将(*mark_debug = "true"*) 添加到需要观察的信号前面。
(*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 ;
(*mark_debug = "true"*) reg [3:0] led_o;
(*mark_debug = "true"*) wire key_cap;
Setp2:为了观察到信号,先点击Run Synthesis
Setp3:单击Set Up Debug 设置需要观察的信号
一下是我们要观察的信号
以下是这只在线逻辑分析仪的采样深度,使用的是FPGA的 BRAM,以及设置Captrue control,对于这种超慢信号,XILINX 的在线逻辑分析低于20M采样速度的,波形窗口就不会显示波形,这个XILINX也没有特别说明过,但是通过设置Captrue control,可以用我们这里的en_10ms来作为扑捉控制,而采样时钟依然用系统时钟。
单击Finish后会出来下面的原理图设计,可以看到FPGA编程的本质还是回归电路设计。现在我们使用代码去设计电路。记得保存,否则无法观察到调试信号。下面的小蚂蚁,就是已经添加调试标记的信号。
Setp4:编译程序
Setp5:下载程序
Setp6:设置触发,以及设置Capture 信号
Captrue mode 一定要设置为BASIC
Window data depth 为采样深度设置为2048最大
Trigger position inwindow 设置为1024
以上参数都可以根据需要用户自行设置
以信号en_10ms作为Capture信号
以信号key_cap 为触发信号
Setp7:启动采集并且观察
按下按键,可以连续多次按下按键,当所有信号触发完成后入下图,可以看到正确观察到了按键程序的状态机信号以及LED等其他信号的输出。
将程序下载。按键SW1每按一次,LED灯很好地熄灭和点亮。LED灯响应无差错。为清晰的表示消抖的效果,可将延时参数设置很小,可以发现,按键有时候明明已经按下去了,LED却无响应。