VHDL电梯控制代码przybycie抵达信号晚1个时钟周期故障排查
VHDL电梯控制抵达信号时序异常问题
- 开发场景:基于VHDL编写电梯控制代码,用于指示电梯抵达所选楼层的信号
przybycie存在时序异常,拉高时机比预期晚1个时钟周期。 - 预期逻辑:楼层计数器
licznik_pieter计数到目标楼层值pietro时,przybycie信号立刻拉高。 - 实际现象:
przybycie在计数器值匹配目标楼层后,延迟1个时钟周期才输出高电平。
问题对应源代码
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.ALL; use IEEE.std_logic_unsigned.ALL; entity winda is port (clk : in std_logic; pietro : in std_logic_vector(2 downto 0); -- 楼层按键输入 alarm : in std_logic; numer_pietra : out std_logic_vector(2 downto 0); koniec : out std_logic); end entity winda; architecture winda_arch of winda is type STANY is (otwarcie_drzwi,spoczynek, wybor_pietra, zamkniecie_drzwi, praca_windy, koniec_pracy); signal stan, stan_nast: STANY; signal licznik_pieter: std_logic_vector(2 downto 0) :="000"; signal drzwi: std_logic; -- 0=开门, 1=关门 signal przybycie: std_logic :='0'; -- 抵达所选楼层指示信号 signal otwarciozamkniecie: std_logic :='0'; -- 开关门动作指示信号 begin reg:process(clk, alarm) begin if (alarm = '1') then stan <= spoczynek; elsif rising_edge(clk) then stan <= stan_nast; end if; end process reg; komb:process(clk, alarm, stan) begin stan_nast <= stan; case stan is when otwarcie_drzwi => stan_nast <= spoczynek; when spoczynek => stan_nast <= wybor_pietra; when wybor_pietra => if (pietro /= licznik_pieter) then stan_nast <= zamkniecie_drzwi; else stan_nast <= wybor_pietra; end if; when zamkniecie_drzwi => stan_nast <= praca_windy; when praca_windy => if (pietro = licznik_pieter) then stan_nast <= koniec_pracy; else stan_nast <= praca_windy; end if; when koniec_pracy => stan_nast <= otwarcie_drzwi; when others => stan_nast <= spoczynek; end case; end process komb; drzwi<= '1' when stan = praca_windy or stan = zamkniecie_drzwi or stan = koniec_pracy else '0'; otwarciozamkniecie <= '1' when stan = zamkniecie_drzwi or stan = otwarcie_drzwi else '0'; licznik:process(clk,alarm,przybycie,pietro,otwarciozamkniecie) begin if (alarm = '1' or drzwi = '0' or otwarciozamkniecie = '1') then przybycie <= '0'; elsif (rising_edge(clk)) then if (stan = praca_windy) then if (licznik_pieter = pietro) then przybycie <= '1'; elsif ( licznik_pieter > pietro ) then przybycie <= '0'; licznik_pieter <= licznik_pieter - "01"; else przybycie <= '0'; licznik_pieter <= licznik_pieter + "01"; end if; end if; end if; end process licznik; koniec <= '1' when stan = koniec_pracy or stan = spoczynek else '0'; numer_pietra <= licznik_pieter when drzwi = '0' else "000"; end architecture winda_arch;
核心逻辑错误说明
przybycie被错误放在同步时序进程中赋值,天然存在时钟延迟
当前przybycie的所有赋值逻辑都放在时钟沿触发的licznik进程内,只有时钟上升沿到来时才会判断条件、更新信号值,同步逻辑的输出必然比输入条件的变化晚1个时钟周期,不可能实现"计数到目标值立刻拉高"的即时响应效果。
同时进程内判断顺序错误:时钟沿到来时,先判断当前计数值是否匹配目标楼层,不匹配才更新计数值。这意味着计数值更新到和目标值相等的那个时钟沿,不会触发przybycie拉高,必须等下一个时钟沿到来、再次判断匹配时才会拉高,正好对应观测到的1周期延迟。组合进程敏感列表不完整,存在隐式延迟风险
用于生成次态stan_nast的组合逻辑进程komb,敏感列表仅包含clk、alarm、stan三个信号,但进程内部读取了pietro和licznik_pieter信号。这两个信号变化时,组合逻辑不会立刻更新输出,会导致状态跳转滞后,进一步加剧时序异常。
修正方法
- 将
przybycie改为组合逻辑赋值,从同步时钟进程中移除:
在架构的并行赋值区域新增语句,删除licznik进程中所有对przybycie的赋值:
改完后只要电梯处于运行状态、计数值等于目标楼层,przybycie <= '1' when (stan = praca_windy and licznik_pieter = pietro) else '0';przybycie就会立刻拉高,不存在时钟延迟。 - 补全组合进程敏感列表,将
pietro、licznik_pieter加入komb进程的敏感列表;如果使用VHDL-2008及以上版本,可直接写process(all)自动补全敏感列表,避免漏写导致的逻辑错误。 - 如果需要
przybycie作为同步信号使用,可调整licznik进程内的判断顺序:时钟沿到来时先更新计数器值,再用更新后的值判断是否抵达目标楼层,可消除1周期的判断延迟,但输出仍然和计数器同步在时钟沿后更新,无法实现零延迟的即时响应。
内容的提问来源于stack exchange,提问作者Saran12
相关产品推荐
相关产品推荐

