如何在 VHDL 中创建计时器
在之前的教程中,我们使用了 wait for
在模拟中延迟时间的声明。但是生产模块呢? wait for
声明不能用于此。这仅在模拟中有效,因为我们不能只告诉电路中的电子暂停给定时间。那么我们如何在设计模块中跟踪时间呢?
答案只是简单地计算时钟周期。每个数字设计都可以访问以固定的已知频率振荡的时钟信号。因此,如果我们知道时钟频率为 100 MHz,我们可以通过计算一亿个时钟周期来测量一秒。
这篇博文是基本 VHDL 教程系列的一部分。
要在 VHDL 中计算秒数,我们可以实现一个计数器来计算经过的时钟周期数。当这个计数器达到时钟频率的值时,例如 1 亿,我们知道已经过了一秒钟,是时候增加另一个计数器了。我们称之为秒计数器。
要计算分钟数,我们可以实现另一个 Minutes 计数器,它会在 60 秒后递增。同样,我们可以创建一个 Hours 计数器来计算小时数,并在 60 分钟后递增。
我们也可以继续这种方法来计算天数、周数和月数。我们受到底层技术中可用物理资源以及计数器长度与时钟频率的限制。
随着计数器长度的增加,显然它会消耗更多的资源。但它的反应也会变慢,因为事件链变长了。
运动
在本视频教程中,我们将学习如何在 VHDL 中创建计时器模块:
计时器 testbench 的最终代码 :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T18_TimerTb is end entity; architecture sim of T18_TimerTb is -- We're slowing down the clock to speed up simulation time constant ClockFrequencyHz : integer := 10; -- 10 Hz constant ClockPeriod : time := 1000 ms / ClockFrequencyHz; signal Clk : std_logic := '1'; signal nRst : std_logic := '0'; signal Seconds : integer; signal Minutes : integer; signal Hours : integer; begin -- The Device Under Test (DUT) i_Timer : entity work.T18_Timer(rtl) generic map(ClockFrequencyHz => ClockFrequencyHz) port map ( Clk => Clk, nRst => nRst, Seconds => Seconds, Minutes => Minutes, Hours => Hours); -- Process for generating the clock Clk <= not Clk after ClockPeriod / 2; -- Testbench sequence process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); -- Take the DUT out of reset nRst <= '1'; wait; end process; end architecture;
计时器模块的最终代码 :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T18_Timer is generic(ClockFrequencyHz : integer); port( Clk : in std_logic; nRst : in std_logic; -- Negative reset Seconds : inout integer; Minutes : inout integer; Hours : inout integer); end entity; architecture rtl of T18_Timer is -- Signal for counting clock periods signal Ticks : integer; begin process(Clk) is begin if rising_edge(Clk) then -- If the negative reset signal is active if nRst = '0' then Ticks <= 0; Seconds <= 0; Minutes <= 0; Hours <= 0; else -- True once every second if Ticks = ClockFrequencyHz - 1 then Ticks <= 0; -- True once every minute if Seconds = 59 then Seconds <= 0; -- True once every hour if Minutes = 59 then Minutes <= 0; -- True once a day if Hours = 23 then Hours <= 0; else Hours <= Hours + 1; end if; else Minutes <= Minutes + 1; end if; else Seconds <= Seconds + 1; end if; else Ticks <= Ticks + 1; end if; end if; end if; end process; end architecture;
Seconds
上放大的波形 信号:
Minutes
上放大的波形 信号:
Hours
上放大的波形 信号:
分析
为了运行 50 小时的模拟,我们给出了命令 run 50 hr
在 ModelSim 控制台中。 50 小时是一个非常长的模拟,因此我们不得不将测试台中的时钟频率降低到 10 Hz。如果我们将其保持在 100 MHz,则模拟将需要数天时间。为了让我们能够模拟设计,这种适应有时是必要的。
我们右键单击波形中的时间线并选择“网格、时间线和光标控制”。将时间单位从ns改为秒、分、小时后,我们可以看到定时器确实是实时工作的。
由于在模拟开始时模块的复位,定时器时间与模拟时间略有偏移。在第一个波形中可以看到,时间线上的 60 秒标记稍早于 Seconds 信号回绕到 0 时。
请注意,在模拟中,计数器值在时钟的上升沿以零时间更新。在现实世界中,计数器值需要一些时间才能从计数器的第一位传播到最后一位。随着计数器长度的增加,我们消耗了一个时钟周期的可用时间。
如果所有级联计数器的累加长度过长,编译后的布局布线步骤会产生错误。在消耗整个时钟周期之前,您可以实现一个计数器多长时间取决于 FPGA 或 ASIC 架构和时钟速度。
增加的时钟速度意味着计数器链会更长。这也意味着时钟周期时间会更短,让计数器链完成的时间更少。
外卖
- 在 VHDL 模块中测量时间是通过计算时钟周期来实现的
- 降低测试台中的时钟频率将加快仿真速度
转到下一个教程 »
VHDL