Verilog 学习第二节(语法学习与应用,led跑马灯)

  • Post author:
  • Post category:其他




设计目标

计数器实验升级,设计让8个led灯以每个0.5s的速率循环闪烁(跑马灯)


小梅哥写法一



module led_run(
    input clk,
    input reset,
    output reg [7:0]led
    );
    reg [24:0]cnt;
    always @(posedge clk or negedge reset) begin
        if(!reset)//记住复位就是复位,不要想if和后面的操作逻辑合并~such as if((!reset)or(cnt==25000000-1))
           cnt<=0;
//        else if(cnt==25000000-1)
        else if(cnt==25000-1)
           cnt<=0;
        else 
           cnt<=cnt+1'd1;//判断的时候不加位宽限定还好,但是赋�?�的时�?�要加,为了好记的话,自己还是随时都加吧~
    end
    
    always @(posedge clk or negedge reset) begin
        if(!reset)
           led<=8'b0000_0001;
//        else if(cnt==25000000-1)begin
        else if(cnt==25000-1)begin
            if(led==8'b1000_0000)
            led<=8'b0000_0001;
            else
            led<=led<<1;
            end
 //以上if  else内的话可以直接变成led={led[6:0],led[7]};
 //这种简便写法
        else
        led<=led;
          
    end
endmodule





小梅哥写法二

module led_run(
    input clk,
    input reset,
    output [7:0]led
    );
    reg [24:0]cnt;
    reg [2:0]count;
    always @(posedge clk or negedge reset) begin
        if(!reset)//记住复位就是复位,不要想着和后面的操作逻辑合并~such as if((!reset)or(cnt==25000000-1))
           cnt<=0;
        else if(cnt==25000-1)
           cnt<=0;
        else 
           cnt<=cnt+1'd1;//判断的时候不加位宽限定还好,但是赋值的时候要加,为了好记的话,自己还是随时都加吧~
    end
    
    always @(posedge clk or negedge reset) begin
        if(!reset)
           count<=0;
        else if(cnt==25000-1)begin
        if(count==7)
            count<=0;
        else
           count<=count+1'b1;
           end
        else 
           count<=count;
    end
    decoder3_8 decoder3_8(.a(count[2]),.b(count[1]),.c(count[0]),.out(led));
    //下面的这种直接写的形式完全可以采用例化的方法实现,并且由于底层模块已经定义好了led为reg类型,所以这层的led就无需再定义了
//    always @(count) begin
//        if(!reset)
//           led=0000_0001;
//        else begin
//        case(count)
//        3'b000:led=8'b0000_0001;
//        3'b001:led=8'b0000_0010;
//        3'b010:led=8'b0000_0100;
//        3'b011:led=8'b0000_1000;
//        3'b100:led=8'b0001_0000;
//        3'b101:led=8'b0010_0000;
//        3'b110:led=8'b0100_0000;
//        3'b111:led=8'b1000_0000;
//        endcase
//        end
//    end
endmodule


改进版

//在led_run中设置参数CMNT;
   parameter CMNT=25'b24999999;
//同时在led_run_tb中设置参数defparam仿真时参数
   defparam led_run.CMNT=25'b24999;
//注意上面的 led_run 代表的是例化后的模块名称,不是原来的 led_run
//以上的写法可以方便实际和仿真次数不同步
//----------------------------
//如果上面测试文件的写法仿真会报错的话可以用以下的写法
led_run#(.MCNT(24999))led_run(.clk(clk),.reset(reset),.led(led));


测试文件

`timescale 1ns / 1ns

module led_run_tb();
   reg clk;
   reg reset;
   wire [7:0]led;
   led_run led_run(.clk(clk),.reset(reset),.led(led));
   initial begin
    clk=0;
   end
   always#10 clk=!clk;
   initial begin
    reset=0;
    #201;
    reset=1;
    #40000000;
    $stop;
    end
endmodule


仿真结果


在这里插入图片描述


收获:


1:在仿真的时候为了节省时间可以选择不用一定计数到25000000,可以选择少一些数,只要能看到有同样的效果就好,在真进行下板的时候记得调回去就可~

2:如果本模块中有一些功能自己曾经写过简单的模块则可以直接调用实现,而不必再在代码中再写一遍,而且如果其中的接口有定义过其是reg类型那么在顶层模块就不用再重复定义了(因为自己写的时候也很可能出现一些小差错)

3:写法二中新填了一个计数器count计数为8,关于else if位置对7的判断地方,自己的逻辑思考中是要有的,但是其实可以直接一直加1,因为3位的计数器再加1的时候会产生溢出,保留位置的值仍是000,可以简便写法不去判断

4:有的时候出现灯的情况和自己理想状况不一样的时候可以看看是不是在写0000_0001的时候忘记在前面加上8’b了如果不加其默认可是为系统宽度十进制的数的,要注意!!

5:参数化的写法不只是用于仿真中,也可以在其他模块例化的时候进行重新赋值等等的使用


自己曾经的错误写法


module led_run(
    input clk,
    input reset,
    output reg [7:0]led
    );
    reg [24:0]cnt;
    reg [2:0]count;
    always @(posedge clk or negedge reset) begin
        if(!reset)//记住复位就是复位,不要想着和后面的操作逻辑合并~such as if((!reset)or(cnt==25000000-1))
           cnt<=0;
        else if(cnt==25000-1)
           cnt<=0;
        else 
           cnt<=cnt+1'd1;//判断的时候不加位宽限定还好,但是赋值的时候要加,为了好记的话,自己还是随时都加吧~
    end
    
    always @(posedge clk or negedge reset) begin
        if(!reset)
           count<=0;
        else if(cnt==25000-1)begin
        if(count==7)
            count<=0;
        else
           count<=count+1'b1;
           end
        else 
           count<=count;
    end
    always @(posedge clk or negedge reset) begin
        if(!reset)
           led<=0;
        else if(cnt==25000-1)
           led[count]<=!led[count];
        else
    end
endmodule

在这里插入图片描述

注:最开始自己想的是每到0.5ms每一位就按位取反就好,但是实际上取反之后它还是亮的,在下一位亮的时候它也亮,没有恢复,所以不是很恰当~(

这里引出的还想要学习的一点是其实自己是想看看不是输入输出的端口比如计数器cnt的变化情况!!!



版权声明:本文为weixin_46741734原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。