parameter MAX_NUM = 9;
parameter CYCLE = 20;
always #(CYCLE/2) clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;//开始复位
#(CYCLE);
rst_n = 1'b1;//结束复位
key = 4'b1111;
#((MAX_NUM)\*CYCLE\*4);
key = 4'b1110;
#((MAX_NUM)\*CYCLE\*4);
key = 4'b1101;
#((MAX_NUM)\*CYCLE\*4);
key = 4'b1011;
#((MAX_NUM)\*CYCLE\*4);
key = 4'b0111;
#((MAX_NUM)\*CYCLE\*4);
$stop;
end
key_led #(.TIME0_2S(MAX_NUM)) u_key_led(
.clk (clk),
.rst_n (rst_n),
.key (key),
.led (led)
);
endmodule
### 3.按键消抖
#### 1.消抖原理
![在这里插入图片描述](https://img-blog.csdnimg.cn/052110df49f340e38c169ca219676c0c.png)
#### 2.系统框图
![在这里插入图片描述](https://img-blog.csdnimg.cn/6b0a1ebe6bdf459b9c5e9d28a54fe245.png)
#### 3.项目代码
//按键消抖
module key_debounce(
input clk ,
input rst_n ,
input wire [3:0] key_in,
output wire [3:0] key_out
);
parameter MAX20 = 20’d999_999;
wire nedge; //下降沿检测
reg [19:0] cnt_20ms; //20ms计数寄存器
reg start; //倒计时开始标志
reg [3:0] key_r0; //按键消抖寄存器0
reg [3:0] key_r1; //按键消抖寄存器1
reg [3:0] flag; //检测按钮
reg [3:0] key_on; //中间按键寄存器
//20ms计数器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_20ms <= 20’d0;
end
else if (nedge) begin
cnt_20ms <= MAX20;
end
else if (start) begin
if (cnt_20ms == 1’d0) begin
cnt_20ms <= 20’d0;
end
else begin
cnt_20ms <= cnt_20ms - 1’b1;
end
end
else begin
cnt_20ms <= cnt_20ms ;
end
end
//下降沿检测
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
key_r0 <= 4’b1111;
key_r1 <= 4’b1111;
end
else begin
key_r0 <= key_in;
key_r1 <= key_r0;
end
end
assign nedge = (key_r0[0]&&key_r1[0])||(key_r0[1]&&key_r1[1])||(key_r0[2]&&key_r1[2])||(key_r0[3]&&key_r1[3]);
//约束start
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
start <= 1’b0;
end
else if (nedge) begin
start <= 1’b1;
end
else if (cnt_20ms == 1’d0)