VHDL中信号顺序更新功能实现问题求助
问题分析与解决方案
问题根源
你的代码存在两个核心问题,导致所有信号同时变为Dec_in的值:
- 组合逻辑而非时序逻辑:当前
process仅以BP_in为敏感信号,属于组合逻辑。当BP_in为高电平时,赋值语句会持续执行,而组合逻辑中信号赋值是即时生效的,最终Num0=Dec_in、Num1=Num0=Dec_in、Num2=Num1=Dec_in,所有信号值自然一致。 - 电平触发而非边沿触发:按键按下是瞬间的上升沿事件,但你用了电平检测。如果
BP_in保持高电平(比如按键按住不放),process会反复触发,进一步加剧信号覆盖问题。
另外,实际硬件中按键存在机械抖动,直接检测边沿会导致多次误触发,这也是需要解决的问题。
修正后的代码
我们需要将逻辑改为时序逻辑,引入FPGA的时钟信号,检测BP_in的上升沿(按键按下的瞬间),同时添加按键消抖逻辑(实际硬件必加):
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity NumShift is port( Clk : in std_logic; -- FPGA时钟(例如50MHz) Dec_in : in std_logic_vector(3 downto 0); BP_in : in std_logic; Num0 : out std_logic_vector(3 downto 0); Num1 : out std_logic_vector(3 downto 0); Num2 : out std_logic_vector(3 downto 0) ); end entity NumShift; architecture Behavioral of NumShift is signal bp_sync : std_logic_vector(1 downto 0); -- 按键同步寄存器 signal bp_edge : std_logic; -- 按键上升沿标志 signal debounce_cnt : unsigned(19 downto 0) := (others => '0'); -- 消抖计数器 signal bp_stable : std_logic := '0'; -- 消抖后的稳定按键信号 -- 内部移位寄存器 signal num0_reg : std_logic_vector(3 downto 0) := (others => '0'); signal num1_reg : std_logic_vector(3 downto 0) := (others => '0'); signal num2_reg : std_logic_vector(3 downto 0) := (others => '0'); begin -- 1. 按键同步:解决异步按键的跨时钟域问题 process(Clk) begin if rising_edge(Clk) then bp_sync <= bp_sync(0) & BP_in; end if; end process; -- 2. 按键消抖:检测稳定的高电平(20ms@50MHz) process(Clk) begin if rising_edge(Clk) then if bp_sync(1) /= bp_stable then debounce_cnt <= (others => '0'); elsif debounce_cnt /= x"F4240" then -- 对应1e6个时钟周期 debounce_cnt <= debounce_cnt + 1; else bp_stable <= bp_sync(1); end if; end if; end process; -- 3. 检测消抖后的按键上升沿 process(Clk) begin if rising_edge(Clk) then bp_edge <= bp_stable and not bp_sync(1); end if; end process; -- 4. 移位逻辑:仅在按键上升沿触发时执行移位 process(Clk) begin if rising_edge(Clk) then if bp_edge = '1' then num2_reg <= num1_reg; num1_reg <= num0_reg; num0_reg <= Dec_in; end if; end if; end process; -- 输出赋值 Num0 <= num0_reg; Num1 <= num1_reg; Num2 <= num2_reg; end architecture Behavioral;
关键修改说明
- 引入时钟信号:所有逻辑在时钟上升沿执行,变为时序逻辑,信号赋值会在下一个时钟周期更新,保证移位顺序正确(
Num2取更新前的Num1,Num1取更新前的Num0,Num0取新的Dec_in)。 - 按键同步与消抖:解决异步按键的跨时钟域问题,避免抖动导致的多次误触发。
- 边沿触发:仅在按键按下的上升沿(消抖后)执行移位操作,不会因按键按住不放而反复触发。
- 内部寄存器替代buffer端口:用内部寄存器存储移位状态,输出端口改为
out模式,更符合VHDL设计规范。
简化验证版(无消抖)
如果仅用于验证移位逻辑,可使用以下简化代码(实际硬件仍建议添加消抖):
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity NumShift is port( Clk : in std_logic; Dec_in : in std_logic_vector(3 downto 0); BP_in : in std_logic; Num0 : out std_logic_vector(3 downto 0); Num1 : out std_logic_vector(3 downto 0); Num2 : out std_logic_vector(3 downto 0) ); end entity NumShift; architecture Behavioral of NumShift is signal bp_prev : std_logic := '0'; signal num0_reg : std_logic_vector(3 downto 0) := (others => '0'); signal num1_reg : std_logic_vector(3 downto 0) := (others => '0'); signal num2_reg : std_logic_vector(3 downto 0) := (others => '0'); begin process(Clk) begin if rising_edge(Clk) then bp_prev <= BP_in; -- 检测BP_in的上升沿 if BP_in = '1' and bp_prev = '0' then num2_reg <= num1_reg; num1_reg <= num0_reg; num0_reg <= Dec_in; end if; end if; end process; Num0 <= num0_reg; Num1 <= num1_reg; Num2 <= num2_reg; end architecture Behavioral;
内容的提问来源于stack exchange,提问作者liampcas
相关产品推荐
相关产品推荐

