[笔记].独立按键消抖的改进.[Verilog]
0赞
发表于 2010/6/25 14:19:55
阅读(12032)
引子
先前的[笔 记].一种独立键盘消抖的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..