【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
  • 仿真代码
`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
  • 功能仿真结果

image-20221112172539435

  • 管脚分配

image-20221112180020304

效果

1.2 移位方法2

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

image-20221112181540760

我们该如何理解

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

画一张图帮助理解

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

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

  • 28
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值