Мы пытаемся создать контроллер для робота, который может выполнять две различные задачи, искать линию и отслеживать линию. (Мы используем три светоизлучателя для обнаружения линии, нарисованной на земле.) Идея заключалась в создании машины fsm moore, которая, однако, использует вместо одного типа обновления состояния несколько. Причиной этого является то, что каждое состояние должно перейти в состояние сброса через 20 мс, чтобы обновить другие компоненты, которые в противном случае не будут работать. Чтобы вернуться в исходное состояние, мы используем дополнительную последовательность состояний, которая используется как вход для того, чтобы машина moore знала, куда возвращаться. (Это может помочь узнать, что сокращение кода только для отслеживания линии отлично работает, также реализовано в реальной жизни.)VHDL: FSM с несколькими типами состояний
Странно, что код, смоделированный на 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'. Example1: 'new_StoredValue' не управляется в инструкции else в начале процесса. Пример 2: тот же для 'new_eureka' в состоянии' reset_state'. Вам нужно указать статус всех ваших сигналов во всех возможных состояниях. В противном случае, чтобы избежать этого, вы можете использовать только синхронизированные процессы. –
Имейте в виду, что вы работаете с оборудованием, а не с программным обеспечением. Вам необязательно идти в состояние сброса, чтобы делать другие вещи, вы можете просто делать их параллельно. В этом и состоит преимущество пользовательского оборудования для цифровой логики. – QuantumRipple
True QuantumRipple, но в этом случае двигатели, которые мы работаем только в том случае, если система регулярно перезагружается, если вы не передадите интеллект контроллера на двигатели. Но это путаница вещей. – user3604362