我们正在尝试为机器人构建一个控制器,它可以执行两个不同的任务,搜索一条线并跟踪一条线。 (我们使用三个光敏电阻来检测地面上绘制的线。)我们的想法是创建一个fsm moore机器,然而它只使用一种类型的状态更新。其原因是每个状态需要在20ms后进入复位状态,以便更新否则将无法工作的其他组件。为了回到原始状态,我们使用一个额外的状态序列作为输入,以便摩尔机器知道返回的位置。 (可能有助于知道将代码简化为仅跟踪线路工作完美,也在现实生活中实现。)
奇怪的是,在ModelSim上模拟的代码完美无瑕,一切都是连接的等等,但在实现时,我们得到了十几个警告,提到了锁存器的存在(关于另外两个状态序列new_eureka和new_StoredValue) ,这完全搞砸了我们的业务。然而,看看代码,我们无法真正找到为什么生产这些锁存器。 我们怎样才能避免这些闩锁出现?
代码和Quartus软件产生的警告。
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity LineFinder is
port ( clk : in std_logic;
reset : in std_logic;
count_out : in std_logic_vector(19 downto 0);
sensor_l_out : in std_logic;
sensor_m_out : in std_logic;
sensor_r_out : in std_logic;
pwm_l_reset : out std_logic;
pwm_l_direction : out std_logic;
pwm_r_reset : out std_logic;
pwm_r_direction : out std_logic;
count_reset: out std_logic
);
end entity LineFinder;
architecture behaviour of LineFinder is
component input_buffer is
port ( clk : in std_logic;
sensor_l_in : in std_logic;
sensor_m_in : in std_logic;
sensor_r_in : in std_logic;
sensor_l_out : out std_logic;
sensor_m_out : out std_logic;
sensor_r_out : out std_logic
);
end component input_buffer;
type line_state is (reset_state,
FindLine_state,
PassLine_state,
CorrectLeft_state,
CorrectRight_state,
wbw_state,
bbb_state,
bbw_state,
bwb_state,
bww_state,
wbb_state,
wwb_state,
www_state);
signal state , new_state: line_state ;
type eureka_state is (FindingLine,
PassingLine,
CorrectingRight,
CorrectingLeft,
TrackingLine);
signal eureka, new_eureka: eureka_state;
signal StoredValue, new_StoredValue: std_logic_vector(2 downto 0) := "000";
constant period: std_logic_vector(19 downto 0) := std_logic_vector (to_unsigned(1000000, 20));
begin
Process1: process (clk, reset)
begin
if (rising_edge(clk)) then
if (reset ='1') then
state <= FindLine_state;
eureka <= FindingLine;
StoredValue <= "000";
else
state <= new_state;
eureka <= new_eureka;
StoredValue <= new_StoredValue;
end if;
end if;
end process;
--Finding Line process
Process2: process (state, eureka, StoredValue, count_out, sensor_l_out, sensor_m_out, sensor_r_out)
begin
if ((not((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0'))) and (eureka = PassingLine)) then
new_StoredValue <= sensor_r_out & sensor_m_out & sensor_l_out;
end if;
case state is
when FindLine_state =>
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= FindingLine;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
new_state <= FindLine_state;
new_eureka <= FindingLine;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= TrackingLine;
else
new_state <= PassLine_state;
new_eureka <= PassingLine;
end if;
when PassLine_state =>
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= PassingLine;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
if ((StoredValue = "001") or (StoredValue = "011")) then
new_state <= CorrectRight_state;
new_eureka <= CorrectingRight;
else
new_state <= CorrectLeft_state;
new_eureka <= CorrectingLeft;
end if;
else
new_state <= PassLine_state;
new_eureka <= PassingLine;
end if;
when CorrectRight_state =>
pwm_l_reset <= '0'; --making sharp turn to right
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '1';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= CorrectingRight;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= TrackingLine;
else
new_state <= CorrectRight_state;
new_eureka <= CorrectingRight;
end if;
when CorrectLeft_state =>
pwm_l_reset <= '0'; --making sharp turn to left
pwm_r_reset <= '0';
pwm_l_direction <= '0';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= CorrectingLeft;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= TrackingLine;
else
new_state <= CorrectLeft_state;
new_eureka <= CorrectingLeft;
end if;
when wbw_state => --aka LineFoundState
-- go to LineTracker process!
-- forward trigger
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= wbw_state;
new_eureka <= TrackingLine;
end if;
when reset_state =>
pwm_l_reset <= '1';
pwm_r_reset <= '1';
pwm_l_direction <= '1';
pwm_r_direction <= '1';
count_reset <= '1';
if (not(eureka = TrackingLine)) then
if (eureka = FindingLine) then
new_state <= FindLine_state;
new_eureka <= FindingLine;
elsif (eureka = PassingLine) then
new_state <= PassLine_state;
new_eureka <= PassingLine;
elsif (eureka = CorrectingRight) then
new_state <= CorrectRight_state;
new_eureka <= CorrectingRight;
elsif (eureka = CorrectingLeft) then
new_state <= CorrectLeft_state;
new_eureka <= CorrectingLeft;
else
new_state <= FindLine_state; --do we need this?
new_eureka <= FindingLine;
end if;
else
--The other reset process
if ((sensor_l_out = '1') and (sensor_m_out ='1') and (sensor_r_out = '1')) then
new_state <= bbb_state;
elsif ((sensor_l_out = '1') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= bbw_state;
elsif ((sensor_l_out = '1') and (sensor_m_out ='0') and (sensor_r_out = '1')) then
new_state <= bwb_state;
elsif ((sensor_l_out = '1') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
new_state <= bww_state;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '1')) then
new_state <= wbb_state;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '1')) then
new_state <= wwb_state;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
new_state <= www_state;
else
new_state <= reset_state;
end if;
end if;
when bbb_state => -- forward
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bbb_state;
new_eureka <= TrackingLine;
end if;
when bbw_state => -- right turn
pwm_l_reset <= '0';
pwm_r_reset <= '1';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bbw_state;
new_eureka <= TrackingLine;
end if;
when bwb_state => -- forward trigger
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bwb_state;
new_eureka <= TrackingLine;
end if;
when bww_state => -- right sharp turn
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '1';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bww_state;
new_eureka <= TrackingLine;
end if;
when wbb_state => -- left turn
pwm_l_reset <= '1';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= wbb_state;
new_eureka <= TrackingLine;
end if;
when wwb_state => -- left sharp turn
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '0';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= wwb_state;
new_eureka <= TrackingLine;
end if;
when www_state => -- forward search
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= FindingLine;
else
new_state <= www_state;
new_eureka <= TrackingLine;
end if;
end case;
end process;
end architecture behaviour;
警告:
Warning (18236): Number of processors has not been specified which may cause overloading on shared machines. Set the global assignment NUM_PARALLEL_PROCESSORS in your QSF to an appropriate value for best performance.
Warning (10631): VHDL Process Statement warning at LineFinder.vhdl(84): inferring latch(es) for signal or variable "new_StoredValue", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at LineFinder.vhdl(84): inferring latch(es) for signal or variable "new_eureka", which holds its previous value in one or more paths through the process
Warning (13012): Latch LineFinder:lbl1|new_eureka.TrackingLine_445 has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal LineFinder:lbl1|state.reset_state
Warning (13012): Latch LineFinder:lbl1|new_eureka.CorrectingRight_463 has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal LineFinder:lbl1|state.reset_state
Warning (13012): Latch LineFinder:lbl1|new_StoredValue[0] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal input_buffer:lbl0|ThreeBitRegister:lbl1|data_out[2]
Warning (13012): Latch LineFinder:lbl1|new_StoredValue[2] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal input_buffer:lbl0|ThreeBitRegister:lbl1|data_out[0]
Warning (13012): Latch LineFinder:lbl1|new_eureka.PassingLine_472 has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal LineFinder:lbl1|state.reset_state
Warning (13012): Latch LineFinder:lbl1|new_eureka.FindingLine_481 has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal LineFinder:lbl1|state.reset_state
Warning (13012): Latch LineFinder:lbl1|new_eureka.CorrectingLeft_454 has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal LineFinder:lbl1|state.reset_state
Warning (18236): Number of processors has not been specified which may cause overloading on shared machines. Set the global assignment NUM_PARALLEL_PROCESSORS in your QSF to an appropriate value for best performance.
Warning (292013): Feature LogicLock is only available with a valid subscription license. You can purchase a software subscription to gain full access to this feature.
Warning (15714): Some pins have incomplete I/O assignments. Refer to the I/O Assignment Warnings report for details
Warning (335093): TimeQuest Timing Analyzer is analyzing 7 combinational loops as latches. For more details, run the Check Timing command in the TimeQuest Timing Analyzer or view the "User-Specified and Inferred Latches" table in the Analysis & Synthesis report.
Warning (18236): Number of processors has not been specified which may cause overloading on shared machines. Set the global assignment NUM_PARALLEL_PROCESSORS in your QSF to an appropriate value for best performance.
Warning (18236): Number of processors has not been specified which may cause overloading on shared machines. Set the global assignment NUM_PARALLEL_PROCESSORS in your QSF to an appropriate value for best performance.
Warning (335093): TimeQuest Timing Analyzer is analyzing 7 combinational loops as latches. For more details, run the Check Timing command in the TimeQuest Timing Analyzer or view the "User-Specified and Inferred Latches" table in the Analysis & Synthesis report.
Warning (18236): Number of processors has not been specified which may cause overloading on shared machines. Set the global assignment NUM_PARALLEL_PROCESSORS in your QSF to an appropriate value for best performance.
Warning (10905): Generated the EDA functional simulation netlist because it is the only supported netlist type for this device.
答案 0 :(得分:1)
事实上,正如A. Kieffer的评论部分所述,我没有在所有情况下(特别是在重置状态下)指定new_StoredValue或new_eureka是什么。然后由锁存器引入该决策,提供不需要的行为。
下面的更正代码成功避免了锁存器的创建。
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity LineFinder is
port ( clk : in std_logic;
reset : in std_logic;
count_out : in std_logic_vector(19 downto 0);
sensor_l_out : in std_logic;
sensor_m_out : in std_logic;
sensor_r_out : in std_logic;
pwm_l_reset : out std_logic;
pwm_l_direction : out std_logic;
pwm_r_reset : out std_logic;
pwm_r_direction : out std_logic;
count_reset: out std_logic
);
end entity LineFinder;
architecture behaviour of LineFinder is
component input_buffer is
port ( clk : in std_logic;
sensor_l_in : in std_logic;
sensor_m_in : in std_logic;
sensor_r_in : in std_logic;
sensor_l_out : out std_logic;
sensor_m_out : out std_logic;
sensor_r_out : out std_logic
);
end component input_buffer;
type line_state is (reset_state,
FindLine_state,
PassLine_state,
CorrectLeft_state,
CorrectRight_state,
wbw_state,
bbb_state,
bbw_state,
bwb_state,
bww_state,
wbb_state,
wwb_state,
www_state);
signal state , new_state: line_state ;
type eureka_state is (FindingLine,
PassingLine,
CorrectingRight,
CorrectingLeft,
TrackingLine);
signal eureka, new_eureka: eureka_state;
signal StoredValue, new_StoredValue: std_logic_vector(2 downto 0) := "000";
constant period: std_logic_vector(19 downto 0) := std_logic_vector (to_unsigned(1000000, 20));
begin
Process1: process (clk, reset)
begin
if (rising_edge(clk)) then
if (reset ='1') then
state <= FindLine_state;
eureka <= FindingLine;
StoredValue <= "000";
else
state <= new_state;
eureka <= new_eureka;
StoredValue <= new_StoredValue;
end if;
end if;
end process;
--Finding Line process
Process2: process (state, eureka, StoredValue, count_out, sensor_l_out, sensor_m_out, sensor_r_out)
begin
if ((not((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0'))) and (eureka = PassingLine)) then
new_StoredValue <= sensor_r_out & sensor_m_out & sensor_l_out;
else
new_StoredValue <= StoredValue;
end if;
case state is
when FindLine_state =>
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= FindingLine;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
new_state <= FindLine_state;
new_eureka <= FindingLine;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= TrackingLine;
else
new_state <= PassLine_state;
new_eureka <= PassingLine;
end if;
when PassLine_state =>
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= PassingLine;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
if ((StoredValue = "001") or (StoredValue = "011")) then
new_state <= CorrectRight_state;
new_eureka <= CorrectingRight;
else
new_state <= CorrectLeft_state;
new_eureka <= CorrectingLeft;
end if;
else
new_state <= PassLine_state;
new_eureka <= PassingLine;
end if;
when CorrectRight_state =>
pwm_l_reset <= '0'; --making sharp turn to right
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '1';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= CorrectingRight;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= TrackingLine;
else
new_state <= CorrectRight_state;
new_eureka <= CorrectingRight;
end if;
when CorrectLeft_state =>
pwm_l_reset <= '0'; --making sharp turn to left
pwm_r_reset <= '0';
pwm_l_direction <= '0';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= CorrectingLeft;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= TrackingLine;
else
new_state <= CorrectLeft_state;
new_eureka <= CorrectingLeft;
end if;
when wbw_state => --aka LineFoundState
-- go to LineTracker process!
-- forward trigger
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= wbw_state;
new_eureka <= TrackingLine;
end if;
when reset_state =>
pwm_l_reset <= '1';
pwm_r_reset <= '1';
pwm_l_direction <= '1';
pwm_r_direction <= '1';
count_reset <= '1';
if (not(eureka = TrackingLine)) then
if (eureka = FindingLine) then
new_state <= FindLine_state;
new_eureka <= FindingLine;
elsif (eureka = PassingLine) then
new_state <= PassLine_state;
new_eureka <= PassingLine;
elsif (eureka = CorrectingRight) then
new_state <= CorrectRight_state;
new_eureka <= CorrectingRight;
elsif (eureka = CorrectingLeft) then
new_state <= CorrectLeft_state;
new_eureka <= CorrectingLeft;
else
new_state <= FindLine_state; --do we need this?
new_eureka <= FindingLine;
end if;
else
--The other reset process
if ((sensor_l_out = '1') and (sensor_m_out ='1') and (sensor_r_out = '1')) then
new_state <= bbb_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '1') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= bbw_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '1') and (sensor_m_out ='0') and (sensor_r_out = '1')) then
new_state <= bwb_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '1') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
new_state <= bww_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '1')) then
new_state <= wbb_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '0') and (sensor_m_out ='1') and (sensor_r_out = '0')) then
new_state <= wbw_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '1')) then
new_state <= wwb_state;
new_eureka <= eureka;
elsif ((sensor_l_out = '0') and (sensor_m_out ='0') and (sensor_r_out = '0')) then
new_state <= www_state;
new_eureka <= eureka;
else
new_state <= reset_state;
new_eureka <= eureka;
end if;
end if;
when bbb_state => -- forward
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bbb_state;
new_eureka <= TrackingLine;
end if;
when bbw_state => -- right turn
pwm_l_reset <= '0';
pwm_r_reset <= '1';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bbw_state;
new_eureka <= TrackingLine;
end if;
when bwb_state => -- forward trigger
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bwb_state;
new_eureka <= TrackingLine;
end if;
when bww_state => -- right sharp turn
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '1';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= bww_state;
new_eureka <= TrackingLine;
end if;
when wbb_state => -- left turn
pwm_l_reset <= '1';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= wbb_state;
new_eureka <= TrackingLine;
end if;
when wwb_state => -- left sharp turn
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '0';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= TrackingLine;
else
new_state <= wwb_state;
new_eureka <= TrackingLine;
end if;
when www_state => -- forward search
pwm_l_reset <= '0';
pwm_r_reset <= '0';
pwm_l_direction <= '1';
pwm_r_direction <= '0';
count_reset <= '0';
if (count_out >= period) then
new_state <= reset_state;
new_eureka <= FindingLine;
else
new_state <= www_state;
new_eureka <= TrackingLine;
end if;
end case;
end process;
end architecture behaviour;