重拾FPGA-单按键(按键消抖)

前言

  1、只是简单的单按键检测功能;未上板仿真,学习笔记。

  2、按键抖动20ms;

  3、消抖,直接是每当检测到下降沿,就计时20ms,若20ms结束后,输入依然为低电平,就认为是一次有效的按下动作;后面改为:每当下降沿时,开始计数,计数未满来了上升沿,状态回到【检测按下】,直到一次数值记满。

准备工作:

  1、状态机

  2、计数值

 

 

 

  3、模块

 

 

   4、代码

  a、计数器

 1 `timescale 1ns/10ps
 2 module JiShuQi_module(
 3     clk,
 4     rst_n,
 5     KaiShi,
 6     JieShu
 7 );
 8     input clk;
 9     input rst_n;
10     input KaiShi;
11     output reg JieShu;
12     
13     parameter  JiShuZhi = 20'd200;        //计数值
14     
15     reg JiShu_ZhuangTai;
16     reg [19:0]JiShuQi;
17     wire JiMan;                    //计数器记满
18     
19     always@(posedge clk or negedge rst_n)
20         if(!rst_n)
21         #1    JiShu_ZhuangTai <= 1'b0;
22         else if(KaiShi)
23         #1    JiShu_ZhuangTai <= 1'b1;
24         else if(JiMan)
25         #1    JiShu_ZhuangTai <= 1'b0;
26         else
27         #1    JiShu_ZhuangTai <= JiShu_ZhuangTai;
28     //计数器计数
29     always@(posedge clk or negedge rst_n)
30         if(!rst_n)
31         #1    JiShuQi <= 20'd0;
32         else if(JiMan)
33         #1    JiShuQi <= 20'd0;
34         else if(JiShu_ZhuangTai)
35         #1    JiShuQi <= JiShuQi + 1'b1;
36         else
37         #1    JiShuQi <= 20'd0;
38     //
39     assign JiMan = (JiShuQi == JiShuZhi)?1'b1:1'b0;
40     //
41     always@(posedge clk or negedge rst_n)
42         if(!rst_n)
43         #1    JieShu <= 1'b0;
44         else if(JiMan)
45         #1    JieShu <= 1'b1;
46         else
47         #1    JieShu <= 1'b0;
48 endmodule

   b、按键检测模块

  1 `timescale 1ns/10ps
  2 module DanAnJianJianCe_module(
  3     clk,
  4     rst_n,
  5     JianCe_En,
  6     AnJian_ShuRu,
  7     AnJian_YouXiao,
  8     AnJian_ZhuangTai
  9 );
 10     input clk;
 11     input rst_n;
 12     input JianCe_En;                    //按键检测开关 可控制,上级系统可给一个持续的信号
 13     input AnJian_ShuRu;                //物理接口
 14     output reg AnJian_YouXiao;        //按键按下有效 与按下持续时间无关,一次动作只给一个有效
 15     output  AnJian_ZhuangTai;        //按下时为1,松开为0
 16     //
 17     reg KaiShi;
 18     wire JieShu;
 19     //
 20     reg AnJian_ShuRu_JiCun_a;        //按键输入信号同步
 21     reg AnJian_ShuRu_JiCun_b;        //按键输入信号同步
 22     wire AnJian_AnXia;                //按键按下有效
 23     wire AnJian_SongKai;                //按键松开
 24     //
 25     reg [3:0]NS;
 26     reg [3:0]CS;
 27     localparam
 28         KongXian                    =    4'b0000,
 29         JianCe_AnXia            =    4'b0001,
 30         AnXia_XiaoDou            =    4'b0010,
 31         JianCe_SongKai            =    4'b0100,
 32         SongKai_XiaoDou        =    4'b1000;
 33     
 34     //按键同步及状态检测
 35     always@(posedge clk or negedge rst_n)
 36         if(!rst_n)begin
 37         #1    AnJian_ShuRu_JiCun_a <= 1'b0;
 38         #1    AnJian_ShuRu_JiCun_b <= 1'b0;
 39         end
 40         else begin
 41         #1    AnJian_ShuRu_JiCun_a <= AnJian_ShuRu;
 42             AnJian_ShuRu_JiCun_b <= AnJian_ShuRu_JiCun_a;
 43         end
 44     assign AnJian_AnXia        = (!AnJian_ShuRu_JiCun_a & AnJian_ShuRu_JiCun_b)?1'b1:1'b0;
 45     assign AnJian_SongKai    = (AnJian_ShuRu_JiCun_a & !AnJian_ShuRu_JiCun_b)?1'b1:1'b0;
 46     
 47 
 48     //状态机1
 49     always@(posedge clk or negedge rst_n)
 50         if(!rst_n)
 51         #1    CS <= KongXian;
 52         else
 53         #1    CS <= NS;
 54     //状态机2
 55     always@(CS,JianCe_En,AnJian_AnXia,AnJian_SongKai,JieShu,AnJian_ShuRu_JiCun_b)begin
 56         NS = 4'bxxxx;
 57         case(CS)
 58             KongXian                :begin 
 59                 if(JianCe_En)
 60                     NS = JianCe_AnXia;
 61                 else
 62                     NS = KongXian;
 63             end
 64             JianCe_AnXia        :begin 
 65                 if(AnJian_AnXia)
 66                     NS = AnXia_XiaoDou;
 67                 else
 68                     NS = JianCe_AnXia;
 69             end
 70             AnXia_XiaoDou        :begin 
 71                 if(JieShu)begin
 72                     if(!AnJian_ShuRu_JiCun_b)
 73                         NS = JianCe_SongKai;
 74                     else
 75                         NS = JianCe_AnXia;
 76                 end
 77                 else
 78                     NS = AnXia_XiaoDou;
 79             end
 80             JianCe_SongKai        :begin 
 81                 if(AnJian_SongKai)
 82                     NS = SongKai_XiaoDou;
 83                 else
 84                     NS = JianCe_SongKai;
 85             end
 86             SongKai_XiaoDou    :begin
 87                 if(JieShu)begin
 88                     if(AnJian_ShuRu_JiCun_b)
 89                         NS = KongXian;
 90                     else
 91                         NS = JianCe_SongKai;
 92                 end
 93                 else
 94                     NS = SongKai_XiaoDou;
 95             end
 96             default:NS = KongXian;
 97         endcase
 98     end
 99     //状态机3
