文章目录
- 设计目标
- 思路
- 仿真结果
- 时间点一:201ns
- 时间点二:220ns
- 时间点三:250,000,220ns
- 时间点四:1,000,000,200ns
- 时间点五:1,000,000,220ns
- 总结:
案例和代码来自小梅哥课程,本人仅对知识点做做笔记,如有学习需要请支持官方正版。
设计目标
让主频50MHz的FPGA每0.25s亮,0.75s灭,如图所示:
可以看到其中1s对应50,000,000个周期,即50MHz,每个周期20ns
50MHz时钟下度过的周期和时间对应关系如下:
周期数量 | 对应时间 |
---|---|
12,500,000 | 0.25秒 |
50,000,000 | 1秒 |
37,500,000 | 0.75秒 |
思路
由于需要计数到50,000,000-1,那么我们计数器的位宽可以设置为26位,2^26=67,108,864,足够计数到50,000,000-1。
reg [25:0] count;
我们的核心目标其实是让led亮12,500,000个周期,然后灭37,500,000个周期,如此反复。
想象下现实中的秒表,从0开始计时,到59,再变为0,刚好是60秒,同理,我们的计数器也是从0开始计数,当上升沿检测到50,000,000-1时,说明已经经历了1秒,所以复位为0
Led灯按照0.5秒闪烁的代码如下,我们在这个基础上改一改
module led_ctrl0(clk,rst_n,led_out
);input clk;input rst_n;output reg led_out;reg [25:0] counter;//第一个always负责counter计数器always@(posedge clk or negedge rst_n) beginif(!rst_n) begincounter <= 0;end else if(counter == 50_000_000-1) begincounter <= 0 ;end else begincounter <= counter + 1'd1;endend//第二个always负责led_out亮灭always@(posedge clk or negedge rst_n) beginif(!rst_n) beginled_out <= 1'b0;end else if(counter == 0 ) beginled_out <= 1'd1;end else if(counter == 1250_0000) beginled_out <= 1'd0;endend
endmodule
`timescale 1ns / 1psmodule led_ctrl_tb();reg clk;reg rst_n;wire led;led_ctrl0 led_ctrl0_inst0(.clk(clk),.rst_n(rst_n),.led_out(led));initial clk = 1;always #10 clk = ~clk;initial beginrst_n = 0;#201rst_n = 1;#2000000000;$stop;endendmodule
仿真结果
我们把变量转换的几个时间点看一遍,请注意我截图中黄色的marker:
时间点一:201ns
201ns时rst_n低电平复位信号由0变成1,即在此之后复位信号就无效了。
时间点二:220ns
在220ns,
第一个always负责counter计数器,检测到counter为0,自增为1
第二个always负责led_out亮灭,检测到counter为0,令led为1
后面每次上升沿时检测到的counter的值就是led亮了多久
时间点三:250,000,220ns
在250,000,220ns
第一个always负责counter计数器,检测到counter为12,500,000,还没到1秒对应的50,000,000-1,所以继续自增。
第二个always负责led_out亮灭,检测到counter为12,500,000,说明已经亮了0.25秒,所以直接灭掉。
时间点四:1,000,000,200ns
第一个always负责counter计数器,检测到counter到了50,000,000-1,所以counter归零。
第二个always负责led_out亮灭,counter为49999999,不是0,所以继续灭。
时间点五:1,000,000,220ns
第一个always负责counter计数器,检测到counter为0,自增为1
第二个always负责led_out亮灭,counter为0,所以点亮led
总结:
从时间点五这个图中可以看出counter计数器当检测到49999999时,实际上已经计数完1秒了,原因是上升沿检测的时候49999999已经持续了一个周期。
led从counter为0到counter为12,500,000刚好亮0.25秒,因为检测到0时实际上会立刻跳变为1,0时刻并不是一个周期,而12,500,000是完整地过了一个周期。然后从12,500,001到49999999,再加上0时刻刚好是0.75秒。所以功能是没问题的。