通过按键按下的时长使LED闪烁不同的模式
按下时间 t < 1s,led0闪烁3次;
1 < t < 2s,led0闪烁10次;
t > 2s,led0-3闪烁10次。
主程序
module led_control (
input clk,
input rst_n,
input key,
output [3:0] led
);
reg [2:0] state;
wire flash_done;
reg mode,en;
reg [4:0] times;
reg [31:0] cnt;
reg en_cnt;
wire key_flag,key_state;
//按键消抖
key_filter key_filter1(
.Clk(clk), //50M时钟输入
.Rst_n(rst_n), //模块复位
.key_in(key), //按键输入
.key_flag(key_flag), //按键标志信号
.key_state(key_state) //按键状态信号
);
//控制灯的闪烁
led_flash led_flash1(
.clk(clk),
.rst_n(rst_n),
.mode(mode), //不同的模式闪烁不同灯的个数
.en(en),
.times(times), //闪烁次数
.led_out(led),
.flash_done(flash_done)
);
//按键计时
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 0;
end
//状态机
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
state <= 0;
en <= 0;
times <= 0;
mode <= 0;
en_cnt <= 0;
end
else
begin
case (state)
0: begin
if(key_flag && !key_state)
begin
state <= 1;
en_cnt <= 1;
end
else
begin
state <= 0;
en_cnt <= 0;
end
end
1: begin
if(key_flag && key_state)
begin
en_cnt <= 0;
if(cnt < 49999999)
state <= 2;
else if(cnt >= 49999999 && cnt < 99999999)
state <= 3;
else
state <= 4;
end
else
begin
state <= 1;
en_cnt <= 1;
end
end
2: begin
if(flash_done)
begin
en <= 0;
state <= 0;
end
else
begin
times <= 3;
mode <= 0;
state <= 2;
en <= 1;
end
end
3: begin
if(flash_done)
begin
en <= 0;
state <= 0;
end
else
begin
times <= 10;
mode <= 0;
state <= 3;
en <= 1;
end
end
4: begin
if(flash_done)
begin
en <= 0;
state <= 0;
end
else
begin
times <= 15;
mode <= 1;
state <= 4;
en <= 1;
end
end
default: begin
state <= 0;
en <= 0;
times <= 0;
mode <= 0;
en_cnt <= 0;
end
endcase
end
end
endmodule
闪灯程序
//led按需求闪烁不同的数量和次数
module led_flash (
input clk,
input rst_n,
input mode, //不同的模式闪烁不同灯的个数
input en,
input [4:0] times, //闪烁次数
output reg [3:0] led_out,
output reg flash_done
);
reg en_cnt;
reg [24:0] cnt; //一次闪烁时长250ms---12499999
reg [6:0]flash_cnt;
parameter s = 25'd12499999;
//闪烁时长计数 一次闪烁时长250ms---12499999
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 0;
else if(en_cnt)
begin
if(cnt == s)
cnt <= 0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= 0;
end
//对闪烁次数进行计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
flash_cnt <= 0;
else if(en)
begin
if(cnt == s)
flash_cnt <= flash_cnt + 1'b1;
else
flash_cnt <= flash_cnt;
end
else
flash_cnt <= 0;
end
//根据模式使不同的灯进行闪烁
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
led_out <= 4'b1111;
else if(!mode)
begin
if(cnt == s)
led_out[0] <= ~led_out[0];
else
led_out[0] <= led_out[0];
end
else
begin
if(cnt == s)
led_out[3:0] <= ~led_out[3:0];
else
led_out[3:0] <= led_out[3:0];
end
end
//根据闪烁次数完成情况 使能计数和输出结束标志位
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
flash_done <= 0;
en_cnt <= 0;
end
else if(en)
begin
if(flash_cnt < times*2)
begin
flash_done <= 0;
en_cnt <= 1;
end
else
begin
flash_done <= 1;
en_cnt <= 0;
end
end
else
begin
flash_done <= 0;
en_cnt <= 0;
end
end
endmodule
按键消抖
module key_filter(
Clk, //50M时钟输入
Rst_n, //模块复位
key_in, //按键输入
key_flag, //按键标志信号
key_state //按键状态信号
);
input Clk;
input Rst_n;
input key_in;
output reg key_flag;
output reg key_state;
localparam
IDEL = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
reg [3:0]state;
reg [19:0]cnt;
reg en_cnt; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_in_sa <= 1'b0;
key_in_sb <= 1'b0;
end
else begin
key_in_sa <= key_in;
key_in_sb <= key_in_sa;
end
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_tmpa <= 1'b0;
key_tmpb <= 1'b0;
end
else begin
key_tmpa <= key_in_sb;
key_tmpb <= key_tmpa;
end
//产生跳变沿信号
assign nedge = !key_tmpa & key_tmpb;
assign pedge = key_tmpa & (!key_tmpb);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
en_cnt <= 1'b0;
state <= IDEL;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(state)
IDEL :
begin
key_flag <= 1'b0;
if(nedge)begin
state <= FILTER0;
en_cnt <= 1'b1;
end
else
state <= IDEL;
end
FILTER0:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
en_cnt <= 1'b0;
state <= DOWN;
end
else if(pedge)begin
state <= IDEL;
en_cnt <= 1'b0;
end
else
state <= FILTER0;
DOWN:
begin
key_flag <= 1'b0;
if(pedge)begin
state <= FILTER1;
en_cnt <= 1'b1;
end
else
state <= DOWN;
end
FILTER1:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
state <= IDEL;
en_cnt <= 1'b0;
end
else if(nedge)begin
en_cnt <= 1'b0;
state <= DOWN;
end
else
state <= FILTER1;
default:
begin
state <= IDEL;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule
仿真文件
`timescale 1ns/1ns
`define clock_period 20
module led_control_tb;
reg clk;
reg rst_n;
reg key;
reg [15:0]myrand;
wire [3:0]led;
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
led_control led_control(
.clk(clk),
.rst_n(rst_n),
.key(key),
.led(led)
);
initial begin
rst_n = 0;
key = 1;
#(`clock_period *10)
rst_n = 1;
#(`clock_period *11)
press_key(39999999);
$stop;
end
task press_key;
input [31:0] press_time;
begin
key = 0;
#press_time;
key = 1;
#press_time;
end
endtask
endmodule
实现效果:
按键按下时长控制LED闪烁模式