1

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

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

谢谢你的帮助。

4

9 回答 9

6

制作单周期脉冲的诀窍是意识到在发出脉冲后,只要触发输入为高电平,您就必须等待,然后才能返回开始。本质上,您正在构建一个非常简单的状态机,但只有 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;
于 2013-11-24T19:29:57.890 回答
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
  • 带有 on 事件的嵌套结构if应该如上
  • clk只应使用的上升沿,因此无需检查clk = '0'

可以使用同步的“0”到“1”检测器打开一个周期脉冲,clr_flag使用一个延迟一个周期的版本,在下面调用,然后检查。flagflagflagflag_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;
于 2013-11-24T18:30:50.737 回答
1

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;
于 2020-02-26T13:01:34.007 回答
0

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

在此处输入图像描述

于 2013-11-30T13:48:15.247 回答
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
于 2016-10-27T11:05:13.930 回答
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);
于 2020-02-24T12:36:10.317 回答
0

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

always @(posedge clk or negedge rst) begin

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

else flgD <= flg;

end

assign trg = (flg^flgD)&flgD;
于 2016-04-25T19:00:12.170 回答
0

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

使用此创建的 PS 电路。

于 2020-02-24T19:34:47.960 回答
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 ;
于 2021-06-10T11:00:55.067 回答