verilog基础语法与应用:位操作——流水灯/跑马灯
今天的实验是计数器实验的升级,设计让8个LED灯以每个0.5s的速率循环闪烁
1 移位法实现
1.1 移位方法1
每个LED灯代表一位,共8位,亮为1,灭为0
![image-20221112161809602](https://i-blog.csdnimg.cn/blog_migrate/a3b7a16a7084ff8f5f1a84e48282a4f8.png)
如何实现这样的逻辑呢?
移位操作即可!
怎么样才能移位呢?
第一个状态需满足最低位为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
- 功能仿真结果
- 管脚分配
效果
1.2 移位方法2
之前我们直接使用了左移操作符实现移位操作,现在我们改进一下,使用位拼接操作来实现
我们该如何理解
led <= {led[6:0],led[7]}; //使用位拼接完成移位
//每次把led[7]的值放到到上一次的led[0]的位置,led[6]代替led[7]
画一张图帮助理解
2 利用之前的3-8译码器(学会模块调用模块)
- 先打开之前的 decoder_3_8的文件
![image-20221112184412479](https://i-blog.csdnimg.cn/blog_migrate/97ccc0892907a0657802af57d34f2035.png)
- 把decoder_3_8.v 的文件复制到这个路径下(
E:\vivado_project\led_run\led_run.srcs\sources_1\new
)这是我的路径
![image-20221112184458889](https://i-blog.csdnimg.cn/blog_migrate/bc4c7e1c92cb3af2b6a0e0a1ffaaaa36.png)
- 然后就成了这样
![image-20221112184736292](https://i-blog.csdnimg.cn/blog_migrate/30e2afde57f277f4e9729c0d979a2efe.png)
- 添加到工程中来
![image-20221112184857590](https://i-blog.csdnimg.cn/blog_migrate/ad0b43b90edd2c69d0d6ce89805fd730.png)
![image-20221112184937847](https://i-blog.csdnimg.cn/blog_migrate/c8bfe27d2a48aae9d345d8645a5aa825.png)
- 然后,工程中就有了3-8译码器的文件
-
在led_run2的文件中例化3-8译码器的文件
- 首先我们需要生成一个新的计数器(代表a、b、c)
- 然后例化(类似仿真的例化)
- 由于之前在decoder_3_8中,out已经定义为了reg型,就不能再把led定义为reg型,所以led的reg需要去掉
- 下面我们仿真一下,看看是否成功实现了功能,我们不用再写一个仿真文件,只需要在之前的仿真文件下面改一下即可
![image-20221112190842587](https://i-blog.csdnimg.cn/blog_migrate/4dd878c9ea82d05723fc3bb4c9e820d1.png)
- 分析仿真结果
从结果我们可以看出,与之前的一样,证明我们成功了
源文件
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
最后附上效果图