lcytms 发表于 2016-11-4 16:50:31

FPGA初级课程第六讲 单独按键消抖

FPGA初级课程
第六讲 单独按键消抖

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:单独按键消抖。
本节课我先简要地介绍一下单独按键消抖的物理原理,然后进行单独按键消抖的架构设计和状态转移图设计,再实际演示一下单独按键消抖的建模与仿真,通过仿真查看单独按键消抖的效果。


lcytms 发表于 2016-11-4 16:52:52

打开《ZX_NO1.pdf》文件,我们看一下四个轻触开关按键的电路图。

lcytms 发表于 2016-11-4 16:58:14

我们打开《26至芯科技奋斗的小孩之altera 系列 第二十六篇 单独按键消抖.pdf》文件。

对于每一个的小实验,我们都可以把它看作是一个小项目,逐步的去分析,设计,调试,最后完成功能。
下面我们就开始我们的“小项目”。

项目名称:单独按键消抖
具体要求:消除按键按下以及抬起时所带来的抖动。
项目分析:
1. 按键电路

lcytms 发表于 2016-11-4 17:01:48

2. 抖动的产生
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。
因而在闭合及断开的瞬间均伴随有一连串的抖动。

3. 按键抖动带来的危害
键抖动会引起一次按键被误读多次。为确保CPU对键的一次闭合仅作一次处理,必须去除键抖动。
在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。

4. 抖动的一些参数
抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。
这是一个很重要的时间参数,在很多场合都要用到。
按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。

5. 解决办法
一是延时重采样;二是持续采样。
从理论上来说,延时(如10ms)重采样的准确率肯定低于持续采样。
笔者采用持续采样。


lcytms 发表于 2016-11-4 17:04:10

好,讲完单独按键消抖的物理原理,我们再回到系统设计上来。

架构图如下图所示。

key_n:带有抖动的低电平有效的按键输入(按键按下为低电平)
click_n:滤除抖动之后的低电平有效的按键波形

lcytms 发表于 2016-11-4 17:07:16

系统设计:
1. 工程的名称:key_filter
2. 状态转移图如下:

lcytms 发表于 2016-11-4 17:08:23

MASK_TIME : 按键持续保持的时间(笔者选择为10ms)

而我们的程序仅仅是做了一个单纯的10ms滤波,也就是要求按键按下、释放均需经过10ms持续保持时间再确认。

lcytms 发表于 2016-11-4 17:09:05

本帖最后由 lcytms 于 2016-11-4 17:14 编辑

下面我们进行建模和仿真。
新建工程文件夹key_filter。
先编写key_filter.v代码。
module key_filter (clk, rst_n, key_n, click_n);

        input clk, rst_n;
        input key_n;
       
        output reg click_n;
       
        parameter MASK_TIME = 500_000;        // 10ms/20ns = 500_000, for checking key hold time
       
        reg cnt;
        reg state;
       
        localparam        s0 = 1'b0,
                                        s1 = 1'b1;

        always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        cnt <= 0;
                                        click_n <= 1;
                                        state <= s0;
                                end
                        else
                                begin
                                        case (state)
                                        s0        :        begin
                                                                if (key_n)
                                                                        begin
                                                                                cnt <= 0;
                                                                                click_n <= 1;
                                                                                state <= s0;
                                                                        end
                                                                else
                                                                        begin
                                                                                if (cnt < MASK_TIME - 1)
                                                                                        begin
                                                                                                cnt <= cnt + 19'b1;
                                                                                                state <= s0;
                                                                                        end
                                                                                else
                                                                                        begin
                                                                                                cnt <= 0;
                                                                                                click_n <= 0;
                                                                                                state <= s1;
                                                                                        end
                                                                        end
                                                        end
                                                       
                                        s1        :        begin
                                                                if (!key_n)
                                                                        begin
                                                                                cnt <= 0;
                                                                                click_n <= 0;
                                                                                state <= s1;
                                                                        end
                                                                else
                                                                        begin
                                                                                if (cnt < MASK_TIME - 1)
                                                                                        begin
                                                                                                cnt <= cnt + 19'b1;
                                                                                                state <= s1;
                                                                                        end
                                                                                else
                                                                                        begin
                                                                                                cnt <= 0;
                                                                                                click_n <= 1;
                                                                                                state <= s0;
                                                                                        end
                                                                        end
                                                        end
                                       
                                        default        :        state <= s0;
                                       
                                        endcase               
                                end
                end

endmodule

lcytms 发表于 2016-11-4 17:17:44

本帖最后由 lcytms 于 2016-11-4 17:20 编辑

然后编写Testbench文件,新建key_filter_tb.v。

解析:
模仿按键抖动时,抖动的时间(低电平或者高电平的持续时间)一定不要超过,否则将会被认为按键按下或者抬起。
模仿按键真正按下或者真正抬起时,给予的时间一定要超过抖动(低电平或者高电平的持续时间)的时间。

`timescale 1ns/1ps

module key_filter_tb;

        reg clk, rst_n;
        reg key_n;
       
        wire click_n;

        key_filter #(.MASK_TIME(5))
                dut (.clk(clk), .rst_n(rst_n), .key_n(key_n), .click_n(click_n));

        initial
                begin
                        clk = 1;
                        rst_n = 0;
                        key_n = 1;
                        #200.1
                        rst_n = 1;
                       
                        #200
                        key_n = 0;
                        #10
                        key_n = 1;
                        #20
                        key_n = 0;
                        #80
                        key_n = 1;
                        #200
                        key_n = 0;
                        #400                        //key hold time is long enough
                        key_n = 1;
                        #10
                        key_n = 0;
                        #20
                        key_n = 1;
                        #80
                        key_n = 0;
                        #200
                        key_n = 1;
                        #200                        //key hold time is long enough
                       
                        #200 $stop;
                end
       
        always #10 clk = ~clk;

endmodule

lcytms 发表于 2016-11-4 17:22:05

设置仿真。

检查仿真结果。
可以看到本次设计成功地将按键按下以及抬起时的抖动滤除。

页: [1] 2
查看完整版本: FPGA初级课程第六讲 单独按键消抖