我正在制作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脉冲),系统将通过两个状态而不是每个标志一个。
因此简而言之:当一个信号变高(与其变为低电平时无关)时,应产生一个时钟周期内的脉冲。
感谢您的帮助。
答案 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)开始完全一个时钟周期。
答案 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门,如下图所示: 因此,在这里您可以看到一个D触发器及其去抖电路。
P.S。使用this创建的电路。
答案 7 :(得分:0)
检测到这些事件时,“上升”,“边缘”和“下降”输出将选通一个周期。输入和输出被同步以与有限状态机一起使用。
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 ;