十、流水灯

流水灯实验是一个经典案例,其效果是让排成一排的led灯依次闪亮,像流水一样循环不止,其原理就是依次控制每个连接到led灯的I/O电平的高低。在本次实验中,让led灯依次闪亮的时间间隔为0.5s,这样速度就比较快,而且肉眼能够分辨。

一、VIsio画图

因为0.5s为一个周期,所以计数器要计数的范围为0~2.5*10^7-1,每次计数到最大值之后清零重新开始计数。设置一个脉冲信号,当计数器计数到最大值的时候产生一个脉冲。最开始的时候是第一个led灯点亮所以初始值是1110(因为led灯是低电平点亮),遇到第一个脉冲信号变为1101,遇到第二个脉冲信号变为1011,再遇到第三个脉冲信号变为0111,再遇到下一个脉冲信号再回到最开始的状态1110,就如此循环下去。

差不多就是下图这个效果:

二、代码

module water_led
#(parameter CNT_MAX=25'd24_999_999)
(
input wire sys_clk,
input wire sys_rst_n,
output reg [3:0] led_out
);
reg [24:0] cnt;
reg cnt_flag;

//cnt赋值
always @(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <= 25'd0;
    else if(cnt == CNT_MAX)
        cnt <= 25'd0;
    else
        cnt <= cnt + 25'd1;
        
//cnt_flag赋值
always @(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_flag <= 1'b0;
    else if(cnt == (CNT_MAX-25'd1))
        cnt_flag <= 1'b1;
    else 
        cnt_flag <= 1'b0;
     
//led_out赋值,左移运算符,右移运算符
always @(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)//当复位信号有效
        led_out <= 4'b1110;
    else if((led_out == 4'b0111)&&(cnt_flag == 1'b1))//当复位信号无效,最后一个灯亮了并且脉冲信号到达
        led_out <= 4'b1110;
    else if(cnt_flag == 1'b1)//不是最后一个灯亮且脉冲信号到达时
        led_out <= led_out << 1;
    else//其他情况保持当前值
        led_out <= led_out;
endmodule

三、仿真

仿真代码:

`timescale 1ns/1ns
module tb_water_led();
reg sys_clk;
reg sys_rst_n;
wire [3:0] led_out;

initial
    begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end 

always #10 sys_clk=~sys_clk;

water_led 
#(.CNT_MAX(25'd24))
water_led_inst
(
.sys_clk  (sys_clk),
.sys_rst_n(sys_rst_n),
.led_out  (led_out)
);
endmodule

仿真波形:

这里就发现一个问题,左移运算之后,第一个周期内点亮第一个led灯,第二个周期点亮一、二个灯,直到第四个灯点亮之后,四个灯就会常量,和我们预计想达到的效果是不一样的。因为左移和右移是在空位补零,而不是补高电平。解决方法就是再设置一个变量,是对输出信号的寄存。

改一下代码:

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 [24:0] cnt;
reg [3:0] led_out_reg;
reg cnt_flag;

//cnt赋值
always @(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <= 25'd0;
    else if(cnt == CNT_MAX)
        cnt <= 25'd0;
    else
        cnt <= cnt + 25'd1;
        
//cnt_flag赋值
always @(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_flag <= 1'b0;
    else if(cnt == (CNT_MAX-25'd1))
        cnt_flag <= 1'b1;
    else 
        cnt_flag <= 1'b0;
     
//led_out_reg赋值,左移运算符,右移运算符
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;
    else//其他情况保持当前值
        led_out_reg <= led_out_reg;
        
assign led_out =~led_out_reg;
endmodule

仿真波形:

四、管脚绑定和上板验证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值