100     always@(posedge clk or negedge rst_n)
101         if(!rst_n)begin
102         #1    AnJian_YouXiao <= 1'b0;
103         #1    KaiShi <= 1'b0;
104         end
105         else begin
106             case(CS)
107                 KongXian            :;
108                 JianCe_AnXia    :
109                     if(AnJian_AnXia) 
110                     #1    KaiShi <= 1'b1;
111                 AnXia_XiaoDou    :begin 
112                 #1    KaiShi <= 1'b0;
113                     if(JieShu && !AnJian_ShuRu_JiCun_b) 
114                     #1    AnJian_YouXiao <= 1'b1;
115                 end
116                 JianCe_SongKai    :begin
117                 #1    AnJian_YouXiao <= 1'b0;
118                     if(AnJian_SongKai)
119                     #1    KaiShi <= 1'b1;
120                 end
121                 SongKai_XiaoDou:
122                 #1    KaiShi <= 1'b0;
123                 default : begin 
124                 #1    KaiShi <= 1'b0;
125                 #1    AnJian_YouXiao <= 1'b0;
126                 end
127             endcase
128         end
129     assign AnJian_ZhuangTai = ~AnJian_ShuRu_JiCun_b;
130 JiShuQi_module JiShuQi(
131     .clk(clk),
132     .rst_n(rst_n),
133     .KaiShi(KaiShi),
134     .JieShu(JieShu)
135 );
136 endmodule

 

        c、顶层模块

 1 `timescale 1ns/10ps
 2 module top_module(
 3     clk,
 4     rst_n,
 5     AnJian_ShuRu
 6 );
 7     input clk;
 8     input rst_n;
 9     input AnJian_ShuRu;                //物理接口
10 
11 DanAnJianJianCe_module tt( 
12     .clk(clk),
13     .rst_n(rst_n),
14     .JianCe_En(1'b1),
15     .AnJian_ShuRu(AnJian_ShuRu),
16     .AnJian_YouXiao(),
17     .AnJian_ZhuangTai()
18 );
19 endmodule

   d、仿真

 1 `timescale 1ns/10ps
 2 `define clk_period 20
 3 
 4 module top_module_tb(
 5 );
 6     reg clk;
 7     reg rst_n;
 8     reg AnJian_ShuRu;
 9     
10     initial clk  = 0;
11     always#(`clk_period/2) clk  = ~clk;
12     
13     initial begin
14         rst_n = 0;
15         AnJian_ShuRu = 1;
16         #(`clk_period*5);
17         rst_n = 1;
18         #(`clk_period*5);
19         DouDong;    
20     end
21     
22     reg [15:0]randnum;
23     task DouDong;begin
24         repeat(30)begin
25             randnum = {$random}%200;
26             #randnum AnJian_ShuRu = ~AnJian_ShuRu;
27         end    
28         #(`clk_period*5);
29         AnJian_ShuRu = 0;
30         #(`clk_period*100);
31         
32         repeat(30)begin
33             randnum = {$random}%200;
34             #randnum AnJian_ShuRu = ~AnJian_ShuRu;
35         end
36         #(`clk_period*5);
37         AnJian_ShuRu = 1;
38         #(`clk_period*100);
39         $stop;
40         end
41     endtask
42     
43 top_module top_module(
44     .clk(clk),
45     .rst_n(rst_n),
46     .AnJian_ShuRu(AnJian_ShuRu)
47 );
48 endmodule

仿真图

 状态机

 

 

  

posted @ 2021-07-28 20:40  王小虎8821  阅读(326)  评论(0)    收藏  举报