我正致力于生成40位长的脉冲序列。我也必须能够调整频率。我尝试制作一个新的低频时钟,并制作一个新的计数器,它依靠它的上升沿并提供高输出并在40位后终止。它不起作用。我尝试了其他一些方法。它们也不是。
例如;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
entity con40 is port(clk:in std_ulogic; q:out std_ulogic);
end entity con40;
architecture Behaviour of con40 is
constant s:std_ulogic_vector:="11111111111111111111111111111111";
signal i:unsigned(4 downto 0):="00000";
signal en:std_logic:='1';
signal reset:std_logic:='0';
begin
q<=s(to_integer(i));
process(reset,clk) is begin
if reset='1' then
i<=(others=>'0');
elsif rising_edge(clk) then
if en='1' then
i<=i+1;
end if;
end if;
end process;
end architecture Behaviour;
此代码中有32位长度,但我想要制作40位,但无论如何,这也不起作用。我认为这种脉冲序列的方法必须是常见的,并且它们被广泛使用。但是嘿!不幸的是,我找不到任何有用的东西。
答案 0 :(得分:0)
以下代码可以是生成脉冲序列的简单实现。该模块需要一个启动脉冲(StartSequence)并使用&#39; SequenceCompleted&#39;确认生成的序列。
我使用带有set = StartSequence
和rst = SequenceCompleted_i
的基本RS触发器代替状态机。我还把这个过程分成了两个过程:
最初,模块默认情况下会发出PULSE_TRAIN(0),也会在每次序列生成后发出。因此,如果你想发出40个,否则设置为PULSE_TRAIN := (0 => '0', 1 to 40 => '1')
此模块在PULSE_TRAIN的位数中是可变的,因此我需要包含一个名为log2ceil的函数,该函数根据PULSE_TRAIN的长度属性计算2s对数,即所需位。
因此,如果'length = 41
位Counter_us
的范围为(5 downto 0)。
entity PulseTrain is
generic (
PULSE_TRAIN : STD_LOGIC_VECTOR
);
port (
Clock : in STD_LOGIC;
StartSequence : in STD_LOGIC;
SequenceCompleted : out STD_LOGIC;
Output : out STD_LOGIC
);
end entity;
architecture rtl of PulseTrain is
function log2ceil(arg : POSITIVE) return NATURAL is
variable tmp : POSITIVE := 1;
variable log : NATURAL := 0;
begin
if arg = 1 then return 0; end if;
while arg > tmp loop
tmp := tmp * 2;
log := log + 1;
end loop;
return log;
end function;
signal State : STD_LOGIC := '0';
signal Counter_us : UNSIGNED(log2ceil(PULSE_TRAIN'length) - 1 downto 0) := (others => '0');
signal SequenceCompleted_i : STD_LOGIC;
begin
process(Clock) is
begin
if rising_edge(Clock) then
if (StartSequence = '1') then
State <= '1';
elsif (SequenceCompleted_i = '1') then
State <= '0';
end if;
end if;
end process;
SequenceCompleted_i <= '1' when (Counter_us = (PULSE_TRAIN'length - 1)) else '0';
SequenceCompleted <= SequenceCompleted_i;
process(Clock)
begin
if rising_edge(Clock) then
if (State = '0') then
Counter_us <= (others => '0');
else
Counter_us <= Counter_us + 1;
end if;
end if;
end process;
Output <= PULSE_TRAIN(to_integer(Counter_us));
end;
答案 1 :(得分:0)
我冒昧地将en
和reset
移动到端口信号,也将常量更改为可识别的40位值,并指定范围使其成为局部静态常量。
你的计数器的问题是它不足以解决40位。您将i
指定为5位值,而40位需要6位计数器。
我还在这里添加了第二个架构,其中i为整数类型信号。如果i
为无符号值或整数类型,则当第一个位置为0(i
)时,您可能需要在39("100111"
)处翻转"000000"
计数器
library ieee;
use ieee.std_logic_1164.all;
entity con40 is
port(
reset: in std_ulogic;
clk: in std_ulogic;
en: in std_ulogic;
q: out std_ulogic
);
end entity con40;
architecture foo of con40 is
constant s: std_ulogic_vector (0 to 39) := x"feedfacedb";
signal i: natural range 0 to 39;
begin
q <= s(i);
process (reset, clk)
begin
if reset = '1' then
i <= 0;
elsif rising_edge(clk) and en = '1' then
if i = 39 then
i <= 0;
else
i <= i + 1;
end if;
end if;
end process;
end architecture;
library ieee;
use ieee.numeric_std.all;
architecture behave of con40 is
constant s: std_ulogic_vector (0 to 39) := x"feedfacedb";
signal i: unsigned (5 downto 0);
begin
q <= s(to_integer(i));
process (reset, clk)
begin
if reset = '1' then
i <= "000000";
elsif rising_edge(clk) and en = '1' then
if i = "100111" then
i <= "000000";
else
i <= i + 1;
end if;
end if;
end process;
end architecture;
我也做了一个快速而肮脏的测试台:
library ieee;
use ieee.std_logic_1164.all;
entity tb_con40 is
end entity;
architecture foo of tb_con40 is
signal clk: std_ulogic := '0';
signal reset: std_ulogic := '1';
signal en: std_ulogic := '0';
signal q: std_ulogic;
begin
DUT:
entity work.con40
port map (
reset => reset,
clk => clk,
en => en,
q => q
);
CLOCK:
process
begin
for i in 0 to 46 loop
wait for 20 ns;
clk <= not clk;
wait for 20 ns;
clk <= not clk;
end loop;
wait;
end process;
STIMULUS1:
reset <= '0' after 40 ns;
STIMULUS2:
en <= '1' after 60 ns;
end architecture;
可以证明正确的输出:
回复评论问题的附录
模式X"FEEDFACEDB"
长度为40位,替代了constant s
的32个全1'值,以证明您实际上正在处理s
数组值的各个元素。 / p>
停止脉冲序列重复出现:
对于架构foo
(使用i
的整数类型):
elsif rising_edge(clk) and en = '1' then
-- if i = 39 then
-- i <= 0;
-- else
if i /= 39 then -- added
i <= i + 1;
end if;
当计数器达到39时,计数器停止运行。
对于体系结构行为(使用i
的无符号类型):
elsif rising_edge(clk) and en = '1' then
-- if i = "100111" then
-- i <= "000000";
-- else
if i /= "100111" then -- added
i <= i + 1;
end if;
end if;
这两种体系结构在39(i
)处的"100111"
计数器的行为完全相同。
通过模拟可以显示计数器已停止:
如果不添加额外的控制输入,第二次发出脉冲流的唯一方法就是调用重置。
答案 2 :(得分:0)
正如@ fru1tbat所提到的,它并不是很清楚什么是&#34;没有工作&#34;以及你真正打算做什么。如果你真的只想生成一个脉冲序列,人们会认为你想要生成一系列交替的“脉冲序列”。和&#39; 0&#39;,并非所有&#39; 1都像你发布的代码一样。
此外,i
计数器只会计数,并且只能重置为&#39; 0&#39;通过使用reset
信号,只要你按照这样的方式就可以了。
如果您想要生成一系列的“1&0”和“0”,您需要这样的事情(未经测试,但应该沿着这些方向):
architecture behaviour of con40 is
constant trainLength:positive:=80;
signal i:unsigned(6 downto 0):=(others=>'0');
...
begin
process(reset,clk) is begin
if reset then
i<=(others=>'0');
q<='0';
elsif rising_edge(clk) then
q<='0'; -- default assignment.
-- Defaults to '0' when if-statement fails.
if i<trainLength then
i<=i+1;
q<=not q;
end if;
end if;
end process;
end architecture behaviour;
这为您提供了单次脉冲序列,这意味着除非再次声明reset
信号,否则无法重复生成脉冲序列。如果这是你想要的,那就好了,否则,你需要更多的信号来满足你想要重新生成脉冲序列而不重置的情况。
在这里,我假设您想要40个高脉冲,这实际上使列车长度为80个时钟周期,而不是40个。此外,我假设你想要50%的占空比,即HIGH和LOW时间相等。根据您的要求,您可能需要更长或更短的脉冲宽度。
考虑到这些假设,您至少需要一个7位计数器来计算80个时钟。您可能会想到其他更好的方法来做到这一点,但这只是我的头脑,并且可能是一个很好的起点。
如果您的工具尚不支持VHDL-2008的增强端口模式(例如,能够从out
- 模式端口读取),那么您可以将q
声明为具有buffer
模式而不是out
。如果您的工具不支持buffer
端口模式,那么您可以声明一个内部信号并将其用于您的逻辑。 E.g:
signal i_q: std_ulogic;
...
i_q<=not i_q; -- use internal signal for logic instead.
q<=i_q; -- drive output from internal signal.
要调整频率,只需在clk
输入中提供更高或更低的频率。这可以从另一个PLL,分频器或您可用的任何其他振荡电路生成。只需将其输出提供给clk
。
希望这有帮助。