所以我最近开始学习VHDL作为大学实习的一部分。 这次,我们的任务是创建一个摩尔机器,您可以在该机器上以某种方式设置时间并将其用作倒计时,一旦达到0就触发警报。
启动状态为“空闲”,如果按“keySet_in”,可以通过按“keyUp_in”增加分钟来设置分钟,或者按“keyDown_in”减少分钟。 如果您按任何其他键,倒计时将转到“开始”并以默认值1分钟开始。还有LED可以控制时钟上的小数点和数字的高亮显示。那些并不重要,并且尽我所能地工作。
从分钟选择中,您可以通过按“keyRight_in”到达第二个计数器的第一个/第二个数字。您可以按照与分钟相同的方式增加/减少它。 一旦达到较小的数值,如果你再次“keyRight_in”,你就会开始。 除非你在几分钟内,否则你总是可以使用keyLeft_in返回,在这种情况下它什么都不做。
如果在倒计时期间按任意键,倒计时将取消并重置为前一个值的空闲状态。如果它达到0,警报将一直播放,直到您按下按钮然后您将返回空闲状态。
现在我们尝试在FPGA上实现我的代码,并且有一些非常奇怪的错误行为,即使我们重写了整个代码并检查了一点点,我和老师都无法解释。现在这些老师也只是学生,所以我想他们的知识并不完美,也许这里的人可能会知道更多:
我们所拥有的一种奇怪的行为是(例如,从我的记忆中,可能不是100%准确)大多数按钮都不起作用。当试图增加/减少分钟时,它只会在9和8之间切换。当试图增加/减少更高的数字秒时,它总是一次需要2步(从9到7到5,......)。大多数其他按钮甚至没有反应,例如你可以不使用leftKey_in。 初始值是1分钟。我们也尝试了3种不同的FPGA。
从那以后,我想到了解决这些问题的两种(不太可能的)选择: 1.为流程P1添加敏感列表 2.添加'state< = idle; '作为初始值(包含在代码中)
所以我知道这是一个很长的文本墙,所以如果任何人仍在阅读,那么代码是: pastebin link(使用stackoverflow的代码有问题,所以我使用了pastebin)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.TIMER_PKG.ALL;
entity CONTROLLER is
port (
-- Clocks and Reset
sysclk_in : in std_logic;
clk10hz_in : in std_logic;
reset_in : in std_logic;
-- Alu
alu_instruction_out : out ALU_INSTRUCTION_TYPE;
timer_is_zero_in : in std_logic;
-- Key Controls
keyUp_in : in std_logic;
keyDown_in : in std_logic;
keyLeft_in : in std_logic;
keyRight_in : in std_logic;
keySet_in : in std_logic;
-- 7 Segment Display
disp_highlight_out : out std_logic_vector(3 downto 0);
disp_dots_out : out std_logic_vector(3 downto 0);
-- Alarm
alarm_out : out std_logic
);
end CONTROLLER;
architecture Behavioral of CONTROLLER is
type fsm_type is ( IDLE, START, WAIT10HZ, CNTDWN, TIMER_END, RESTORE,
SEL_MIN, INC_MIN, DEC_MIN,
SEL_SEC10, INC_sec10, DEC_SEC10,
SEL_SEC, INC_SEC, DEC_SEC);
signal state, next_state : fsm_type;
state <= idle;
begin
P1:process is begin
wait until rising_edge(sysclk_in);
state <= next_state;
end process;
P2:process(sysclk_in, reset_in, keyup_in, keydown_in, keyleft_in, keyright_in, keyset_in,
timer_is_zero_in) is begin
next_state <= state;
case state is
when IDLE =>
if (keyright_in or keyup_in or keydown_in or keyleft_in) = '1' then
next_state <= start;
elsif keyset_in = '1' then
next_state <= sel_min;
end if;
when Start =>
next_state <= wait10hz;
when wait10hz =>
if clk10hz_in = '1' then
next_state <= cntdwn;
end if;
when cntdwn =>
if timer_is_zero_in = '1' then
next_state <= timer_end;
elsif (keyright_in or keyup_in or keydown_in or keyleft_in or keyset_in) ='1' then
next_state <= restore;
end if;
when restore =>
next_state <= start;
when timer_end =>
if (keyright_in or keyup_in or keydown_in or keyleft_in or keyset_in) ='1' then
next_state <= idle;
end if;
when sel_min =>
if keyup_in = '1' then
next_state <= inc_min;
elsif keydown_in ='1' then
next_state <= dec_min;
elsif keyright_in ='1' then
next_state <= sel_sec10;
end if;
when sel_sec10 =>
if keyleft_in = '1' then
next_state <= sel_min;
elsif keyright_in ='1' then
next_state <= sel_sec;
elsif keyup_in = '1' then
next_state <= inc_sec10;
elsif keydown_in = '1' then
next_state <= dec_sec10;
end if;
when sel_sec=>
if keyleft_in ='1' then
next_state <= sel_sec10;
elsif keyright_in ='1' then
next_state <= start;
elsif keydown_in ='1' then
next_state <= dec_sec;
elsif keyup_in ='1' then
next_state <= inc_sec;
end if;
when inc_min =>
next_state <= sel_min;
when dec_min =>
next_state <= sel_min;
when inc_sec10 =>
next_state <= sel_sec10;
when dec_sec10 =>
next_state <= sel_sec10;
when inc_sec =>
next_state <= sel_sec;
when dec_sec =>
next_state <= sel_sec;
when others => null;
end case;
if reset_in = '1' then
next_state <= idle;
end if;
disp_highlight_out <= "1111";
disp_dots_out <= "0101";
alarm_out <= '0';
alu_instruction_out <= alu_none;
case state is
when start =>
alu_instruction_out <= alu_store;
disp_highlight_out <= "1111";
disp_dots_out <= "0101";
when idle =>
alu_instruction_out <= alu_none;
disp_highlight_out <= "1111";
disp_dots_out <= "0101";
alarm_out <= '0';
when wait10hz =>
alu_instruction_out <= alu_none;
disp_highlight_out <= "1111";
disp_dots_out <= "0101";
when cntdwn =>
alu_instruction_out <= alu_dec_timer;
disp_highlight_out <= "1111";
disp_dots_out <= "0101";
when timer_end =>
alu_instruction_out <= alu_store;
disp_highlight_out <= "1111";
disp_dots_out <= "0101";
alarm_out <= '1';
when sel_min =>
alu_instruction_out <= alu_none;
disp_highlight_out <= "1000";
disp_dots_out <= "0101";
when inc_min =>
alu_instruction_out <= alu_single_inc_min;
disp_highlight_out <= "1000";
disp_dots_out <= "0101";
when dec_min =>
alu_instruction_out <= alu_single_dec_min;
disp_highlight_out <= "1000";
disp_dots_out <= "0101";
when sel_sec10 =>
alu_instruction_out <= alu_none;
disp_highlight_out <= "0100";
disp_dots_out <= "0101";
when dec_sec10 =>
alu_instruction_out <= alu_single_dec_sec10;
disp_highlight_out <= "0100";
disp_dots_out <= "0101";
when inc_sec10 =>
alu_instruction_out <= alu_single_inc_sec10;
disp_highlight_out <= "0100";
disp_dots_out <= "0101";
when dec_sec =>
alu_instruction_out <= alu_single_dec_sec;
disp_highlight_out <= "0010";
disp_dots_out <= "0101";
when inc_sec =>
alu_instruction_out <= alu_single_inc_sec;
disp_highlight_out <= "0010";
disp_dots_out <= "0101";
when sel_sec =>
alu_instruction_out <= alu_none;
disp_highlight_out <= "0010";
disp_dots_out <= "0101";
when others =>
alu_instruction_out <= alu_none;
end case;
end process;
end Behavioral;
希望有人可以帮忙! 迎接
答案 0 :(得分:1)
虽然可以实现2进程状态机,但是更难以阅读和管理。
但是,如果您使用2个流程,那么: - 第一个进程是时钟(就像你的P1一样) - 第二个过程在灵敏度列表中使用了所有输入。您的P2在灵敏度列表中没有“clk_10hz_in”且没有“状态”信号。但是您在灵敏度列表中有“sysclk_in”,它不用作组合P2中的输入。
- &GT;如果不同信号在(几乎)同时改变电平(例如sysclk_in和其他信号),这可能会导致意外行为。