• 按键消抖实验


    当按键被按下在到被释放,期间产生的输入信号会发生抖动,如果不进行消抖处理,直接使用可能就会误触发。

    按键消抖实验设计思路,当按键被按下,隔20ms取数据,也就是说20ms的前后各取一次数据进行边沿检测:

    (1)、需要一个计数器cnt,因为按键随时都可能会被按下,所以计数器需一直启动在计数,需一直在检测。

     1 always @(posedge clk or negedge rst_n)begin
     2     if(!rst_n)begin
     3         cnt <= 0;
     4     end
     5     else if(add_cnt)begin
     6         if(end_cnt)begin
     7             cnt <= 0;
     8         end
     9         else begin
    10             cnt <= cnt + 1;
    11         end
    12     end
    13 end
    14 
    15 assign add_cnt = 1;
    16 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en;

    (2)、需要一个边沿检测器,需要对输入pin 上的信号进行边沿检测,检测到下降沿之后,立刻马上将计数器cnt 清0 ,cnt从0开始计数,数到20ms 取一次数据

     1 always @(posedge clk or negedge rst_n)begin
     2     if(!rst_n)begin
     3         key_rst <= 1;
     4         key_rst_r <= 1;
     5     end
     6     else begin
     7         key_rst <= wr_en;
     8         key_rst_r <= key_rst;
     9     end
    10 end
    11 //当key_en = 1时,说明有检测到下降沿,但这个并不能当做一个真正有效的信号去启动cnt0,
    12 //在按键按下到释放期间可能会多次产生key_en = 1
    13 assign key_en = key_rst_r & (~key_rst); 
     1 //每隔20ms就取按键上的值    
     2 always @(posedge clk or negedge rst_n)begin
     3     if(!rst_n) begin
     4         pin_status <= 1;
     5     end
     6     else if(end_cnt) begin //隔20ms 取一次数据
     7         pin_status <= wr_en;
     8     end
     9 end
    10 
    11 always @(posedge clk or negedge rst_n)begin
    12     if(!rst_n)begin 
    13         pin_status_r <= 1;
    14     end
    15     else begin
    16         pin_status_r <= pin_status;
    17     end
    18 end
    19 
    20 //前20MS的值与后20MS的值
    21 assign pin_status_ctrl = pin_status_r & (~pin_status);//这个信号才比较稳定信号,可以当做启动计数器cnt0

    完整代码:该代码是基于spi flash 一个读ID操作

      1 module spi_flash(
      2                     clk,
      3                     rst_n,
      4                     wr_en,
      5                     spi_miso,
      6                     
      7                     spi_sclk,
      8                     spi_mosi,
      9                     spi_cs,
     10                     rec_buf
     11 );
     12 parameter         SCLK_CLK = 3'd04;
     13 parameter         T_20MS      = 20'd1_000_000;
     14 parameter        CMD_ID     = 8'h9f;
     15 
     16 input            clk        ;
     17 input            rst_n    ;
     18 input            wr_en    ;
     19 input            spi_miso;
     20 
     21 output            spi_sclk;
     22 output            spi_mosi;
     23 output            spi_cs    ;
     24 output[24-1:0]    rec_buf    ;
     25 
     26 wire             add_cnt0;
     27 wire            end_cnt0;
     28 wire             add_cnt1;
     29 wire            end_cnt1;
     30 wire             add_cnt/*synthesis keep=1*/;
     31 wire            end_cnt/*synthesis keep=1*/;
     32 wire             key_en/*synthesis keep=1*/;
     33 
     34 wire            key_h_2_l;
     35 wire              pin_status_ctrl/*synthesis keep=1*/;
     36 
     37 reg[3-1:0]        cnt0;
     38 reg[6-1:0]        cnt1;
     39 reg[20-1:0]     cnt/*synthesis preserve=1*/;
     40 reg             wr_vld;
     41 reg             key_rst;
     42 reg             key_rst_r;
     43 reg             pin_status;
     44 reg             pin_status_r;
     45 
     46 
     47 /************************************************/
     48 //按键消抖动
     49 always @(posedge clk or negedge rst_n)begin
     50     if(!rst_n)begin
     51         key_rst <= 1;
     52         key_rst_r <= 1;
     53     end
     54     else begin
     55         key_rst <= wr_en;
     56         key_rst_r <= key_rst;
     57     end
     58 end
     59 
     60 assign key_en = key_rst_r & (~key_rst);
     61 
     62 //每隔20ms就取按键上的值    
     63 always @(posedge clk or negedge rst_n)begin
     64     if(!rst_n) begin
     65         pin_status <= 1;
     66     end
     67     else if(end_cnt) begin
     68         pin_status <= wr_en;
     69     end
     70 end
     71 
     72 always @(posedge clk or negedge rst_n)begin
     73     if(!rst_n)begin 
     74         pin_status_r <= 1;
     75     end
     76     else begin
     77         pin_status_r <= pin_status;
     78     end
     79 end
     80 
     81 //前20MS的值与后20MS的值
     82 assign pin_status_ctrl = pin_status_r & (~pin_status);
     83 
     84 always @(posedge clk or negedge rst_n)begin
     85     if(!rst_n)begin
     86         cnt <= 0;
     87     end
     88     else if(add_cnt)begin
     89         if(end_cnt)begin
     90             cnt <= 0;
     91         end
     92         else begin
     93             cnt <= cnt + 1;
     94         end
     95     end
     96 end
     97 
     98 assign add_cnt = 1;
     99 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en;
    100 
    101 
    102 always @(posedge clk or negedge rst_n)begin
    103     if(!rst_n)begin
    104         wr_vld <= 0;
    105     end
    106     else if(pin_status_ctrl)begin
    107         wr_vld <= 1;
    108     end
    109     else if(end_cnt1)begin
    110         wr_vld <= 0;
    111     end
    112 end
    113 
    114 always @(posedge clk or negedge rst_n)begin
    115     if(!rst_n)begin
    116         cnt0 <= 0;
    117     end
    118     else if(add_cnt0)begin
    119         if(end_cnt0)begin
    120             cnt0 <= 0;
    121         end
    122         else begin
    123             cnt0 <= cnt0 + 1;
    124         end
    125     end
    126 end
    127 
    128 assign add_cnt0 = wr_vld;
    129 assign end_cnt0 = add_cnt0 && cnt0 == SCLK_CLK -1;
    130 
    131 always @(posedge clk or negedge rst_n)begin
    132     if(!rst_n)begin
    133         cnt1 <= 0;
    134     end
    135     else if(add_cnt1)begin
    136         if(end_cnt1)begin
    137             cnt1 <= 0;
    138         end
    139         else begin
    140             cnt1 <= cnt1 + 1;
    141         end
    142     end
    143 end
    144 
    145 assign add_cnt1 = end_cnt0;
    146 assign end_cnt1 = add_cnt1 && cnt1 == 33 -1;
    147 
    148 reg spi_sclk;
    149 always @(posedge clk or negedge rst_n)begin
    150     if(!rst_n)begin
    151         spi_sclk <= 1;
    152     end
    153     else if(end_cnt0 && cnt1 != 32)begin
    154         spi_sclk <= 0;
    155     end
    156     else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1))begin
    157         spi_sclk <= 1;
    158     end
    159 end
    160 
    161 reg spi_cs;
    162 always @(posedge clk or negedge rst_n)begin
    163     if(!rst_n)begin
    164         spi_cs <= 1;
    165     end
    166     else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1) && cnt1 == 0)begin
    167         spi_cs <= 0;
    168     end
    169     else if(end_cnt1)begin
    170         spi_cs <= 1;
    171     end
    172 end
    173 
    174 reg spi_mosi;
    175 always @(posedge clk or negedge rst_n)begin
    176     if(!rst_n)begin
    177         spi_mosi <= 1;
    178     end
    179     else if(end_cnt0 && cnt1 >= 0 && cnt1 < 8)begin
    180         spi_mosi <= CMD_ID[7-cnt1];
    181     end
    182 end
    183 
    184 reg[24-1:0] rec_buf_temp;
    185 always @(posedge clk or negedge rst_n)begin
    186     if(!rst_n)begin
    187         rec_buf_temp <= 0;
    188     end
    189     else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1)-1) && cnt1 >= 9 && cnt1 < 33)begin
    190         rec_buf_temp[32-cnt1] <= spi_miso;
    191     end
    192 end
    193 
    194 reg dout_vld;
    195 always @(posedge clk or negedge rst_n)begin
    196     if(!rst_n)begin
    197         dout_vld <= 0;
    198     end
    199     else begin
    200         dout_vld <= end_cnt1;
    201     end
    202 end
    203 
    204 reg[24-1:0] rec_buf;
    205 always @(posedge clk or negedge rst_n)begin
    206     if(!rst_n)begin
    207         rec_buf <= 0;
    208     end
    209     else if(end_cnt1)begin
    210         rec_buf <= rec_buf_temp;
    211     end
    212 end
    213 
    214 endmodule 
    View Code

    用quartus II 的SignalTab抓取的波形:

    如果pin_status_ctl 检测到多次,可以将间隔时间适当的加长点。一般的轻触按键20~50ms。

    触发条件可以多开几个窗口进行捕获观察 。

  • 相关阅读:
    UI和3D物体的堆叠响应
    UI中的事件系统EventSystem
    UI的管理
    学习笔记--2020年12月30日
    Java集合框架
    Java基本数据类型
    数据存储
    intent和手势探测
    即时消息Toast和对话框
    Android事件处理的三种方法
  • 原文地址:https://www.cnblogs.com/wen2376/p/16171571.html
Copyright © 2020-2023  润新知