设计规划
依次点亮4个LED灯,实现流水灯的效果,两灯之间点亮间隔为0.5s,LED灯一次点亮持续时间0.5s。
LED灯低电平点亮,因此流水灯应该是1110-1101-1011-0111-1110-1101-...
首先是时钟信号、复位信号,由于需要计时,我们还要产生一个计数器cnt。然后还需要产生一个cnt_flag脉冲标志信号作为流水切换的标志,每当计数器计数到24_999_998时拉高并只产生一个时钟的高电平(高电平出现LED状态就开始切换)。最重要的是,流水灯的实现是通过左移操作,无法直接通过led_out的左移实现,因此需要定义一个led_out_reg(led_out从1110左移一次是1100,会有两个灯点亮,而led_out_reg是LED的位反0001,左移一次是0010,取反后led_out是1101,就能实现流水的需求)。
编写代码
module water_led
#(
parameter CNT_MAX = 25'd24_999_999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
output wire [3:0] led_out
);
//reg define
reg [24:0] cnt ;
reg cnt_flag ;
reg [3:0] led_out_reg ;
//cnt:计数器计数500ms
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 25'b0;
else if(cnt == CNT_MAX)
cnt <= 25'b0;
else
cnt <= cnt + 1'b1;
//cnt_flag:计数器计数满500ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag <= 1'b0;
else if(cnt == CNT_MAX - 1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
//led_out_reg:led循环流水
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
led_out_reg <= 4'b0001;
else if(led_out_reg == 4'b1000 && cnt_flag == 1'b1)
led_out_reg <= 4'b0001;
else if(cnt_flag == 1'b1)
led_out_reg <= led_out_reg < < 1'b1; //左移
assign led_out = ~led_out_reg;
endmodule
三个中间信号的定义:cnt,cnt_flag,led_out_reg。
1、cnt:计数器变化的条件是时钟上升和复位有效(复位下降),复位信号有效时cnt变为低电平;计满时清零;其他时刻+1。
2、cnt_flag:计数器计满的脉冲标志信号,变化条件和cnt一样,复位有效时变为低电平;计满前一个时钟拉高;其他时刻都为0,这样就能成为一个脉冲信号,并在计满前拉高,标志led要左移。
3、led_out_reg:暂存led灯状态,可以直接对这个信号进行操作来控制LED灯。复位和初始时是最右边的灯亮,反推出led_out_reg=0001;当最左边的灯亮且计满标志信号拉高时,令最右边的灯亮led_out_reg=0001;当计满标志信号拉高时,led_out_reg左移。而控制LED电平的输出信号led_out是led_out_reg的按位取反。
编写testbench
`timescale 1ns/1ns
module tb_water_led();
//wire define
wire [3:0] led_out ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always #10 sys_clk = ~sys_clk;
//-------------------- water_led_inst --------------------
water_led
#(
.CNT_MAX (25'd24)
)
water_led_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.led_out (led_out ) //output [3:0] led_out
);
endmodule
testbench代码是非常熟悉的,信号定义,初始化,实例化。
对比波形
1110-1101-1011-0111分别对应了十六进制的e,d,b,7
由于在testbench模块,为了节省时间将CNT_MAX设置成24,因此24个时钟脉冲LED的状态就会发生变化,波形和我们预想的一致。
分配管脚
全部0条评论
快来发表一下你的评论吧 !