[笔记]再笔记--边干边学Verilog HDL --003
lab03 消抖模块之一
本实验是一个简单的按键消抖。主要由电平检测和10ms延时2个模块组成。
以前,知道按键要消抖,但一直没做过。究其原因,可能是觉得麻烦,效果不炫,悲哀。无论如何,“出来混,总要还的”。咋消抖呢?大大们说,先检测电平变化,再将确定的变化延时输出。说起来简单,其中还有些小九九:
1> 消的是什么抖?
首先,要搞清楚,“抖”(跳变)是从哪里来的,最开始,我们的常识:按下按键,电平就变了。假设是由高变低。事实上,在按下的过程中,由于,按键大多是机械结构,就会产生轻微的跳变,瞬间(us级)跳变n次。也就是说这个瞬间,电平不是那么“干净”,所以就有了消抖的需求:期颐得到“干净”、确定的电平。这要求真不高,只是,俺以前直接无视了。
2> 咋消?
接着上面的按键的动作说,既然电平瞬间就由高变为我们要的低,那么,消抖就要在这个瞬间完成。首先,要知道按键想得到一个什么样的电平,就需要检测电平,而前面说了,电平有段时间是抖动的,干脆从100us之后开始检测,这样就忽略了抖动,(至于这100us是咋来的,科学吗?不晓得,做实验测试,还OK)。检测电平之后,判断出是高变低还是低变高,这个判断有需要很短的时间(ns级),然后,就是稳定的电平了,至此,我们得到了电平的确切变化动作,再加上一个延时模块,包含判断电平变化的时间,也就是akuei2说的“过滤”。这里用的10ms,够吗,当然够,为啥是10ms,不晓得,不过同样,实验可以验证。
3> 设计思路
(1)一旦检测到按键按下(高电平到低电平变化),“电平检查模块”就会拉高H2L_sig电平,然后拉低。
(2)“10ms延迟模块”,检测到H2L_sig高电平,就会利用10ms过滤H2L_sig, 拉高输出。
(3)当按键释放,“电平检测模块”会拉高L2H_sig电平,然后拉低。
(4)“10ms延迟模块”检查到L2H_sig就会利用10ms过滤L2H_sig,然后拉低输出。
代码
detect_module.v
2 * File name: detect_mocule.v
3 *
4 */
5
6 module detect_module
7 (
8 clk, rst_n, pin_in, H2L_sig, L2H_sig
9 );
10
11 input clk;
12 input rst_n;
13 input pin_in;
14 output H2L_sig;
15 output L2H_sig;
16
17 parameter T100US = 13'd5000-1;
18
19 reg [12:0] count;
20 reg isEn;
21
22 always @(posedge clk or negedge rst_n)
23 if (!rst_n)
24 begin
25 count <= 13'd0;
26 isEn <= 1'b0;
27 end
28 else if (count == T100US)
29 isEn <= 1'b1;
30 else
31 count <= count + 1'b1;
32
33 reg H2L_F1;
34 reg H2L_F2;
35 reg L2H_F1;
36 reg L2H_F2;
37
38 always @(posedge clk or negedge rst_n)
39 if (!rst_n)
40 begin
41 H2L_F1 <= 1'b1;
42 H2L_F2 <= 1'b1;
43 L2H_F1 <= 1'b0;
44 L2H_F2 <= 1'b0;
45 end
46 else
47 begin
48 H2L_F1 <= pin_in;
49 H2L_F2 <= H2L_F1;
50 L2H_F1 <= pin_in;
51 L2H_F2 <= L2H_F1;
52 end
53
54 assign H2L_sig = isEn ? (H2L_F2 & !H2L_F1) : 1'b0;
55 assign L2H_sig = isEn ? (!L2H_F2 & L2H_F1) : 1'b0;
56
57 endmodule
58
这里isEn = 1寄存器是表示100us的延迟完成。电平检测模块的有效是发生在100us之后。
delay_module.v
2 * File name: delay_mocule.v
3 *
4 */
5
6 module delay_module
7 (
8 clk, rst_n, H2L_sig, L2H_sig, pin_out
9 );
10
11 input clk;
12 input rst_n;
13 input H2L_sig;
14 input L2H_sig;
15 output pin_out;
16
17 parameter T1MS = 16'd50_000 - 1;
18
19 reg [15:0] count;
20
21 always @(posedge clk or negedge rst_n)
22 if (!rst_n)
23 count <= 16'd0;
24 else if (isCount && count == T1MS)
25 count <= 16'd0;
26 else if (isCount)
27 count <= count + 1'b1;
28 else if (!isCount)
29 count <= 16'd0;
30
31 reg [3:0] count_ms;
32
33 always @(posedge clk or negedge rst_n)
34 if (!rst_n)
35 count_ms <= 4'd0;
36 else if (isCount && count == T1MS)
37 count_ms <= count_ms + 1'b1;
38 else if (!isCount)
39 count_ms <= 4'd0;
40
41 reg isCount;
42 reg rpin_out;
43 reg [1:0] i;
44
45 always @(posedge clk or negedge rst_n)
46 if (!rst_n)
47 begin
48 isCount <= 1'b0;
49 rpin_out <= 1'b0;
50 i <= 2'd0;
51 end
52 else
53 case (i)
54
55 2'd0:
56 if (H2L_sig) i <= 2'd1;
57 else if (L2H_sig) i <= 2'd2;
58
59 2'd1:
60 if (count_ms == 4'd10) begin
61 isCount <= 1'b0;
62 rpin_out <= 1'b1;
63 i <= 2'd0;
64 end
65 else
66 isCount <= 1'b1;
67
68 2'd2:
69 if (count_ms == 4'd10) begin
70 isCount <= 1'b0;
71 rpin_out <= 1'b0;
72 i <= 2'd0;
73 end
74 else
75 isCount <= 1'b1;
76
77 endcase
78
79 assign pin_out = rpin_out;
80
81 endmodule
82
这里isCount是定时器和计数器的使能。由其控制10ms延时的开始。
debounce_module.v
2 * File name: debounce_mocule.v
3 * Function: debounce module.
4 * ------------------------------
5 * Pins: KEY0-rst_n, KEY1-pin_in, LEDG8-pin_out
6 *
7 * Target board: DE2.
8 * Software: Quartus II 9.1 sp1
9 * ----------------------------
10 * yf.x
11 * 7-12-2011
12 *
13 */
14
15 module debounce_module
16 (
17 CLOCK_50, KEY, LEDG
18 );
19
20 input CLOCK_50;
21 input [1:0] KEY;
22 output [8:8] LEDG;
23
24 wire H2L_sig;
25 wire L2H_sig;
26
27 detect_module U1
28 (
29 .clk (CLOCK_50),
30 .rst_n (KEY[0]),
31 .pin_in (KEY[1]),
32 .H2L_sig (H2L_sig),
33 .L2H_sig (L2H_sig)
34 );
35
36 delay_module U2
37 (
38 .clk (CLOCK_50),
39 .rst_n (KEY[0]),
40 .H2L_sig (H2L_sig),
41 .L2H_sig (L2H_sig),
42 .pin_out (LEDG[8])
43 );
44
45 endmodule
46
47
RTL图
小结
本实验的目的是体验“低级建模”里的单模块单功能的建模准则。直观,方便人读。