在VHDL中计算特定时间段内的边缘

时间:2015-06-04 12:28:03

标签: vhdl counter reset encoder

对于电动机的速度测量,我想在10ms的时间间隔内计算编码器输入的上升沿和下降沿的数量。

为此,我为40 MHz时钟实现了一个时钟分频器,如下所示:

entity SpeedCLK is
Port ( CLK          : in  STD_LOGIC;
       CLKspeed     : out  STD_LOGIC);
end SpeedCLK;
architecture Behavioral of SpeedCLK is
signal CounterCLK   : NATURAL range 0 to 400001;
begin

SpeedCounter : process
begin
wait until rising_edge(CLK);
CounterCLK <= CounterCLK + 1;
if CounterCLK < 400000 then
    CLKspeed        <= '0';
else
    CLKspeed        <= '1';
    CounterCLK      <= 0;
end if;
end process SpeedCounter;

end Behavioral;

这应该每10毫秒使CLKSpeed'1'。我将此块用作Toplevel VHDL模块中的一个组件。在下一个模块中,我使用移位寄存器对编码输入(QEPA)中的边沿进行计数,以对输入信号进行去抖动。

entity SpeedMeasure is
Port (
    QEPA        :   in      STD_LOGIC;
    CLK     :   in      STD_LOGIC;
    CLKSpeed    :   in      STD_LOGIC;
    Speed       :   OUT INTEGER -- in rpm
    );
end SpeedMeasure;

architecture Behavioral of SpeedMeasure is

begin
Edges : process(CLKSpeed, CLK)

variable detect     : STD_LOGIC_VECTOR(5 downto 0) := "000000";
variable    EdgesPerTime    : INTEGER := 0;
variable    CountQEPA       : INTEGER := 0;

begin
if CLKSpeed = '1' then
    EdgesPerTime := countQEPA;
    countQEPA := 0;
ELSIF (CLK'EVENT AND CLK = '1') THEN
    detect(5 downto 1) := detect(4 downto 0);
    detect(0) := QEPA;
if (detect = "011111") OR (detect = "100000") then 
countQEPA := countQEPA + 1;
    else
        countQEPA := countQEPA;
    end if;
end if; 
Speed <= EdgesPerTime;
end process Edges;


end Behavioral;

这应该每隔10 ms在我的变量CountQEPA中写入edgesPerTime的当前值,然后重置计数器。 信号Speed通过uart传输。不幸的是,每隔10ms重置一次CountQEPA,我EdgesPerTime的常数值为0。如果我删除代码中的重置行,我可以收到EdgesPerTime的增加值,直到达到整数(2 ^ 16)的最大数,此时计数器重置为0.

VHDL中用于计算设定时间段内上升沿和下降沿的正确实现是什么?

任何帮助都非常复杂,因为我对vhdl仍然很陌生。

1 个答案:

答案 0 :(得分:0)

您正在使用变量构建一个锁存器。您的综合工具推断CLKSpeed的异步重置countQEPA,并且由于您的锁存EdgesPerTime在其写入启用countQEPA被置位时锁存CLKSpeed,您只能看到重置countQEPA的{​​{1}}值。

您应该构建适当的同步逻辑:

0

我不是变量的忠实粉丝,但现在似乎综合工具变得更加聪明。如您所见,我制作了三个单独的流程来显示我们真正想要的内容。 CountQEPA和去抖现在是信号,因为它们需要从其他过程中读取。

我假设CLKSpeed与CLK(40 MHz)同步。如果不是,那么你应该考虑时钟域之间的握手。

您当然可以从这些单独的流程中制作单个流程。一般来说,我试图避免变量,因为它们可以很容易地用来描述不可综合的行为,就像你发现的那样。

我不确定您的编码器反弹多长时间,但如果您以40 MHz进行采样,则6位移位寄存器可能无法正常工作,因为只有125 ns去抖(您只使用低5位进行去抖动,注意到状态变化的最高位。)

说到你的去抖者。考虑以下情况:

signal CountQEPA : integer                      := 0;
signal detect    : std_logic_vector(5 downto 0) := (others => '0');
begin

edge_cnt_p : process (
    CLK
    )
begin

    if (rising_edge(CLK)) then

        -- synchronous reset
        if (CLKSpeed = '1') then

            countQEPA <= 0;

        elsif ((detect = "011111") or (detect = "100000")) then

            countQEPA <= countQEPA + 1;

        end if;

    end if;

end process edge_cnt_p;

edge_debounce_p : process (
    CLK
    )
begin

    if (rising_edge(CLK)) then

        detect <= detect(detect'left downto 1) & QEPA;

    end if;

end process edge_debounce_p;

count_register_p : process (
    CLK
    )
begin

    if (rising_edge(CLK)) then

        -- synchronous write enable
        if (CLKSpeed = '1') then

            Speed <= countQEPA;

        end if;

    end if;

end process count_register_p;

这可能不是你想要的。您应该将去抖信号与最后稳定状态进行比较,而不是假设state'delayed(5 * clk_period)是稳定状态。

正如我上面所说,我假设CLK是你的40 MHz时钟。您不需要快速采样编码器信号,因为正确的去抖动器会占用大量的移位寄存器位而没有任何附加值,因为您必须将该时钟分频至1 kHz,以便进行时隙计数。

相反,请考虑编码器信号的最大频率。您可能希望至少以该频率的两倍进行过采样,使该频率翻两倍才能安全。所以每个“位时间”有四个样本。

由于您期望1 kHz处有许多边缘,我认为您的编码器至少快两个数量级,即100 kHz。因此,将40 Mhz降至400 kHz,并在QEPA中进行调整以进行去抖动。对这些时隙测量采样400 kHz至1 kHz。

旁注:哪种电机编码只使用一位?你确定你没有处理正交编码器吗?