一、题目
8个Led灯以0.5s的速率循环闪烁
二、思路
学习板上晶振为 50MHz,也就是说时钟周期为 20ns,每个灯0.5s的速率循环闪烁,即0-0.5s时,第一个灯亮其他灭,第0.5-1s时,第二个灯亮其他灭,以此循环。0.5s =500_000_000ns
500_000_000ns / 20ns = 25000000 因为是从0开始计数,所以( 25000000-1次即可,转换为二进制: 1011111010111100000111111 至少25位的计数器counter,且每当计数次数达到需要清零并重新计数.
三、设计文件
`timescale 1ns / 1ns
module pipeline_led(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==25000000-1)
// else if(counter==8'd24999) //缩小仿真时间,验证功能,与下一条语句是相同的意思
// else if(counter==24999) //缩小仿真时间,验证功能
counter <=0;
else
counter <=counter +1'b1;
//led进程
always@(posedge clk or negedge reset_n)
if(!reset_n)
led <= 8'b0000_0001;
else if(counter==25000000-1)begin
// else if(counter==8'd24999)begin //缩小仿真时间,验证功能,与下一条语句是相同的意思
// else if(counter==24999)begin //缩小仿真时间,验证功能
if(led ==8'b1000_0000)
led <=8'b0000_0001;//当1处于最高位时,无法通过移位进行处理
else
led <= led<<1;//每当计数器1在[6:0]时,1左移一位
end
else
led <=led;//此处的else的执行语句,可以省略不写
endmodule
四、激励文件
`timescale 1ns / 1ns
module pipeline_led_tb( );
reg clk;
reg reset_n;
wire [7:0]led;
pipeline_led pipeline_led(
.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;
$stop;
end
endmodule
五、仿真图
如果以0.5s为闪烁时间间隔,仿真要等很久,以下仿真图是把时间缩短之后的
![](https://img-blog.csdnimg.cn/img_convert/ee39bc479217200a7cb34b2b5c7d02c5.png)
六、总结
在仿真图里变量的的顺序是testbench里例化的顺序,一般把时钟写在第一位比较好
可以用"位拼接"{led[6:0,led[7]]}对led进程进行改写
//led进程
always@(posedge clk or negedge reset_n)
if(!reset_n)
led <= 8'b0000_0001;
else if(counter==25000000-1)begin
led <= {led[6:0],led[7]};//每次都将上一次的低7位放到高7位上,最高位led[7]赋值到最低位led[0]上
end
else
led <=led;
合并写是错误的
//正确写法
if(!reset_n)
counter <=0;
else if(counter==24999) //缩小仿真时间,验证功能
counter <=0;
//合并的错误写法
if((!reset_n) || (counter==25000000-1))
counter <=0;
tb里两个initial是并行执行的,且只执行一次,但是always不是,always只要满足条件就能一直执行。
流水灯相比于之前的三八译码器、二选一多路器来说,引入了时钟的概念,所以是时序逻辑设计(不仅取决于当前的输入,还与前一时刻输入形成的状态有关)
组合逻辑电路(输出只与目前的输入形成一种函数关系)