安德鲁

[笔记].独立按键消抖的改进.[Verilog]

0
阅读(12145)

引子

先前的[笔 记].一种独立键盘消抖的Verilog写法.[Verilog]是针对4个按键写的。今天我略为改动下,改成参数化,已验证,非常好用。

 

代码

key_debounce.v
01 module key_debounce
02 #(parameter KEY_WIDTH = 4)
03 (
04   input                    i_clk,
05   input                    i_rst_n,
06   input      [KEY_WIDTH:1] i_key,       // 按下为0,松开为1
07   output reg [KEY_WIDTH:1] o_key_val    // 键值
08 ); 
09  
10 //++++++++++++++++++++++++++++++++++++++
11 reg [KEY_WIDTH:1] key_samp1, key_samp1_locked;
12  
13 // 将i_key采集至key_samp1
14 always @ (posedge i_clk, negedge i_rst_n)
15   if(!i_rst_n)
16     key_samp1 <= {KEY_WIDTH{1'b1}};
17   else        
18     key_samp1 <= i_key;
19  
20 // 将key_samp1锁存至key_samp1_locked
21 always @ (posedge i_clk, negedge i_rst_n)
22   if(!i_rst_n)
23     key_samp1_locked <= {KEY_WIDTH{1'b1}};
24   else        
25     key_samp1_locked <= key_samp1;
26 //--------------------------------------
27  
28 //++++++++++++++++++++++++++++++++++++++
29 wire [KEY_WIDTH:1] key_changed1;
30  
31 // 当key_samp1由1变为0时
32 // key_changed1由0变为1,只维持一个时钟周期
33 assign key_changed1 = key_samp1_locked & (~key_samp1);
34 //--------------------------------------
35  
36  
37 //++++++++++++++++++++++++++++++++++++++
38 reg [19:0] cnt;
39  
40 // 一旦有按键按下,cnt立即被清零
41 always @ (posedge i_clk, negedge i_rst_n)
42   if(!i_rst_n)
43     cnt <= 20'h0;
44   else if(key_changed1)
45     cnt <= 20'h0;
46   else
47     cnt <= cnt + 1'b1;
48 //--------------------------------------
49  
50  
51 //++++++++++++++++++++++++++++++++++++++
52 reg [KEY_WIDTH:1] key_samp2, key_samp2_locked;
53  
54 // 只有当按键不变化(不抖动),且维持20ms以上时
55 // 才将i_key采集至key_samp2
56 always @ (posedge i_clk, negedge i_rst_n)
57   if(!i_rst_n)
58     key_samp2 <= {KEY_WIDTH{1'b1}};
59   else if(cnt == 20'hF_FFFF)            // 0xFFFFF/50M = 20.9715ms
60     key_samp2 <= i_key;
61  
62 // 将key_samp2锁存至key_samp2_locked
63 always @ (posedge i_clk, negedge i_rst_n)
64   if(!i_rst_n)
65     key_samp2_locked <= {KEY_WIDTH{1'b1}};
66   else
67     key_samp2_locked <= key_samp2;
68 //--------------------------------------
69  
70 //++++++++++++++++++++++++++++++++++++++
71 wire [KEY_WIDTH:1] key_changed2;
72  
73 // 当key_samp2由1变为0时
74 // key_changed2由0变为1,只维持一个时钟周期
75 assign key_changed2 = key_samp2_locked & (~key_samp2);
76 //--------------------------------------
77  
78  
79 //++++++++++++++++++++++++++++++++++++++
80 // 每次按键稳定后,输出键值
81 // 按下为0,松开为1
82 always @ (posedge i_clk, negedge i_rst_n)
83   if(!i_rst_n)
84     o_key_val <= {KEY_WIDTH{1'b1}};
85   else
86     o_key_val <= ~key_changed2;
87 //--------------------------------------
88  
89 endmodule

解析

关键是如何正确使用全局参数。第2行,在module名和moudule的I/O中间声明一些参量;同声明moudule的I/O一样,声明多个参 量,使用逗号隔开;注意小括号末尾无需分号。第16行及以下类似行,先前是key_samp1 <= 4'hF,现在怎么写呢? 复制KEY_WIDTH个1'b1即可:key_samp1_locked <= {KEY_WIDTH{1'b1}}。

 

参考

1 Quartus II->Edit->Insert Template..