VHDL状态机COUNT_OUT输出始终为0,仿真观测异常求助
正交编码器计数器FSM的问题分析与解决
一、COUNT_OUT始终为0的根本原因
你的代码存在两个核心问题,直接导致count信号无法正常更新,进而COUNT_OUT输出始终为0:
1. 多进程驱动同一个信号(非法操作)
信号count被两个进程同时赋值:
SYNC_PROC时序进程(时钟上升沿触发)中,当z='1'时会给count赋0;NEXT_STATE_DECODE组合逻辑进程(敏感列表触发)中,在各个状态分支里对count做赋值/增减操作。
VHDL中,非resolved类型的信号不允许被多个进程驱动,unsigned属于非resolved类型,这种冲突会导致信号值异常,仿真中通常会保持初始值(0),综合时会直接报错。
2. 计数逻辑的时序设计错误
正交编码器的计数更新必须是同步时序逻辑,你现在把count的增减放在组合逻辑进程里,不仅会引发多驱动问题,还会引入亚稳态、毛刺等风险,不符合FPGA同步设计的基本原则。
二、代码修正方案
重构代码,将count的更新完全移到同步进程中,组合逻辑进程只负责生成状态转移和计数控制信号:
修正后的核心代码示例
-- 新增计数控制信号,用于组合逻辑给时序进程传递计数指令 signal en_count : std_logic; signal up_down : std_logic; SYNC_PROC: process(CLK) begin if rising_edge(CLK) then if (z='1') then state <= S00; count <= (others=>'0'); else state <= next_state; -- 同步更新count,仅在计数使能有效时操作 if en_count = '1' then if up_down = '1' then count <= count + 1; else count <= count - 1; end if; end if; end if; end if; end process; NEXT_STATE_DECODE: process(state, A, B) begin -- 给所有输出信号加默认赋值,避免组合逻辑锁存 next_state <= state; en_count <= '0'; up_down <= '0'; case state is when S00 => if(A = '0' and B = '1') then next_state <= S01; elsif(A = '1' and B = '0') then next_state <= S10; end if; when S01 => if(A = '1' and B = '1') then next_state <= S11; elsif(A = '0' and B = '0') then next_state <= S00; end if; when S11 => if(A = '1' and B = '0') then en_count <= '1'; up_down <= '0'; -- 计数减1 next_state <= S10; elsif(A = '0' and B = '1') then en_count <= '1'; up_down <= '1'; -- 计数加1 next_state <= S01; end if; when S10 => if(A = '0' and B = '0') then en_count <= '1'; up_down <= '0'; -- 计数减1 next_state <= S00; elsif(A = '1' and B = '1') then en_count <= '1'; up_down <= '1'; -- 计数加1 next_state <= S11; end if; end case; end process; -- COUNT_OUT直接同步输出count COUNT_OUT <= count;
修正要点说明
- 将
count的更新完全移到SYNC_PROC时序进程中,彻底解决多驱动问题; - 组合逻辑进程仅负责生成状态转移指令和计数控制信号(
en_count控制是否计数,up_down控制加减方向); - 组合逻辑进程中给所有输出信号添加默认赋值,避免出现组合逻辑锁存(FPGA设计的基本规范);
- 移除原组合进程中对
count的所有赋值,确保信号驱动唯一。
三、仿真无法观测内部信号的解决方法
针对state、next_state、count无法在仿真中观测的问题,按以下步骤处理:
使用行为级仿真(前仿真)
不要使用综合后仿真(门级仿真),因为综合工具会优化掉未被直接输出的内部信号。行为级仿真直接基于VHDL代码,能完整保留所有内部信号。手动添加信号到波形窗口
以Vivado仿真为例:- 运行仿真后,在左侧Scope窗口找到
GPIO_demo模块,展开后即可看到state、next_state、count等内部信号; - 选中目标信号,右键选择Add to Waveform,即可在波形窗口观测。
- 运行仿真后,在左侧Scope窗口找到
添加属性强制保留信号
如果行为级仿真中仍看不到信号,可以在信号定义时添加keep属性,强制工具保留信号:type state_type is (S00, S01, S10, S11); signal state, next_state: state_type; attribute keep : boolean; attribute keep of state : signal is true; attribute keep of next_state : signal is true; signal count: unsigned(11 downto 0) := (others=>'0'); attribute keep of count : signal is true;
内容的提问来源于stack exchange,提问作者Wally
相关产品推荐
相关产品推荐

