设置一个方向位
判断方向时可以直接使用led_reg的最低位和最高位。
//方法1:设置标志位
module water_led_double
#(
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 cnt_flag;
reg [3:0] led_reg ;//作为led_out的取反信号,方便编程
reg led_dir; //dir = 1向左流水(在板子上是向右)
//计数器计数 500ms
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 25'b0;
else if(cnt == CNT_MAX)
cnt <= 25'b0;
else
cnt <= cnt + 1'b1;
end
//标志位
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_flag <= 1'b0;
else if(cnt == CNT_MAX - 1'b1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
end
//led_dir方向位
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_dir <= 1'b1;//初始向左
else if(led_reg == 4'b1000)
led_dir <= 1'b0;//转为向右
else if(led_reg == 4'b0001)
led_dir <= 1'b1;//转为向左
else
led_dir <= led_dir;
end
//led移位
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_reg <= 4'b0001;
else if(cnt_flag && led_dir) //向左
led_reg <= led_reg << 1'b1;
else if(cnt_flag && !led_dir) //向右
led_reg <= led_reg >> 1'b1;
end
assign led_out = ~led_reg;
endmodule
testbench
`timescale 1ns/1ns
module water_led_double_tb();
wire [3:0] led_out ;
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
always #10 sys_clk = ~sys_clk;
water_led_double
#(
.CNT_MAX (25'd24 )
)
water_led_double_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.led_out (led_out ) //output
);
endmodule
失败方法:
灵活使用{}拼接符,大大简化编程
//方法2:使用拼接{}符号,只需检测两个端点的值即可
module water_led_double
#(
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 cnt_flag;
reg [3:0] led_reg ;//作为led_out的取反信号,方便编程
//计数器计数 500ms
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 25'b0;
else if(cnt == CNT_MAX)
cnt <= 25'b0;
else
cnt <= cnt + 1'b1;
end
//标志位
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_flag <= 1'b0;
else if(cnt == CNT_MAX - 1'b1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
end
assign led_out = ~led_reg;
endmodule
一定要注意,这里的判断条件
需要用不等于来判断,如果用等于的逻辑,只能移动一次就停止了
//led移位
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_reg <= 4'b0001;
else if(cnt_flag && !led_reg[3]) //只要最高位不等于1,就向左
led_reg <= {led_reg[2:0], led_reg[3] };
else if(cnt_flag && !led_reg[0]) //只要最低位不等于1,就向右
led_reg <= {led_reg[0] ,led_reg[3:1] };
end
如果像上面这么写,就会先向左,然后向右,之后就是在右侧两个灯之间来回流水了,因为判断逻辑有问题。