文章目录
- 按键控制led变化
- 一、简介
- 二、代码
- 三、仿真代码
- 四、仿真结果
- 五、总结
按键控制led变化
一、简介
使用按键控制开发板上一个led灯的亮灭,当按键按下的时候led灯就亮,当再一次按下按键的时候led就不亮了。由于按键存在抖动,按键松开的时候led灯就不亮,所以需要一个消抖模块对按键消抖
二、代码
module key_led (
input wire clk,
input wire rst_n,
input wire[3:0] key,
output reg[3:0] led
);
parameter TIME_0_2S = 10_000_000; //
reg[24:0] cnt_0_2S;
reg[1:0] state;
//=================0.2s计时====================//
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_0_2S<=24'd0;
end
else if(cnt_0_2S == TIME_0_2S - 1)begin
cnt_0_2S<=24'd0;
end
else begin
cnt_0_2S<=cnt_0_2S+1'b1;
end
end
//=================state=================//
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
state<=2'b00;
end
else if(cnt_0_2S == TIME_0_2S - 1) begin
state<=state+1'b1;
end
else begin
state<=state;
end
end
//================按键控制流水灯===============//
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led<=4'b0000;
end
else if(~key[0]) begin
case (state)
2'd0:led<=4'b0001;
2'd1:led<=4'b0010;
2'd2:led<=4'b0100;
2'd3:led<=4'b1000;
endcase
end
else if(~key[1]) begin
case (state)
2'd0:led<=4'b1000;
2'd1:led<=4'b0100;
2'd2:led<=4'b0010;
2'd3:led<=4'b0001;
endcase
end
else if(~key[2]) begin
case (state)
2'd0:led<=4'b1111;
2'd1:led<=4'b0000;
2'd2:led<=4'b1111;
2'd3:led<=4'b0000;
endcase
end
else if(~key[3]) begin
case (state)
2'd0:led<=4'b1111;
2'd1:led<=4'b1111;
2'd2:led<=4'b1111;
2'd3:led<=4'b1111;
endcase
end
else begin
led<=4'b0000;
end
end
endmodule
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : 辣子鸡味的句橘子,331197689@qq.com
// File : key_debounce.v
// Create : 2023-07-14 10:36:44
// Revise : 2023-07-14 10:36:44
// Editor : sublime text4, tab size (4)
// -----------------------------------------------------------------------------
module key_debounce(
input wire clk,
input wire rst_n,
input wire[3:0] key_in,//四个按键信号输入
output reg[3:0] key_out//四个按键信号消抖输出
);
parameter TIME_20MS = 1000_000;
reg[19:0] cnt;//20ms计数器
wire add_cnt;//计数开始
wire ent_cnt;//计数终止
wire nedge;//下降沿检测
reg[3:0] key_in_r0;//同步key_in输入信号
reg[3:0] key_in_r1;//延迟一个周期
reg[3:0] key_in_r2;//延迟两个周期
reg flag;//消抖开始标志信号
//计数器模块,当addent满足时开始计数,检测到下降沿重新计数,end_ent满足时停止计数,消抖完成
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
cnt<=20'd0;
end
else if(add_cnt)begin
if(ent_cnt)begin
cnt<=20'd0;
end
else if(nedge)begin
cnt<=20'd0;
end
else begin
cnt<=cnt+1;
end
end
else begin
cnt<=cnt;
end
end
assign add_cnt = flag;//计数开始条件
assign end_cnt = (cnt == TIME_20MS - 1)&&add_cnt;//终止结束条件,当满足计时到20ms,且满足计时条件时成立
//信号延时模块
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
key_in_r0<=4'b1111;
key_in_r1<=4'b1111;
key_in_r2<=4'b1111;
end
else begin
key_in_r0<=key_in;
key_in_r1<=key_in_r0;
key_in_r2<=key_in_r1;
end
end
//检测下降沿,当任意一个按键出现下降沿都会被检测到
assign nedge = (~key_in_r1[0]&key_in_r2[0])||(~key_in_r1[1]&key_in_r2[1])||(~key_in_r1[2]&key_in_r2[2])||(~key_in_r1[3]&key_in_r2[3]);
//消抖开始模块
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
flag<=1'b0;
end
else if(nedge)begin//当出现下降沿开始消抖
flag<=1'b1;
end
else if(end_cnt)begin//当end_cnt满足时停止消抖
flag<=1'b0;
end
else begin
flag<=flag;
end
end
//输出信号赋值模块,当消抖完毕标志按键按下,出现一个脉冲信号表示按键按下
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
key_out<=4'b1111;//默认为高电瓶
end
else if(end_cnt)begin
key_out<=key_in;//稳定信号赋值
end
else begin
key_out<=4'b1111;//其他信号默认为高电平
end
end
endmodule
module key_top(
input wire clk,
input wire rst_n,
input wire[3:0] key,
output wire[3:0] led
);
wire[3:0] key_r;
key_debounce inst_key_debounce (
.clk(clk),
.rst_n(rst_n),
.key(key),
.key_r(key_r));
key_led inst_key_led (
.clk(clk),
.rst_n(rst_n),
.key(key_r),
.led(led));
endmodule
三、仿真代码
module key_top_tb();
reg clk;
reg rst_n;
reg[3:0] key;
wire[3:0] led;
wire[3:0] key_r;
parameter SYS_CLK = 20;
parameter TIME = 100;
always #(SYS_CLK/2) clk = ~clk;
initial begin
clk=1'b0;
rst_n=1'b0;
#(2*SYS_CLK);
rst_n=1'b1;
key = 4'b1111;
#(2*SYS_CLK);
repeat (19) begin
key[0] = ~key[0];
#(2*SYS_CLK);
end
key[0] = 1'b0;
#(400*SYS_CLK);
$stop;
end
key_debounce #(.TIME_20MS(TIME)) inst_key_bounce (
.clk(clk),
.rst_n(rst_n),
.key(key),
.key_r(key_r));
key_led #(.TIME_0_2S(TIME)) inst_key_led (
.clk(clk),
.rstn(rstn),
.key(key),
.led(led));
endmodule
四、仿真结果
五、总结
总的来说编写不算复杂,需要注意的是模块之间的连接和按键消抖模块