当前位置:   article > 正文

从零开始学习vivado——day4 跑马灯(让8个LED灯以每个0.5s的速率循环闪烁)_走马灯vivado

走马灯vivado


前言

研一从零开始学习verilog!!!此时不学何时学!
第一次写博客,以此激励自己努力学习!
我跟的视频教程是b站的一个up主,小梅哥爱漂流。

一、vivado是什么?

二、跑马灯设计(让8个LED灯以每个0.5s的速率循环闪烁)

1.工程文件

①编写端口代码:

module Led_run(
   Clk,
   Reset_n,
   Led
);
    input Clk;
    input Reset_n;
    output reg[7:0]Led;
    reg [24:0]counter;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

②计数器

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
      counter<=0;
    else  if(counter==25000-1)//本来应该是25000000-1的,但是为了更快出图像,此处可调整一下数量级
      counter<=0;
    else
      counter<=counter+1'd1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其中,一定是<=,如果直接用=,则波形图会出现错误,从00000010到00000100的时间会非常短,导致整个图像看起来就是每次左移两位。

③LED灯循环闪烁

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
      Led<=0000_0001;
 /*    else  if(counter==25000-1)begin
             if(Led==8'b1000_0000)
                Led<=8'b0000_0001;
              else
                 Led <= Led << 1;//Led左移一位
                 end
*/
        else  if(counter==25000-1)
            Led<={Led[6:0],Led[7]};//向左循环移动一位
           else
                Led<=Led;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

两个/之间的内容为注释掉的内容。要实现8个LED循环闪烁,可用<=进行左移,但这样LED不会循环,如果不加限制条件,会一直出现0000——0000的情况;而直接使用位拼接 Led<={Led[6:0],Led[7]},即循环左移一位。最后加一个endmodule即可。

④代码整合

module Led_run(
   Clk,
   Reset_n,
   Led
);
    input Clk;
    input Reset_n;
    output reg[7:0]Led;
    reg [24:0]counter;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
      counter<=0;
    else  if(counter==25000-1)
      counter<=0;
    else
      counter<=counter+1'd1;//一定是<=,如果直接用=,则波形图会出现错误,从00000010到00000100的时间会非常短,导致整个图像看起来就是每次左移两位
      
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
      Led<=0000_0001;
 /*    else  if(counter==25000-1)begin
             if(Led==8'b1000_0000)
                Led<=8'b0000_0001;
              else
                 Led <= Led << 1;//Led左移一位
                 end
*/
        else  if(counter==25000-1)
            Led<={Led[6:0],Led[7]};//向左循环移动一位
           else
                Led<=Led;
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

2.激励文件

①编写端口代码与例化

