实现功能描述:通过选择不同按键,控制4个小灯的不同变化。具体实现功能如下:
当按键key1按下时,led灯从右往左依次闪烁;
当按键key2按下时,led灯从左往右依次闪烁;
当按键key3按下时,led灯全亮;
当按键key4按下时,led灯每次加1'b1;//如:led=0010;led+1'b1=0011;
程序:
led灯模块:
module key_led (
input wire clk,//时钟50MHZ
input wire rst_n,//复位信号,下降沿有效
input wire [3:0] key_value,
input wire [3:0] key_flag,
output reg [3:0] led
);
//按键消抖
//wire [3:0] flag;
//wire [3:0] key_value;
parameter TIME = 24'd10_000_000;//0.2s
reg [23:0] cnt;//计数寄存器,计数0.2s
reg [2:0] state;//记录四个led状态
//0.2s计数器模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt <= 24'd0;//计数器清零
end
else if(cnt == TIME - 1)begin//记满10_000_000个数后清零
cnt <= 24'd0;//计数器清零
end
else begin
cnt <= cnt + 1'd1;
end
end
//状态确定模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
state <= 3'd0;
end
else if((key_flag==4'b0001)&&(key_value[0]==1'b0))begin //此时led从右往左依次闪烁
state <= 3'd1;
end
else if((key_flag==4'b0010)&&(key_value[1]==1'b0))begin //此时led从左往右依次闪烁
state <= 3'd2;
end
else if((key_flag==4'b0100)&&(key_value[2]==1'b0))begin //此时四个led灯同时闪烁
state <= 3'd3;
end
else if((key_flag==4'b1000)&&(key_value[3]==1'b0))begin //此时led加一
state <= 3'd4;
end
else begin
state <= state;
end
end
//状态控制led模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led <= 4'b0001;
end
else begin
case (state)
1: if (cnt == TIME - 1'b1)
led<= {led[2:0],led[3]};
else
led <= led;
2: if(cnt == TIME - 1'b1)
led <= {led[0],led[3:1]};
else
led <= led;
3: if(cnt == TIME - 1'b1)
led <= 4'b1111;
else
led <= led;
4: if(cnt == TIME - 1'b1)
led <=led+1'b1;
else
led <=led;
default:led <= 4'b0001;
endcase
end
end
endmodule
按键消抖模块:
//四个按键消抖
module key_debounce (
input wire clk,
input wire rst_n,
input wire [3:0] key,
output reg [3:0] flag,
output reg [3:0] key_value
);
parameter DELAY = 20'd1000_000;//20ms
reg [19:0] delay_cnt ;//延迟计数器
reg [3:0] key_reg; //中间按键寄存器,存放当前按键的值,用于和下次按键作比较
//延迟计数器模块
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
delay_cnt <= 20'd0;
key_reg <=4'b1111;
end
else begin
key_reg <= key;
if((key_reg[0]!=key[0])||(key_reg[1]!=key[1])||(key_reg[2]!= key[2])||(key_reg[3]!=key[3]))begin//如果抖动
delay_cnt <= DELAY;
end
else begin
if(delay_cnt>20'd0)begin
delay_cnt <= delay_cnt - 1'b1;
end
else begin
delay_cnt <= 20'd0;//如果延时计数器小于等于0,延时计数器清零
end
end
end
end
//获取各个按键的状态以及其稳定信号
//根据延时计数器获取flag[0]状态以及稳定按键信号key_value[0]
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag[0] <= 1'b0;
key_value[0] <= 1'b1;
end
else if((delay_cnt == 20'd0)&&(key[0]==1'b0))begin
flag[0] <=1'b1;//当条件满足,改变抖动标志
key_value[0] <=key[0];//将key[0]的稳定信号存入key_value中
end
else begin
flag[0] <= 1'b0;//计数器没有记满1000_000;此时抖动
key_value[0] <= key_value[0];
end
end
//根据延时计数器获取flag[1]状态以及稳定按键信号key_value[1]
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag[1] <= 1'b0;
key_value[1] <= 1'b1;
end
else if((delay_cnt == 20'd0)&&(key[1]==1'b0))begin
flag[1] <=1'b1;//当条件满足,改变抖动标志
key_value[1] <=key[1];//将key[0]的稳定信号存入key_value中
end
else begin
flag[1] <= 1'b0;//计数器没有记满1000_000;此时抖动
key_value[1] <= key_value[1];
end
end
//根据延时计数器获取flag[2]状态以及稳定按键信号key_value[2]
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag[2] <= 1'b0;
key_value[2] <= 1'b1;
end
else if((delay_cnt == 20'd0)&&(key[2]==1'b0))begin
flag[2] <=1'b1;//当条件满足,改变抖动标志
key_value[2] <=key[2];//将key[0]的稳定信号存入key_value中
end
else begin
flag[2] <= 1'b0;//计数器没有记满1000_000;此时抖动
key_value[2] <= key_value[2];
end
end
//根据延时计数器获取flag[3]状态以及稳定按键信号key_value[3]
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag[3] <= 1'b0;
key_value[3] <= 1'b1;
end
else if((delay_cnt == 20'd0)&&(key[3]==1'b0))begin
flag[3] <=1'b1;//当条件满足,改变抖动标志
key_value[3] <=key[3];//将key[0]的稳定信号存入key_value中
end
else begin
flag[3] <= 1'b0;//计数器没有记满1000_000;此时抖动
key_value[3] <= key_value[3];
end
end
endmodule
顶层模块:
module top_key_led (
input wire clk,
input wire rst_n,
input wire [3:0] key,
output wire[3:0] led
);
wire [3:0] key_value;
wire [3:0] flag;
parameter TIME = 24'd10_000_000;//0.2s
key_led #(.TIME(TIME)) key_led_inst(
/*input wire */.clk (clk ),//时钟50MHZ
/*input wire */.rst_n(rst_n),//复位信号,下降沿有效
/*input wire [3:0]*/.key_value(key_value ),
.key_flag (flag),
/*output reg [3:0]*/.led (led)
);
parameter DELAY = 20'b1000_1000;//20ms
key_debounce #(.DELAY(DELAY)) key_debounce_inst (
/*input wire */.clk (clk ),
/*input wire */.rst_n (rst_n),
/*input wire [3:0]*/.key (key ),
/*output reg [3:0]*/.flag (flag ),
/*output reg [3:0]*/.key_value(key_value)
);
endmodule
仿真测试模块:
`timescale 1ns/1ns
module tb_top_key_led ();
reg clk;
reg rst_n;
reg [3:0] key;
wire [3:0] led;
initial begin
clk = 1'b0;
rst_n=1'b0;
#10
rst_n=1'b1;
end
always #10 clk = ~clk;
initial begin
key = 4'b1111;
#40000
key = 4'b1110;
#40000
key = 4'b1101;
#40000
key = 4'b1011;
#40000
key= 4'b0111;
#50000;
$stop;
end
top_key_led #(.TIME(200),
.DELAY(1000))
top_key_led_inst(
/*input wire */ .clk (clk ),//时钟50MHZ
/*input wire */ .rst_n(rst_n),//复位信号,下降沿有效
/*input wire [3:0]*/ .key (key ),
/*output reg [3:0]*/ .led (led)
);
endmodule
仿真图:
经过上板验证后,实验现象和实验预期设想相同,本次没有上传实验现象视频。