zoukankan      html  css  js  c++  java
  • 04 初探按键消抖与仿真模型

    我是先把计数器拆分:加法和减法计数器。

    先做加法计数器,再把加法计数器拆成按键控制和led控制部分,在本子上写下他们的大致原理再,写下他们的输入输出端口模块,最终按照模块端口和工作原理及各小功能模块,照图施工就行。

    总体——拆分——各模块(仿真验证)(对于一个模块先写模块的端口,和它的工作原理,大概由那几个部分构成,及各部分的联系)

    一 设计定义

    第一部分设计功能:实现按键的按下是真正的按下,滤除掉机械抖动。(原因是按键动作会有一段稳定的状态,而机械抖动会给出错误的电平信号且不稳定)

    第二部分设计原理:按键按下可以分为,下降沿和上升沿。而完整的按键按下与释放,由四个状态组成,分别是空闲状态,按下滤波状态(下降沿),按下稳定状态(低电平),按键释放滤波状态(上升沿)。状态如下图:

    通过上面对按键按下与释放的过程,分析设计方法可以为状态机,各个状态转移的关系。如下图:状态触发条件----从抖动到稳定需要10ms的延时,才能进入下一个状态。

     

    总结:按键按下与释放,首先得把按键分为下降沿和上升沿,下降沿与上升沿都得维持20ms/10ms, 才能看作真正的按下与释放。否则为抖动。

    二  设计输入

    整体模块框图及设计代码:

     

    module key_filter

    (

        clk,

        rst_n,

        key_in,

        pin_out

    );

        input clk;

        input rst_n;

        input key_in;            //

        output pin_out;          //the output of key,when the key_in==1(means press)

        //the output of key,when the key_in==0(means release)

    //此处省略下面的边沿检测和状态机部分

    endmodule

    按键消抖设计,分为两部分,一是按键边沿检测模块(下降沿和上升沿),二是状态机模块实现整个按下与释放过程。

    第一部分边沿检测:边沿检测就是检测按键的下降沿和上升沿,而实现按键的按下与释放的原理:使用两级D触发器,记忆按键当前状态的电平值和上一个状态的电平值,通过比较这两个状态的电平,就能判断下降沿和上升沿。电路结构图如下图:

     

    第二部分边沿检测代码:

    reg H2L_F1;                 //first reg(store the value of key from 1 to 0,press)

        reg H2L_F2;

        reg L2H_F1;                 //first reg(store the value of key from 0 to 1,press)

        reg L2H_F2;  

        //the clasic edge detection(边沿检测)

        //注意小梅哥的边缘检测,优良的不同

    //他只用了两个寄存器,并且定义了按键的上升沿和下降沿(assign)

    //

    assign nedge=!H2L_F1 & H2L_F2

    assign podge= L2H_F1 & !L2H_F2

     

    always@(posedge clk or negedge rst_n)

        if(!rst_n)

           begin

               H2L_F1<=1'b1;

               H2L_F2<=1'b1;

              L2H_F1<=1'b0;

               L2H_F2<=1'b0;

            end

        else   begin

               H2L_F1<=key_in;

               H2L_F2<=H2L_F1;

              L2H_F1<=key_in;

               L2H_F2<=L2H_F1;

           end

    第二部分按键按下与释放状态:

    设计原理:照图施工,是按键按下与释放,就如设计定义的状态原理图和状态转移图所示。分为四个状态,未按下的空闲状态,按下的滤波状态,按下稳定状态,释放滤波状态。触发条件,分别是,下降沿到来,满足10ms的延迟,上升沿到来,满足10ms的延迟。思路如下面代码所示。

    //be careful the binary(二进制)

        localparam

           IDEL = 4'b0001,      //the idel state

           FILTER0 = 4'b0010,   //first filter(key from 1 to 0)

           DOWN = 4'b0100,      //when the key_in==0

           FILTER1 = 4'b1000;   //second filter(key from 0 to 1)

    parameter T10MS = 20'd500_000-1;

           reg [19:0]delay_cnt;

           reg [3:0]state;

           reg pin_out;

           //他把计数器的10MS单独写在一个模块

    //小梅哥滤波的原理:按键的下降沿与上升沿的间隔时间大于10MS

    //还有按键的输出信号,即表示按键按下或释放的信号,只有保持一个时钟周期

           always@(posedge clk or negedge rst_n)

           if(!rst_n)begin

           state<=IDEL;

           delay_cnt<=20'd0;

           pin_out<=1'b0;

           end

           else   begin

               case(state)

                  IDEL:begin

                      if(!H2L_F1 & H2L_F2)

                         state<=FILTER0;

                      else

                         state<=IDEL;

                  end

                  FILTER0:begin

                      if(key_in==1'b0)begin

                         if((delay_cnt==T10MS) )begin

                            state<=DOWN;

                             pin_out<=1'b1;

                             delay_cnt<=20'd0;

                         end

                         else

                         delay_cnt<=delay_cnt+1'b1;

                         end

                      else

                             state<=IDEL;

                  end

                  DOWN:begin

                      if(L2H_F1 & !L2H_F2)

                         state<=FILTER1;

                      else

                         state<=DOWN;

                  end

                  FILTER1:begin

                      if(key_in==1'b1)begin

                         if((delay_cnt==T10MS) )begin

                             state<=IDEL;

                             pin_out<=1'b0;

                             delay_cnt<=20'd0;

                         end

                         else

                         delay_cnt<=delay_cnt+1'b1;

                         end

                      else

                             state<=DOWN;

                      end

                 

                  default:state<=IDEL;

               endcase

              

           end

    三  仿真验证

    我对仿真的理解就是,给一个系统,加激励,然后观察输出的波形。作用有两个:一是验证设计是否实现功能。二是定位问题。

    仿真模型:我的理解就是在tb文件里产生时钟与复位信号,在仿真模型文件里产生(除时钟和复位信号的)其他激励如按键信号key,最终在tb文件调用仿真文件key_model即可。(类似与顶层模块与各个功能模块之间的调用)

     

    第一步部分 Task函数调用与随机函数的用法:

    抖动是人为的设计了一些固定值抖动,不具有随机性且编写出来的文件太长, 这里可以采用随机数发生函数来产生抖动

    Task函数格式:

    task press_key;
    begin

    //中间部分为仿真具体实现功能,自己设计
    end

    endtask

    //在仿真主程序中,直接调用Task函数名press_key;

    A:下面表格为仿真模型(key_model)的代码:

    注,这是单独的一个设计模块,类似于功能模块(部分)。

    //Task函数与随机函数

    reg [15:0]myrand;
    task press_key;
    begin
    repeat
    (50) begin //五十次随机时间按下抖动
    myrand = {$random}%65536;
    #
    myrand key_in = ~key_in;
    end
    key_in = 0;
    #
    50_000_000; //按下稳定
    repeat(50) begin //50 次随机时间释放抖动
    myrand = {$random}%65536;
    #
    myrand key_in = ~key_in;
    end
    key_in = 1;
    #
    50_000_000; //释放稳定
    end
    endtask

    B:下面表格为仿真顶层(key_ filter_tb)的代码:

    注:这个仿真设计相当于顶层,可以直接调用仿真模型。

    //仿真主程序调用Task函数

    initial begin
    Rst_n = 1'b0;

    key_in = 1'b1;
    #(`clk_period*10) Rst_n = 1'b1;
    #30000;
    press_key; #10000;
    press_key; #10000;
    press_key; #10000;
    $stop;
    end

    C: 收获有三:

    A写好一个部分的程序,其他的在此基础上复制修改(如把按键按下的写好,写按键释放时,复制一段只需要把按键的值改成(0-1即可))

    B 模拟真实仿真时,若时间较长可以把时钟信号删除掉,再

    进行仿真(缩小仿真时间)

    key_filter#(.T10MS(999))//表示仿真时间参数T10MS为计数到999,即1000个时钟周期,也就是20_000ns等效于10MS.

    C对于信号输入的值很多情况,最好调用一个随机函数$random。。且把仿真程序分成几个部分,在一个主要的仿真顶层程序直接调用。比如再key_filter_tb 仿真程序中调用key_model程序(类似于模块划分,设置顶层程序与子程序。)

    D学习语法可以看IEEE—2005语法标准

     

    从仿真波形看出,能够实现把小于十毫秒的抖动滤除,实现按键消抖。

    我学到了,边沿检测,仿真模型,随机函数等等。至此,一个按键消抖模块完成勒,很开心。

  • 相关阅读:
    swift 学习笔记
    collection view 开发笔记
    代码片段
    childViewController 小计
    iOS 二维码扫描
    statusbarhidden stuff 状态栏的各种特性
    AFNetworking 3.0 断点续传 使用记录
    scrollview 图片放大 捏合 瓦片地图 相关注意事项
    iOS 9 强制横屏
    简单的JS运动封装实例---侧栏分享到
  • 原文地址:https://www.cnblogs.com/Xwangzi66/p/12621999.html
Copyright © 2011-2022 走看看