一、实验要求
(1)两个按键分别控制led灯的样式和速度,样式分为流水灯和翻转灯,速度分为0.5s/1s/1.5s/2s四个挡位。
(2)分别对两个按键进行按键消抖。
二、状态图
三、程序设计
(1)状态机模块
`timescale 1ns / 1ps
module fancy_led(
input sys_clk ,//系统时钟
input rst_n ,//系统复位
input key_flag_1 ,//key_1按键消抖后产生的标志信号,根据此标志信号完成状态跳转
input key_flag_2 ,//key_2按键消抖后产生的标志信号,根据此标志信号完成状态跳转
input [3:0] led_water ,//从流水灯模块输出
input [3:0] led_jump ,//从翻转灯模块输出
output reg [3:0] led ,//被赋值输出的变量
output reg[31:0] TIME //定义一个时间变量,输入给led_water和led_jump
);
//定义现态、次态
reg [2:0] cur_state; //现态
reg [2:0] next_state; //次态
parameter TIME_0_5s = 32'd25_000_000 ;
parameter TIME_1s = 32'd50_000_000 ;
parameter TIME_1_5s = 32'd75_000_000 ;
parameter TIME_2s = 32'd10_000_000_0 ;
//定义空闲状态
localparam IDLE = 9'b0000 ;
//定义流水灯的四个状态
localparam water_0_5s = 9'b0001 ;
localparam water_1s = 9'b0010 ;
localparam water_1_5s = 9'b0011 ;
localparam water_2s = 9'b0100 ;
//定义翻转灯的四个状态
localparam jump_0_5s = 9'b0101 ;
localparam jump_1s = 9'b0110 ;
localparam jump_1_5s = 9'b0111 ;
localparam jump_2s = 9'b1000 ;
//状态机第一段:描述现态和次态的关系
always@(posedge sys_clk)
if(!rst_n)
cur_state <= IDLE ;
else
cur_state <= next_state ;
//状态机第二段: 描述现态和次态的触发
//key_flag_1改变样式 key_flag_2改变速度
always@(*)
case(cur_state)
IDLE :
begin
if(key_flag_1)
next_state = water_0_5s ;
else if(key_flag_2)
next_state = jump_0_5s ;
else
next_state = cur_state ;
end
water_0_5s :
begin
if(key_flag_2)
next_state = water_1s ;
else if (key_flag_1)
next_state = jump_0_5s ;
else
next_state = cur_state ;
end
water_1s :
begin
if(key_flag_2)
next_state <= water_1_5s ;
else if(key_flag_1)
next_state <= jump_0_5s ;
else
next_state <= cur_state ;
end
water_1_5s :
begin
if(key_flag_2)
next_state <= water_2s ;
else if(key_flag_1)
next_state <= jump_0_5s ;
else
next_state <= cur_state ;
end
water_2s :
begin
if(key_flag_2)
next_state <= water_0_5s ;
else if(key_flag_1)
next_state <= jump_0_5s ;
else
next_state <= cur_state ;
end
jump_0_5s :
begin
if(key_flag_2)
next_state <= jump_1s ;
else if(key_flag_1)
next_state <= water_0_5s ;
else
next_state <= cur_state ;
end
jump_1s :
begin
if(key_flag_2)
next_state <= jump_1_5s ;
else if(key_flag_1)
next_state <= water_0_5s ;
else
next_state <= cur_state ;
end
jump_1_5s :
begin
if(key_flag_2)
next_state <= jump_2s ;
else if(key_flag_1)
next_state <= water_0_5s ;
else
next_state <= cur_state ;
end
jump_2s :
begin
if(key_flag_2)
next_state <= jump_0_5s ;
else if(key_flag_1)
next_state <= water_0_5s ;
else
next_state <= cur_state ;
end
endcase
//状态机第三段 ,关键信号赋值
always@(posedge sys_clk)
case(cur_state)
IDLE :
led <= 4'b1111 ;
water_0_5s : begin
led <= led_water ;
TIME <= TIME_0_5s ;
end
water_1s : begin
led <= led_water ;
TIME <= TIME_1s ;
end
water_1_5s : begin
led <= led_water ;
TIME <= TIME_1_5s ;
end
water_2s : begin
led <= led_water ;
TIME <= TIME_2s ;
end
jump_0_5s : begin
led <= led_jump ;
TIME <= TIME_0_5s ;
end
jump_1s : begin
led <= led_jump ;
TIME <= TIME_1s ;
end
jump_1_5s : begin
led <= led_jump ;
TIME <= TIME_1_5s ;
end
jump_2s : begin
led <= led_jump ;
TIME <= TIME_2s ;
end
endcase
endmodule
(2)流水灯模块
`timescale 1ns / 1ps
module led_water(
input sys_clk ,
input rst_n ,
input [31:0] TIME ,
output reg[3:0] led_water
);
//parameter TIME_1s=26'd50_000_000 ;//定义流水灯计时器\翻转灯计时器最大值
reg [26:0] count ;
//流水灯和翻转灯的1s计时器
always@(posedge sys_clk)
if(!rst_n)
count <= 0 ;
else if(count == TIME-1 )
count <= 0 ;
else
count <= count +1;
always@(posedge sys_clk)
if(!rst_n)
led_water <= 4'b0001 ;
else if( count == TIME-1 )
led_water <={led_water[0],led_water[3:1]} ;
else
led_water <=led_water;
endmodule
(3)翻转灯模块
`timescale 1ns / 1ps
module led_jump(
input sys_clk ,
input rst_n ,
input [31:0] TIME ,
output reg[3:0] led_jump
);
//parameter TIME_1s=26'd50_000_000 ;//定义流水灯计时器\翻转灯计时器最大值
reg [26:0] count_2 ;
//翻转灯的1s计时器
always@(posedge sys_clk)
if(!rst_n)
count_2 <= 0 ;
else if(count_2 == TIME-1 )
count_2 <= 0 ;
else
count_2 <= count_2 +1;
always@(posedge sys_clk)
if(!rst_n)
led_jump <= 4'b0110 ;
else if( count_2 == TIME-1 )
led_jump <=~led_jump ;
else
led_jump <=led_jump ;
endmodule
(4)按键消抖模块
`timescale 1ns / 1ps
module key_1_debounce(
input sys_clk ,
input rst_n ,
input key_1 ,
output wire key_flag_1
);
parameter TIME_20ms = 19'd10_000_0 ;
reg [19:0] cnt_key_1 ;
always@(posedge sys_clk)
if(!rst_n)
cnt_key_1 <= 0 ;
else if( key_1 == 0 )begin
if(cnt_key_1== TIME_20ms -1)
cnt_key_1<= cnt_key_1 ;
else
cnt_key_1 <= cnt_key_1 +1 ;
end
else
cnt_key_1 <= 0 ;
assign key_flag_1 = (cnt_key_1 == TIME_20ms -2)? 1:0 ;
endmodule
`timescale 1ns / 1ps
module key_2_debounce(
input sys_clk ,
input rst_n ,
input key_2 ,
output wire key_flag_2 //长久的使能信号
);
parameter TIME_20ms = 19'd10_000_0 ;
reg [19:0] cnt_key_2 ;
always@(posedge sys_clk)
if(!rst_n)
cnt_key_2 <= 0 ;
else if( key_2 == 0 )begin
if(cnt_key_2 == TIME_20ms -1)
cnt_key_2 <= cnt_key_2 ;
else
cnt_key_2 <= cnt_key_2 +1 ;
end
else
cnt_key_2 <= 0 ;
assign key_flag_2 = (cnt_key_2 == TIME_20ms -2)? 1:0 ;
endmodule
四、block块设计
生成的顶层代码:
//Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.
//--------------------------------------------------------------------------------
//Tool Version: Vivado v.2020.1 (win64) Build 2902540 Wed May 27 19:54:49 MDT 2020
//Date : Thu Jun 6 18:40:01 2024
//Host : LAPTOP-A2IQ2GRP running 64-bit major release (build 9200)
//Command : generate_target block_fancy_led_wrapper.bd
//Design : block_fancy_led_wrapper
//Purpose : IP block netlist
//--------------------------------------------------------------------------------
`timescale 1 ps / 1 ps
module block_fancy_led_wrapper
(key_1_0,
key_2_0,
led_0,
rst_n_0,
sys_clk_0);
input key_1_0;
input key_2_0;
output [3:0]led_0;
input rst_n_0;
input sys_clk_0;
wire key_1_0;
wire key_2_0;
wire [3:0]led_0;
wire rst_n_0;
wire sys_clk_0;
block_fancy_led block_fancy_led_i
(.key_1_0(key_1_0),
.key_2_0(key_2_0),
.led_0(led_0),
.rst_n_0(rst_n_0),
.sys_clk_0(sys_clk_0));
endmodule