• 【FPGA】verilog基础语法与应用:位操作 / 模块调用——流水灯(跑马灯)


    verilog基础语法与应用:位操作——流水灯/跑马灯

    今天的实验是计数器实验的升级,设计让8个LED灯以每个0.5s的速率循环闪烁

    1 移位法实现

    1.1 移位方法1

    每个LED灯代表一位,共8位,亮为1,灭为0

    image-20221112161809602

    如何实现这样的逻辑呢?

    位操作即可!

    怎么样才能移位呢?

    第一个状态需满足最低位为1,然后每次左移1个

    • 源代码
    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 == 2500_0000-1)
          //  else if(counter == 2500-1) //为了仿真的时候方便观察,把数字改小
                counter <= 0;
            else
                counter <= counter + 1'd1;
                
                
        // 用移位方法实现 8个灯循环闪烁
        //0000_0001    
        //0000_0010    
        //0000_0100    
        //0000_1000    
        //0001_0000    
        //0010_0000    
        //0100_0000 
        //1000_0000    
    
         always@(posedge clk or negedge reset_n)
            if(!reset_n)
                led <= 8'b0000_0001;
            else if(counter == 2500_0000-1)
          //  else if(counter == 2500-1) //为了仿真的时候方便观察,把数字改小,现在是0.05ms
    
                begin
                    if(led==8'b1000_0000)
                        led <= 8'b0000_0001;
                    else
                        led <= led << 1; //  '<<' 是左移
                end
            else
                led <= 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
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 仿真代码
    `timescale 1ns / 1ps
    
    module led_run_tb;
    
        reg clk;
        reg reset_n;
        wire [7:0] led;
        
        led_run UUT(
            .clk(clk),
            .reset_n(reset_n),
            .led(led)
        );
        
        initial clk = 1;
        always#10 clk =~ clk;
    
        initial begin
            reset_n = 0;
            #201;
            reset_n = 1;
            #4000000;  //仿真时是小数字,0.05ms闪烁一次
            $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
    • 25
    • 26
    • 功能仿真结果

    image-20221112172539435

    • 管脚分配

    image-20221112180020304

    效果

    1.2 移位方法2

    之前我们直接使用了左移操作符实现移位操作,现在我们改进一下,使用位拼接操作来实现

    image-20221112181540760

    我们该如何理解

    led <= {led[6:0],led[7]}; //使用位拼接完成移位
                              //每次把led[7]的值放到到上一次的led[0]的位置,led[6]代替led[7]
    
    • 1
    • 2

    画一张图帮助理解

    image-20221112175716250

    2 利用之前的3-8译码器(学会模块调用模块)

    • 先打开之前的 decoder_3_8的文件
    image-20221112184412479
    • 把decoder_3_8.v 的文件复制到这个路径下(E:\vivado_project\led_run\led_run.srcs\sources_1\new)这是我的路径
    image-20221112184458889
    • 然后就成了这样
    image-20221112184736292
    • 添加到工程中来
    image-20221112184857590 image-20221112184937847
    • 然后,工程中就有了3-8译码器的文件

    image-20221112185037272

    • 在led_run2的文件中例化3-8译码器的文件

      • 首先我们需要生成一个新的计数器(代表a、b、c)

      image-20221112185925036

      • 然后例化(类似仿真的例化)

      image-20221112190011319

      • 由于之前在decoder_3_8中,out已经定义为了reg型,就不能再把led定义为reg型,所以led的reg需要去掉

    image-20221112190216130

    • 下面我们仿真一下,看看是否成功实现了功能,我们不用再写一个仿真文件,只需要在之前的仿真文件下面改一下即可
    image-20221112190842587
    • 分析仿真结果

    image-20221112191022145

    从结果我们可以看出,与之前的一样,证明我们成功了

    源文件

    module led_run2(
        clk,
        reset_n,
        led
        );
        input clk;
        input reset_n;
        output [7:0] led;
        
    
        reg [24:0] counter;
        
        always@(posedge clk or negedge reset_n)
            if(!reset_n)
                counter <= 0;
            else if(counter == 2500_0000-1)
           // else if(counter == 2500-1) //为了仿真的时候方便观察,把数字改小
                counter <= 0;
            else
                counter <= counter + 1'd1;
    
        reg [2:0] counter2; //引入一个新的3位计数器
        
         always@(posedge clk or negedge reset_n)
            if(!reset_n)
                counter2 <= 0;
    //         else if(counter2 == 7) 由于3位2进制数最大就是7,所以这个else if 可省略不写
    //            counter2 <= 0;
             else if(counter == 2500_0000-1)
           //else if(counter == 2500-1) //为了仿真的时候方便观察,把数字改小
                counter2 <= counter2 + 1'b1;
                
        decoder_3_8  decoder_3_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
    • 36
    • 37
    • 38
    • 39
    • 40

    最后附上效果图
    在这里插入图片描述

  • 相关阅读:
    golang list 遍历
    现代营销杂志现代营销杂志社现代营销编辑部2022年第11期目录
    Samba服务搭建
    概统 | 一图总结特殊积分之伽马函数
    postgresql数据库备份
    2022-11-14对象树模型
    cmdline-tools component is missing
    MNN编译
    半导体晶圆厂内外网数据单向导出,什么样的方案才安全又便捷?
    Maven——采用profile设定不同的开发环境切换
  • 原文地址:https://blog.csdn.net/Living_Amethyst/article/details/127824118