【问题标题】:ONE clock period pulse based on trigger signal一个基于触发信号的时钟周期脉冲
【发布时间】:2013-11-24 13:15:25
【问题描述】:

我正在制作一个 MIDI 接口。 UART 工作正常,它将 8 位消息和标志一起发送到控制单元。当标志变高时,单元会将消息存储在一个寄存器中,并使 clr_flag 为高,以便再次将 UART 的标志设置为低。问题是我不能让这个 clr_flag 长一个时期。我需要它是一个周期长,因为这个信号还控制一个状态机,指示正在存储什么样的消息(例如 note_on -> key_note -> velocity)。

我的问题是,信号(在这种情况下为标志)如何仅在一个 clk 周期内触发脉冲?我现在所拥有的几乎在一个时钟周期内产生了一个脉冲,但我做了两次,因为标志还没有变成 0。我尝试了很多方法,现在我有了这个:

get_data:process(clk, flag)
  begin
  if reset = '1' then
    midi <= (others => '0');
    clr_flag <= '0';
    control_flag <= '0';

  elsif ((clk'event and clk='1') and flag = '1') then
      midi <= data_in;
      clr_flag <= '1'; 
      control_flag <= '1';     
  elsif((clk'event and clk='0') and control_flag = '1') then
    control_flag <= '0';
  elsif((clk'event and clk='1') and control_flag = '0') then
    clr_flag <= '0';
  end if;
end process;

这个双脉冲或长于一个周期脉冲的问题(在此之前,我有一些东西使 clr_flag 成为两个周期的 clk 脉冲),是系统将通过两种状态而不是每个标志一个状态。

简而言之:当一个信号变高时(与它何时变低无关),应该在一个时钟周期内产生一个脉冲。

感谢您的帮助。

【问题讨论】:

  • 我才开始学习 vhdl,对我来说有一些魔力,这就是我在评论中回答的原因。尝试从 elsif 中删除 clk'event。有时它对我有帮助。

标签: triggers vhdl clock pulse


【解决方案1】:

制作单周期脉冲的诀窍是意识到在发出脉冲后,只要触发输入为高电平,您就必须等待,然后才能返回开始。本质上,您正在构建一个非常简单的状态机,但只有 2 个状态,您可以使用简单的布尔值来区分它们。

Morten 认为需要为时钟进程采用一种标准模式是正确的;我选择了另一种效果同样好的。

get_data:process(clk, reset)
   variable idle : boolean;
begin
   if reset = '1' then
      idle := true;
   elsif rising_edge(clk) then
      clr_flag <= '0';     -- default action
      if idle then
         if flag = '1' then
            clr_flag <= '1';  -- overrides default FOR THIS CYCLE ONLY
            idle <= false;
         end if;
      else
         if flag = '0' then
            idle := true;
         end if;
      end if;
  end if;
end process;

【讨论】:

  • 明确这两种状态而不是使用“空闲”和“非空闲”不是更好吗?
  • @AyoubBargach 你可以,但在什么意义上“更好”?如果你看一下布尔类型的定义,你会看到一个有两个值的枚举类型;形式相同,只是名称不同。
  • 你在哪里声明了clr_flagflag变量?
  • @Unknown123 它们不是变量,我只是假设问题中的声明。
【解决方案2】:

为了使设计实现一个周期,有几个问题需要解决 使用触发器(寄存器)脉冲。

首先,通常通过 VHDL 结构在硬件中使用触发器 遵循如下结构:

process (clk, reset) is
begin
  -- Clock
  if rising_edge(clk) then
    -- ... Flip flops to update at rising edge
  end if;
  -- Reset
  if reset = '1' then
    -- Flip flops to update at reset, which need not be all
  end if;
end process;

所以get_data进程应该相应更新,因此:

  • 敏感度列表应仅包含时钟 (clk) 和 reset
  • if on event 的嵌套结构应该如上
  • 只应使用clk 的上升沿,因此不检查clk = '0'

flag 变高时在clr_flag 上产生一个周期脉冲,可以使用 在flag 上同步“0”到“1”检测器,使用flag 的版本,即 延迟一个周期,在下面调用flag_ff,然后检查(flag = ''1) and (flag_ff = '0')

生成的代码可能如下所示:

get_data : process (clk, reset) is
begin
  -- Clock
  if rising_edge(clk) then
    flag_ff  <= flag;  -- One cycle delayed version
    clr_flag <= '0';   -- Default value with no clear
    if (flag = '1') and (flag_ff = '0') then  -- Detected flag going from '0' to '1'
      midi     <= data_in;
      clr_flag <= '1';  -- Override default value making clr_flag asserted signle cycle
    end if;
  end if;
  -- Reset
  if reset = '1' then
    midi     <= (others => '0');
    clr_flag <= '0';
    -- No need to reset flag_ff, since that is updated during reset anyway
  end if;
end process;

【讨论】:

    【解决方案3】:

    FSM 的同步和边缘检测

    当检测到这些事件时,上升、边沿和下降输出将选通一个周期。输入和输出同步以用于有限状态机。

    entity SynchroniserBit is
        generic
        (
            REG_SIZE: natural := 3  -- Default number of bits in sync register.
        );
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            async_in: in std_logic := '0';
            sync_out: out std_logic := '0';
            rise_out: out std_logic := '0';
            fall_out: out std_logic := '0';
            edge_out: out std_logic := '0'
        );
    end;
    
    architecture V1 of SynchroniserBit is
        constant MSB: natural := REG_SIZE - 1;
        signal sync_reg: std_logic_vector(MSB downto 0) := (others => '0');
        alias sync_in: std_logic is sync_reg(MSB);
        signal rise, fall, edge, previous_sync_in: std_logic := '0';
    begin
        assert(REG_SIZE >= 2) report "REG_SIZE should be >= 2." severity error;
    
        process (clock, reset)
        begin
            if reset then
                sync_reg <= (others => '0');
                previous_sync_in <= '0';
                rise_out <= '0';
                fall_out <= '0';
                edge_out <= '0';
                sync_out <= '0';
            elsif rising_edge(clock) then
                sync_reg <= sync_reg(MSB - 1 downto 0) & async_in;
                previous_sync_in <= sync_in;
                rise_out <= rise;
                fall_out <= fall;
                edge_out <= edge;
                sync_out <= sync_in;
            end if;
        end process;
    
        rise <= not previous_sync_in and sync_in;
        fall <= previous_sync_in and not sync_in;
        edge <= previous_sync_in xor sync_in;
    end;
    

    【讨论】:

      【解决方案4】:

      下面是一种从持续至少一个时钟周期的信号 (flag1) 创建一个持续恰好一个时钟周期的信号 (flag2) 的方法。 p>

      【讨论】:

      • 我相信你只需要两个状态机,因为低是空闲的。
      【解决方案5】:

      我不使用 VHDL 编程〜这是我通常在 Verilog 中为相同的建议所做的:

      always @(posedge clk or negedge rst) begin
      
      if(~rst) flgD <= 1'b0;
      
      else flgD <= flg;
      
      end
      
      assign trg = (flg^flgD)&flgD;
      

      【讨论】:

        【解决方案6】:

        我是 verilog 的新手,这是我用于触发的示例代码。希望这符合您的目的。您可以在 VHDL 中尝试相同的逻辑。

        module main(clk,busy,rd);
        
        input clk,busy;    // busy input condition 
        output rd;         // trigger signal
        reg rd,en;
        
        always @(posedge clk)
        begin
          if(busy == 1)
          begin
            rd <= 0;
            en <= 0;
          end
        
          else
          begin
            if (en == 0 )
            begin
              rd <= 1;
              en <= 1;
            end
            else 
              rd <= 0; 
          end
        end
        
        endmodule
        

        【讨论】:

          【解决方案7】:

          下面的verilog 代码将准确地保存一个时钟周期的信号值。

          module PulseGen #(
              parameter integer BUS_WIDTH = 32
              )
              (
              input [BUS_WIDTH-1:0] i,
              input clk,
              output [BUS_WIDTH-1:0] o
              );
          
              reg [BUS_WIDTH-1:0] id_1 = 0 ;
              reg [BUS_WIDTH-1:0] id_2 = 0 ;
              always @(posedge clk)begin
               id_1 <= i;
               id_2 <= id_1;
              end
              assign o = (id_1 &  ~id_2);
          

          【讨论】:

            【解决方案8】:

            实现这一点的方法是创建一个去抖电路。如果您需要一个 D 触发器从 0 变为 1,仅对于第一个时钟,只需在其输入之前添加一个 AND 门,如下图所示: 所以在这里你可以看到一个 D 触发器及其去抖电路。

            附:使用this 创建的电路。

            【讨论】:

              【解决方案9】:
                      --------------------------------------------------------------------------------
              --------------------------------------------------------------------------------
              --input of minimum 1 clock pulse will give output of wanted length.
              --load number 5 to PL input and you will get a 5 clock pulse no matter how long input is.
              --------------------------------------------------------------------------------
              --------------------------------------------------------------------------------
              library ieee ;
              use ieee.std_logic_1164.all ;
              use ieee.std_logic_unsigned.all ;
              entity fifth is
                       port (clk , resetN      : in std_logic;
                             pdata             : in integer range 0 to 5; --parallel data in. to choose how many clock the out pulse would be.
                             din               : in std_logic;
                             dout              : out std_logic
                             ) ;
              end fifth ;
              architecture arc_fifth of fifth is
                 signal count   : integer range 0 to 5;
                 signal pl      : std_logic; --trigger detect output.
                 signal sample1 : std_logic;
                 signal sample2 : std_logic;
              --trigger sync proccess.
              begin
              process(clk , resetN)
              begin
              if resetN = '0' then 
                 sample1<='0';
                 sample2<='0';
              
                 elsif rising_edge(clk) then
                 sample1<=din;
                 sample2<=sample1;
              
              end if;
              end process;
              pl <= sample1 and (not sample2); --trigger detect output. activate the counter.
              
              --counter proccess.
              process ( clk , resetN )
              begin
                 if resetN = '0' then
                       count <= 0 ;
                       elsif rising_edge(clk) then
                             if pl='1' then
                             count<=pdata;
                             else       
                                if count=0 then
                                count<=count;
                                else
                                count<=count-1;
                                end if;
                             end if;       
              end if ;
                 end process ;
              
              dout<='1' when count>0 else '0';--output - get the wanted lenght pulse no matter how long is input
              
              end arc_fifth ;
              

              【讨论】:

                猜你喜欢
                • 2020-03-26
                • 1970-01-01
                • 2021-11-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-02-23
                • 1970-01-01
                相关资源
                最近更新 更多