按键消抖 verilog FPGA 基础练习5
发现问题,用技术解决问题。兴趣是自己的源动力 !
目录
- 按键消抖 verilog FPGA 基础练习5
- 前言
- 一、消抖
- 1.1 消抖问题
- 1.1.1 功能代码
- 1.1.2 tb仿真代码
- 1.1.3 仿真结果
- 总结
前言
按键消的的练习主要是对计数器使用的一个巩固,核心就是任何一个需要使用计数器的地方,先建立一个always语句去计数,然后根据条件去判断什么时候清零,什么时候保持等等功能。消抖功能的实现,消抖的本质就是通过计数器的计数来避免前抖和后抖,核心方法就是只要有高电平,计数器就清零
一、消抖
注意理解下面两句话,就可以处理任何消抖了
- 消抖的本质就是通过计数器的计数来避免前抖和后抖:
- 核心方法就是只要有高电平,计数器就清零
1.1 消抖问题
设定抖动参数为10个clk 后抖也是10个clk,稳定时间为50clk
1.1.1 功能代码
module key_filter
#(
parameter CNT_MAX = 20'd999_999 //计数器计数最大值
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire key_in , //按键输入信号
output reg key_flag //key_flag为1时表示消抖后检测到按键被按下
//key_flag为0时表示没有检测到按键被按下
);
//************************************************
// 消抖的本质就是通过计数器的计数来避免前抖和后抖:
// 核心方法就是只要有高电平,计数器就清零
//************************************************
// 计数器计数,CNT_MAX 决定按键抖动的容忍时间
reg [19:0] cnt_filter;
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
cnt_filter <= 20'b0 ;
else if(key_in == 1'b1) // 确定计数器归零条件
cnt_filter <= 20'b0 ;
else if(key_in == 1'b0 & (cnt_filter == CNT_MAX)) // 确定保持条件
cnt_filter <= cnt_filter;
else
cnt_filter <= cnt_filter + 1; // 确定递增条件。这里考虑计数器在下一个按键来之前需要保持,否则会一直计数
end
// 拉高flag
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
key_flag <= 1'b0 ;
else if(cnt_filter == CNT_MAX - 1'b1) // 确定拉高条件,这里使用CNT_MAX - 1'b1表示只拉高一个周期
key_flag <= 1'b1 ;
else
key_flag <= 1'b0 ;
end
endmodule
1.1.2 tb仿真代码
`timescale 1ns/1ns
module tb_top;
reg sys_clk;
reg sys_rst_n;
reg [19:0] cnt_sim;
reg key_in;
wire key_flag;
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
#50;
sys_rst_n = 1'b1;
end
always #10 sys_clk = ~sys_clk;
// 设定抖动参数为10个clk 后抖也是10个clk,稳定时间为50clk,则可以用计数器来模拟
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
cnt_sim <= 8'b0;
else if(cnt_sim == 20'd70 -1'b1) //设置计数器清零
cnt_sim <= 8'b0;
else
cnt_sim <= cnt_sim + 1'b1;
end
// 只要是要依据计数器来操作的,就先给单独给一个计数器来计数,然后依据这个计数器来判定动作
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
key_in <= 1'b0;
// 前后10clk 来随机一个key_in
else if(cnt_sim <= 20'd10 | cnt_sim >=20'd60)
key_in <= ($random) % 2;
else
key_in <= 1'b0;
end
key_filter
#(
.CNT_MAX(20'd20) //计数器计数最大值
)
u0_key_filter
(
.sys_clk (sys_clk ), //系统时钟50MHz
.sys_rst_n (sys_rst_n ), //全局复位
.key_in (key_in ), //按键输入信号
.key_flag (key_flag ) //key_flag为1时表示消抖后检测到按键被按下
//key_flag为0时表示没有检测到按键被按下
);
endmodule
1.1.3 仿真结果
图1 前抖
图2 后抖
总结
- 核心思想:很多功能的实现,都是需要一个计数器(计数器需要考虑递增条件、归零条件或者保持条件),然后通过对计数器值的判别,实现其特有的功能或者操作
- 知识点总结:
- 消抖的核心要点是什么?
- 计数器使用的核心是什么?
- 当一个功能需要使用计数器时?如何进行核计数器进行交互或者判决?
- 欢迎一起交流学习,如有错误之处,还请各位指正。
参考资料
[1] FPGA系列教学