米联客 ZYNQ/SOC精品教程 S01-CH06 FPGA按钮去抖实验

5 篇文章 11 订阅
3 篇文章 0 订阅

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

6.1 概述

按键的消抖,是指按键在闭合或松开的瞬间伴随着一连串的抖动,这样的抖动将直接影响设计系统的稳定性,降低响应灵敏度。因此,必须对抖动进行处理,即消除抖动的影响。实际工程中,有很多消抖方案,如RS触发器消抖,电容充放电消抖,软件消抖。本章利用FPGA内部来设计消抖,即采取软件消抖。

按键的机械特性,决定着按键的抖动时间,一般抖动时间在5ms~10ms。消抖,也意味着,每次在按键闭合或松开期间,跳过这段抖动时间,再检测按键的状态。只要通过简单的延时就可实现按键的消抖动。

6.2 使用硬件

开发板底板中配套4个独立按键与FPGA相连,具体请参见底板原理图。本章使用了开发板按键和led。各个按键独立,消抖过程相同,因此使用底板上的SW1按键模拟实际使用。按键每按一次,对应的LED灯反转一次。即检测按键是否有闭合和断开的过程,如果有,第一次则LED灯点亮,第二次,则LED灯熄灭。

6.3 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);

 

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输出一次高电平。

6.4 调用key模块

以下代码中调用了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

6.5 综合布线前仿真时序

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:放大波形观察毛刺

6.6 Chipscope在线逻辑分析仪仿真

很多时候软件仿真后的代码也不一定完全执行正确,这个时候我们可以通过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等其他信号的输出。

6.7 输出结果

将程序下载。按键SW1每按一次,LED灯很好地熄灭和点亮。LED灯响应无差错。为清晰的表示消抖的效果,可将延时参数设置很小,可以发现,按键有时候明明已经按下去了,LED却无响应。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值