-1

我正在生成一个 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 位,但无论如何,这也不起作用。我认为这种脉冲序列的方法必须是常见的,并且它们正在被广泛使用。但是,嘿!不幸的是,我找不到任何有用的东西。

4

3 回答 3

0

As what @fru1tbat mentioned, it's not really clear what is "not working" and what you really intend to do. If you would really just want to generate a pulse train, one would think you want to generate a series of alternating '1' and '0', not all '1's like in the code you posted.

Also, the i counter just counts up, and can only be reset to '0' by use of the reset signal, which is fine as long as you intended it that way.

If you'd like to generate a train of '1's and '0's, you'd need something like this (not tested, but should be along these lines):

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;

This gives you a single-shot pulse train, means there is no way to repeat generation of the pulse train unless you assert the reset signal again. This is fine if it's what you want, otherwise, you'll need more signals to cater for cases where you'd like to re-generate the pulse train without resetting.

Here, I'm assuming you'd like 40 HIGH pulses, which essentially makes the train length 80 clock cycles, not 40. Also, I'm assuming you want a 50% duty cycle, i.e. the HIGH and LOW times are equal. Depending on your requirements, you may need a pulse width that is longer or shorter.

With these assumptions in mind, you'd need at least a 7-bit counter to count 80 clocks. You may think of other better ways to do this as well, but this just comes off the top of my head, and is probably a good place to start.

If your tool doesn't yet support VHDL-2008's enhanced port modes (e.g. ability to read from out-mode ports), then you could declare q as having a buffer mode instead of out. If your tool doesn't support buffer port modes, then you can declare an internal signal and use it for your logic. 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.

To adjust the frequency, simply supply a higher or lower frequency into your clk input. This can be generated from another PLL, or a frequency divider, or any other oscillating circuitry you have available. Just supply its output into your clk.

Hope this helps.

于 2014-09-11T19:59:00.053 回答
0

我冒昧地移动enreset移植信号,还将您的常量更改为可识别的 40 位值,并指定范围以使其成为局部静态常量。

您的计数器的问题是它不足以处理 40 位。您已i指定为 5 位值,而 40 位需要 6 位计数器。

我还在此处添加了第二个架构,其中 i 作为整数类型信号。对于无符号值或整数类型,当第一个位置为 0 ( ) 时,您可能需要在 39 ( ) 处i翻转计数器。i"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 位,并替换了 32 个全 1 的值,constant s以证明您实际上是在处理s数组值的各个元素。

要停止重复出现的脉冲序列:

对于架构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; 

两种架构的行为相同,将i计数器停止在 39 ( "100111")。

通过模拟可以显示计数器已停止:

在此处输入图像描述

在不添加额外控制输入的情况下,使脉冲流第二次发生的唯一方法是调用重置。

于 2014-09-11T19:29:47.467 回答
0

以下代码可以是生成脉冲序列的简单实现。该模块需要一个启动脉冲 (StartSequence) 并使用“SequenceCompleted”确认生成的序列。

set = StartSequence我没有使用状态机,而是使用带有and的基本 RS 触发器rst = SequenceCompleted_i。我还将该过程分为两个过程:

  1. 状态控制 - 如果需要,这可以扩展到完整的 FSM
  2. 用于计数器

最初,该模块默认发出 PULSE_TRAIN(0) 并且在每个序列生成之后。因此,如果您想发出 40 个,否则为零集PULSE_TRAIN := (0 => '0', 1 to 40 => '1')

这个模块在 PULSE_TRAIN 的位数中是可变的,所以我需要包含一个名为 log2ceil 的函数,它从 PULSE_TRAIN 的长度属性中计算 2s 对数,也就是所需的位。因此,如果'length = 41Counter_us的范围为(5 到 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;
于 2014-09-11T13:41:20.073 回答