基于触发信号的一个时钟周期脉冲

时间:2013-11-24 13:15:26

标签: triggers vhdl clock pulse

我正在制作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脉冲),系统将通过两个状态而不是每个标志一个。

因此简而言之:当一个信号变高(与其变为低电平时无关)时,应产生一个时钟周期内的脉冲。

感谢您的帮助。

9 个答案:

答案 0 :(得分:5)

制作单周期脉冲的诀窍是意识到已经产生脉冲,只要触发输入为高电平,就必须等待,然后再回到开始状态。从本质上讲,您构建的是一个非常简单的状态机,但只有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;

答案 1 :(得分: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的嵌套结构应如上所述
  • 只应使用clk的上升沿,因此不会检查clk = '0'

clr_flag变高时,在flag上产生一个周期脉冲可以用a 在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;

答案 2 :(得分:1)

下面是一种创建信号(flag2)的方法,该信号从至少一个时钟周期的信号(flag1)开始完全一个时钟周期。

enter image description here

答案 3 :(得分:0)

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

always @(posedge clk or negedge rst) begin

if(~rst) flgD <= 1'b0;

else flgD <= flg;

end

assign trg = (flg^flgD)&flgD;

答案 4 :(得分:0)

我是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

答案 5 :(得分:0)

以下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);

答案 6 :(得分:0)

实现此目的的方法是创建一个去抖动电路。如果仅在第一个时钟需要D触发器将0更改为1,只需在其输入之前添加一个AND门,如下图所示: second one is the debounce circuit for the first flip-flip 因此,在这里您可以看到一个D触发器及其去抖电路。

P.S。使用this创建的电路。

答案 7 :(得分:0)

FSM的同步和边缘检测

检测到这些事件时,“上升”,“边缘”和“下降”输出将选通一个周期。输入和输出被同步以与有限状态机一起使用。

Synchronisation and edge detection

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;

答案 8 :(得分:0)

        --------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--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 ;