Мы пытаемся создать контроллер для робота, способного выполнять две разные задачи: поиск линии и отслеживание линии. (Мы используем три светорезистора для обнаружения линии, проведенной на земле.) Идея состояла в том, чтобы создать fsm машину Мура, которая, однако, использует вместо одного типа обновления состояния несколько. Причина этого в том, что каждое состояние должно переходить в состояние сброса через 20 мс, чтобы обновить другие компоненты, которые в противном случае не будут работать. Чтобы вернуться в исходное состояние, мы используем дополнительную последовательность состояний, которая используется в качестве входных данных, чтобы машина Мура знала, куда вернуться. (Возможно, полезно знать, что сокращение кода только до отслеживания строки работает отлично, что также реализовано в реальной жизни.)
Странно то, что смоделированный на 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.
process2
. Пример 1:new_StoredValue
не задается оператором else в начале процесса. Пример 2: то же самое дляnew_eureka
в состоянииreset_state
. Вам необходимо указать статус всех ваших сигналов во всех возможных состояниях. В противном случае, чтобы избежать этого, вы можете использовать только синхронизированные процессы. - person A. Kieffer   schedule 15.12.2016