led跑马灯多种方法(移位法,位拼接法,调用模块法,位移及位拼接语法,testbench的理解,源文件的存储路径,计数器的个数,调用模块的方式)

  跟着教程写了几种方法,才发现自己写的虽然能实现,但比较繁琐。教程有三种方法:

1.移位法,每次左移一位,相比我自己写的,优点是不用把每一种情况都写出来。但是需要考虑左移到最后一位时需要自己再写个赋值语句重新回到第一位。

2.位拼接法,循环左移,每一次都把最后一位放到第一位,其他六位左移一位,克服了移位法的问题,简化了代码。

3.调用已有模块法,调用4-16译码器刚好可以实现流水灯,需要额外的counter作为译码器的输入。

  • 移位法
module led_run1(    //移位法
    clk,
    reset,
    led  
    );
    input clk;
    input reset;
    output reg [7:0]led;
    
    reg [5:0]counter1;
    always@( posedge clk or negedge reset )begin
        if( reset == 1'd0)
        counter1 <= 1'd0;
        else if(counter1 == 4 )    这两个虽然赋值语句一样,但是不能把判断语句合并。
        counter1 <=1'd0;
        else
        counter1 <= counter1 + 1'd1;     
    end
    
    always@(posedge clk or negedge reset) begin
        if( reset == 1'd0)
        led <= 8'b0000_0001;
        else if(counter1 == 4 )begin
            if(led == 8'b1000_0000)
            led <= 8'b0000_0001;      //最后一位的处理
            else
            led <= led << 1'd1 ;      //注意左移几位的语法,应该怎么写
        end
    end
endmodule
  • 位拼接法

 

module led_run2(    //位拼接法
    clk,
    reset,
    led  
    );
    input clk;
    input reset;
    output reg [7:0]led;
    
    reg [5:0]counter1;
    always@( posedge clk or negedge reset )begin
        if( reset == 1'd0)
        counter1 <= 1'd0;
        else if(counter1 == 4 )
        counter1 <=1'd0;
        else
        counter1 <= counter1 + 1'd1;     
    end
    
    always@(posedge clk or negedge reset) begin
        if( reset == 1'd0)
        led <= 8'b0000_0001;
        else if(counter1 == 4 )begin
            led <= {led[6:0],led[7]};    //位拼接的语法,十分注意
end
    end
endmodule

 

  • 调用模块法

 

module led_run4(    //调用模块4-16译码器法
    clk,
    reset,
    led  
    );
    input clk;
    input reset;
    output wire [15:0]led;
    
    reg [2:0]counter1;
    reg [3:0]counter4;    一个用来计数,一个用来译码
    always@( posedge clk or negedge reset )begin
        if( reset == 1'd0)
        counter1 <= 1'd0;
        else if(counter1 == 4 )
        counter1 <=1'd0;
        else
        counter1 <= counter1 + 1'd1;     
    end
    
    always@(posedge clk or negedge reset) begin
        if( reset == 1'd0)
        counter4 <= 8'd1;
        else if(counter1 == 4 )begin
        counter4 <= counter4 + 1'b1;
        end
    end
    
    decoder_4_16 decoder_4_16_run(        //调用的方法类似于仿真时的例化,存储电路与组合逻辑电路相结合。
               .a(counter4[3]),
               .b(counter4[2]),
               .c(counter4[1]),
               .d(counter4[0]),
               .out(led)
        );
        
endmodule

 

 

注意:

1.左移/右移的语法:led=led << n   /   led=led >> n

2.位拼接的语法:led={led[6:0],led[7]} 注意花括号,中括号,数组表达方式。定义时中括号放名字前,引用时放名字后。逗号隔开位。

3.一个testbench可以用来测试验证多个模块,需要修改的是tb里面例化的模块名,激励如果一样可以不修改。(testbench差不多就是个激励产生器用来验证性能)

4.在工程中创建的design sources的源文件的路径为:.srcs->sources->new->xx.v

5.时序电路自少需要一个计数器来控制开发板时钟信号和我们实际需要的周期信号的关系。但是不是说只能有一个,可以根据需求增加。

6.报错:ordered port connections cannot be mixed with named port connections  目标端口连接不能与命名端口连接混合 

  

 

 

  原因:最后一个变量后面加了逗号,删掉即可。

 

7.调用子模块的方式:

 

  7.1把子模块的文件复制到当前工程的design源文件目录下,路径上面有写。

 

  7.2在vivado中添加该文件进design sources,作为子模块。

 

  7.3在顶层文件(即要调用该子文件的文件)调用子模块,方式是类似于testbench的例化。注意,在子模块(底层)中定义了输出为reg型,在顶层应该定义输出为wire型。

    效果

 

 

   

 

 

 

 

posted @ 2022-05-11 20:41  little_breeze  阅读(636)  评论(0编辑  收藏  举报