module Led_run_tb();
      reg Clk;
      reg Reset_n;
      wire [7:0]Led;
    Led_run Led_run(   
   .Clk(Clk),
   .Reset_n(Reset_n),
   .Led(Led)
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

②编写时钟信号与复位信号

    initial Clk=1;
    always #10 Clk = !Clk;//10ns翻转一次
    initial begin
        Reset_n=0;
        #201;//错开时钟上升沿
        Reset_n=1;
        #400000000;//4s之后灯全部跑完
        $stop;
    end
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

③代码整合

`timescale 1ns/1ns;

module Led_run_tb();
      reg Clk;
      reg Reset_n;
      wire [7:0]Led;
     Led_run Led_run(   
    //Led_run Led_run_38decoder(        //调用3-8译码器的方法
   .Clk(Clk),
   .Reset_n(Reset_n),
   .Led(Led)
);

    initial Clk=1;
    always #10 Clk = !Clk;
    initial begin
        Reset_n=0;
        #201;
        Reset_n=1;
        #4000000000;//4s之后灯全部跑完
        $stop;
    end
        
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

④仿真结果
在这里插入图片描述
波形变化没问题,但是波形变化的周期出了大问题,LED灯循环居然只花了160ns,这与设计的差太多,无论我计数器那里改成25000000-1还是25000-1,图像居然都一样,与视频不符合,这点很奇怪,难道是我开局没选和他一样的板子吗?这个问题后续再解决。

3.调用3-8译码器实现走马灯

①copy文件到指定目录
在这里插入图片描述
在这里插入图片描述

先将3-8译码器的工程文件copy到走马灯的sources文件里面,然后会在Design Sources里面发现他

②例化

    reg [2:0]counter2;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
      counter2<=0;  
/*    else if (counter2==7)
         counter2<=0;   */   //这两行也可以不写,因为counter2位宽为3,最大值为7,当达到7时会自动变为0然后继续计数
     else    
       counter2<=counter2+1;
 //调用3-8译码器的模块
     decoder3_8 decoder3_8(
        .a( counter2[2]),
        .b( counter2[1]),
        .c( counter2[0]),
        .out(Led)
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

由于例化了3-8译码器,所以此时Led只作为接口,out已经在3-8译码器中定义了reg类型,Led就不用定义了
在这里插入图片描述
③代码整合
3-8译码器代码

module decoder3_8(
    a,b,c,out
);
    input a;
    input b;
    input c;
    output reg [7:0]out;//位宽是8位,类型为reg类型,与always相配
    //以always块描述的信号赋值,被赋值对象必须定义为reg类型
    //b代表二进制;3'b101    8'b0000_1010
    //d代表十进制;3'd5      8'd10  
    //h代表十六进制;         8'ha
   always@(*)//*代表a b c
        case({a,b,c})//{a,b,c}变成了一个三位的信号,这种操作叫做位拼接
            3'b000:out=8'b0000_0001;
            3'b001:out=8'b0000_0010;
            3'b010:out=8'b0000_0100;
            3'b011:out=8'b0000_1000;
            3'b100:out=8'b0001_0000;
            3'b101:out=8'b0010_0000;
            3'b110:out=8'b0100_0000;
            3'b111:out=8'b1000_0000;   
       endcase
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

设计代码

`timescale 1ns/1ns;

module Led_run_tb();
      reg Clk;
      reg Reset_n;
      wire [7:0]Led;
  //Led_run Led_run(   
    Led_run Led_run_38decoder(        //调用3-8译码器的方法
   .Clk(Clk),
   .Reset_n(Reset_n),
   .Led(Led)
);

    initial Clk=1;
    always #10 Clk = !Clk;
    initial begin
        Reset_n=0;
        #201;
        Reset_n=1;
        #4000000000;//4s之后灯全部跑完
        $stop;
    end
        
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

激励文件代码

module Led_run(
   Clk,
   Reset_n,
   Led
);
    input Clk;
    input Reset_n;
    output [7:0]Led;//因为例化了3-8译码器,所以此时Led只作为接口,out已经在3-8译码器中定义了reg类型,Led就不用定义了
    reg [25:0]counter;
    reg [2:0]counter2;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
      counter<=0;
    else  if(counter==25000000-1)
      counter<=0;
    else
      counter<=counter+1;//一定是<=,如果直接用=,则波形图会出现错误,从00000010到00000100的时间会非常短,导致整个图像看起来就是每次左移两位
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
      counter2<=0;  
/*    else if (counter2==7)
         counter2<=0;   */   //这两行也可以不写,因为counter2位宽为3,最大值为7,当达到7时会自动变为0然后继续计数
     else    
       counter2<=counter2+1;
 //调用3-8译码器的模块
     decoder3_8 decoder3_8(
        .a( counter2[2]),
        .b( counter2[1]),
        .c( counter2[0]),
        .out(Led)
);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

④仿真结果
在这里插入图片描述
结果与前面一直, 依旧存在周期不对的问题。


总结

今天学习了跑马灯的设计,结合了前面计数器和3-8译码器的知识。
新学的语法有:
①Led <= Led << 1意思为Led左移一位,<<为左移符号;
② Led<={Led[6:0],Led[7]},意思为向左循环移动一位。Led位宽为8,意思就是把第八位移到最后面,其他的依次前推一位,达到左循环移动一位的目的;
③工程文件的例化,需要先将要用的工程文件复制到现有工程的sources文件里面,然后会在Design Sources里面发现他,之后就直接在激励文件里面使用例化就可以。需要注意的是,如果有变量在被例化的文件里面已经定义类型了(如reg或wire),那在激励文件里面就不用再定义。
④在always块里面最好使用<=,不要直接使用=,防止图像发生错误

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号