实现效果是让排成一排的 led 灯依次闪亮,像“流水”一样循环不止,看上去很舒服,其原理就是依次控制每个连接到 led 灯的 I/O 电平的高低。
先上代码
第一种:case()分支语句,仿真结果如下
`timescale 1ns/1ns
//左移流水灯:每过0.5s左移一次
module water_led
#(
parameter CNT_MAX = 25'd24_999_999 , //0.5s计数最大值
parameter CNT = 3'd3
)
(
input wire clk ,
input wire rst ,
output reg [4:0] led //输出控制led灯
);
reg [24:0] cnt_500ms ;
reg [2:0] cnt;
reg [3:0] move;
//0.5s计时器
always@(posedge clk or negedge rst)
if(!rst) //rst取反:当复位按键没有按下,为高点平取反后又变为低,按键按下反之。
cnt_500ms <= 25'b0;
else if(cnt_500ms == CNT_MAX)
cnt_500ms <= 25'b0;
else
cnt_500ms <= cnt_500ms + 1'b1;
//计数周期为4的计数器
always@(posedge clk or negedge rst)
if(!rst)
cnt <= 3'd0;
else if((cnt_500ms == CNT_MAX) && (cnt == CNT)) //计数满4,清零
cnt <= 3'd0;
else if(cnt_500ms == CNT_MAX)
cnt <= cnt + 1'b1;
else
cnt <= cnt;
always@(posedge clk or negedge rst) //case()分支语句
if(!rst)
led <= 4'b0001;
else case (cnt)
3'd0: led <= 4'b0001;
3'd1: led <= 4'b0010;
3'd2: led <= 4'b0100;
3'd3: led <= 4'b1000;
default: led <= 4'b0001;
endcase
always@(posedge clk or negedge rst) //位拼接运算符 { , ,, }
if(!rst) begin
led <= 4'b0000;
move <= 4'b0001;
end
else if(cnt_500ms == CNT_MAX)
led <= {led[2:0],move[cnt]};
else
led <= led;
always@(posedge clk or negedge rst) //移位运算符 << >>
if(!rst)
led <= 4'b0001;
else if((cnt_500ms == CNT_MAX) && ( led == 4'b1000))
led <= 4'b0001;
else if (cnt_500ms == CNT_MAX)
led <= led << 1'b1;
else
led <= led;
always@(posedge clk or negedge rst) //乘(*)除(/)运算
if(!rst)
led <= 4'b0001;
else if((cnt_500ms == CNT_MAX) && (led == 4'd8))
led <= 4'b0001;
else if(cnt_500ms == CNT_MAX)
led <= led * 2;
endmodule
第二种:拼接运算符
第三种:移位运算符
第四种:乘除运算
总结:上面方法是Verilog语法的基本应用,最简单的方法为移位运算符,稍微难点的是拼接。重点掌握拼接运算符的使用。