正点原子视频学习笔记—Verilog下按键消抖, 实现LED灯的点亮和熄灭
在学习FPGA的基础阶段会有按键控制LED灯亮灭的实验,其中避免不了要对按键进行消抖处理,以及LED的控制模块,和顶层例化模块。本文包括详细的源代码和注释。
1.按键消抖部分的代码如下所示:
//key_debounce
module
key_d(
input clk
,
input rst_n
,
input key
,
output key_value
,
output key_flag
);
reg key_reg
;
reg
[19:0] cnt
;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n
)
begin
key_reg
<=1'b1
;
cnt
<=20'd0
;
end
else
begin
key_reg
<=key
;
if(key_reg
!=key
)
cnt
<=20'd1000_000
;
else
begin
if(cnt
>20'd0
)
cnt
<=cnt
-1,b1
;
else
cnt
<=20'd0’
;
end
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n
)
begin
key_value
<=1'b1
;
key_flag
<=1'b0
;
end
else
begin
if(cnt
==20'd1
)
begin
key_value
<=key
;
key_flag
<=1'b1
;
end
else
begin
key_value
<=key_value
;
key_flag
<=1'b0
;
end
end
end
endmodule
主要思路:
第一个always块: 1.复位状态下,计数器cnt初值为0,键值中间寄存器key_reg为1(按键未按下); 2.非复位状态下,将按键的值key赋给key_reg,并在下一时刻检验二者是否还相等。如果不相等,给计数器赋最大值1000_000,准备倒计时;如果相等,计数器的值开始由1000_000做减一操作,直到计数器倒计时到0。此时的键值已是消抖完毕后稳定的键值。
第二个always块: 1.复位状态下,消抖完毕的键值接收变量key_value为1,按键标志位key_flag为0; 2.非复位状态下,如果cnt=1,说明计数器的值已经由1000_000倒计时到1,即按键消抖完毕,此时将稳定的键值key赋给key_value,按键消抖标志位key_flag置1;如果cnt的值不等于1,说明倒计时还未结束,消抖还未完毕,key_value、key_flag保持原来的值。
关于cnt最大值得解释: 我们知道,现在市场上出售的机械按键,抖动的时间一般不超过20ms,对于50Mhz晶振而言,一个周期为1/50M等于20ns,所以要想实现20ms的计数,需要1000_000次计数周期。简单点说,对于50Mhz的晶振而言,计1000_000个数的时间为20ms,所以cnt的最大值为1000_000。
2.LED灯控制模块程序如下所示:
//LED
module
led_c(
input clk
,
input rst_n
,
output key_value
,
output key_flag
,
output led
);
always@(posedge clk or negedge rst_n)
begin
if(!rst_n
)
led
<=1'b1
;
else if((key_value
==1'b0
)&&key_flag
)
led
=~led
;
end
endmodule
对于语句
else if((key_value
==1'b0
)&&key_flag
)
led
=~led
;
做以下解释: 1.按键按下和松开的时候都会产生一个flag,按下稳定后key_value为0,松开稳定后key_value为1,(没有按下的时候按键值为1),而是否稳定的条件就是flag是否为1,所以flag为1且key_value为0,两个条件缺一不可。 2.key_value=0的原因:在上一个按键消抖模块中,将稳定后的键值key赋给了key_value,所以要想让key_value等于0,key就必须为0,key为0的条件就是按键按下,而key_value=key又是在按键按下并且键值稳定后才开始执行的,所以key_value=0代表的条件就是,按键key按下并且键值稳定后。
3.例化模块程序如下所示:
//top_k_l
module
top_k_l(
input clk
,
input rst_n
,
input key
,
output led
);
wire key_value
;
wire key_flag
;
key_d
u_key_d(
.key (key
),
.clk (clk
),
.rst_n (rst_n
),
.key_value (key_value
),
.key_flag (key_flag
)
);
led_c
u_led_c(
.key_value (key_value
),
.key_flag (key_flag
),
.clk (clk
),
.rst_n (rst_n
),
.led (led
)
);
endmodule
本次实验笔记到此结束。