与其担心未来,不如现在好好努力。在这条路上,只有奋斗才能给你安全感。你若努力,全世界都会为你让路。

用verilog HDL语言设计一个FPGA的流水灯程序,要求时序满足下图所示,自定义流水间隔。



《FPGA学习》->流水灯设计_sed


设计先确定好流水间隔,我这里设置为500ms,换算成时钟周期公式为 (流转间隔时间/1S)*50MHz,单位为ns,那500ms的流转间隔得到的时钟周期为(500000/1000000000)*50000000 = 25000000(ns) 。

module waterfall_light                //模块开始,定义名称为waterfall_light
#(
parameter CNT_MAX = 25'd24_999_999 //定义全局变量,时间周期为500ms (500000/1000000000)*50000000 = 25000000(ns)
)
(
input wire sys_clk , //定义sys_clk为输入模式 (时钟)
input wire sys_rst_n , //定义sys_rst_n为输入模式 (复位)

output reg[3:0]led_out //定义led_out为寄存器类型的输出模式
);

reg [24:0] cnt ; //定义cnt为25位宽的寄存器类型

always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0) //复位信号到来
begin
cnt <= 25'd0; //使cnt清零
end
else if(cnt == CNT_MAX) //cnt计数到最大值
begin
cnt <= 25'd0; //使cnt清零
end
else
begin
cnt <= cnt + 25'd1;//时钟信号到来,cnt的值+1
end
end

always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0) //复位信号到来
begin
led_out <= 4'b1110; //使led_out的值改为4'b1110
end
else if(cnt == CNT_MAX) //cnt计数到最大值
begin
led_out <= {led_out[2:0],led_out[3]}; //1110 -> 1101 -> 1011 -> 0111 -> 1110
// a = 10; b = 01; {a,b}= 1001
end
else
begin
led_out <= led_out; //led_out保持不变
end
end

endmodule //模块结束

运行后的仿真波形如下:



《FPGA学习》->流水灯设计_sed_02


从图中可以看出,运行后的仿真波形与设计需求保持一致,任务完成。仿真文件代码如下:

`timescale 1ns/1ns               //时间尺度预编译指令      时间单位/时间精度

module tb_waterfall_light(); //定义模块名称为tb_waterfall_light
reg sys_clk ; //定义sys_clk为reg型
reg sys_rst_n ; //定义sys_rst_n为reg型

wire [3:0] led_out ; //定义led_out为reg型

initial //初始化
begin
sys_clk = 1'b1 ; //使sys_clk初始化为高电平状态
sys_rst_n = 1'b0 ; //使sys_clk初始化为低电平状态
#20 //延时20ns
sys_rst_n = 1'b1 ; //使sys_rst_n电平拉高
end

always #10 sys_clk = ~sys_clk; //使sys_clk电平10ns电平状态反转一次

waterfall_light //例化对象名称
#(
.CNT_MAX (25'd24) //改变parameter定义的参数
)
waterfall_light_inst //实例化名称
(
.sys_clk (sys_clk), //使sys_clk信号端口例化为sys_clk
.sys_rst_n (sys_rst_n), //使sys_rst_n信号端口例化为sys_rst_n

.led_out (led_out) //使led_out信号端口例化为led_out
);

endmodule //模块结束