Конечный автомат - без регистра сдвига
Вот что я получил. Я не понял ваш переход с S18 на S19. Мне кажется, что преамбула была обнаружена, когда она находится на этапе S18, поэтому нет необходимости в дополнительном переходе обнаружения. Я также разделил ваш S19 на 3 состояния, то есть S18, S19 и S20.
![State diagram without shift register](https://i.stack.imgur.com/x1yMp.png)
Конечный автомат - с регистром сдвига
Вот диаграмма состояний для сдвигового регистра, используемого для обнаружения последовательности преамбулы. S1 ожидает сдвиговый регистр для определения последовательности преамбулы.
![State diagram without shift register](https://i.stack.imgur.com/oqz0S.png)
VHDL Реализация FSM
![Synchronous State Machine](https://i.stack.imgur.com/geIQJ.png)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity StateMachineChallenge is
generic
(
NUM_STATES: natural := 5;
NUM_OUTPUTS: natural := 6
);
port
(
clock: in std_logic;
reset: in std_logic;
button: in std_logic;
found_preamble: in std_logic;
timer_a_timeout: in std_logic;
timer_b_timeout: in std_logic;
timer_c_timeout: in std_logic;
state: out natural range 0 to NUM_STATES := 0;
outputs: out std_logic_vector(NUM_OUTPUTS - 1 downto 0) := (others => '0')
);
end entity;
architecture V1 of StateMachineChallenge is
constant S0: natural range 0 to NUM_STATES := 0;
constant S1: natural range 0 to NUM_STATES := 1;
constant S2: natural range 0 to NUM_STATES := 2;
constant S3: natural range 0 to NUM_STATES := 3;
constant S4: natural range 0 to NUM_STATES := 4;
constant LED_OFF, FIND_PREAMBLE_OFF, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_OFF: std_logic := '0';
constant LED_ON, FIND_PREAMBLE_ON, TIMER_A_ON, TIMER_B_ON, TIMER_C_ON: std_logic := '1';
constant SERVO_POSITION_START: std_logic := '0'; -- 1.0 ms
constant SERVO_POSITION_90DEG: std_logic := '1'; -- 1.5 ms
type TOutputsTable is array(0 to NUM_STATES - 1) of std_logic_vector(NUM_OUTPUTS - 1 downto 0);
constant OUTPUTS_TABLE: TOutputsTable :=
(
-- LED, Find preamble, Servo position, Timer A run, Timer B run, Timer C run
(LED_OFF, FIND_PREAMBLE_OFF, SERVO_POSITION_START, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_ON, SERVO_POSITION_START, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_OFF, SERVO_POSITION_90DEG, TIMER_A_ON, TIMER_B_OFF, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_OFF, SERVO_POSITION_90DEG, TIMER_A_OFF, TIMER_B_ON, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_OFF, SERVO_POSITION_START, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_ON)
);
signal next_state: natural range 0 to NUM_STATES := S0;
signal next_outputs: std_logic_vector(NUM_OUTPUTS - 1 downto 0) := OUTPUTS_TABLE(S0);
begin
--
-- State register and outputs register.
--
process(clock, reset)
begin
if reset = '1' then
state <= S0;
outputs <= OUTPUTS_TABLE(S0);
elsif rising_edge(clock) then
state <= next_state;
outputs <= next_outputs;
end if;
end process;
--
-- Next state logic
--
process(reset, state, button, found_preamble, timer_a_timeout, timer_b_timeout, timer_c_timeout)
begin
if reset = '1' then
next_state <= S0;
else
case state is
when S0 => -- Reset
if button = '1' then
next_state <= S1;
else
next_state <= S0;
end if;
when S1 => -- Looking for preamble
if found_preamble then
next_state <= S2;
else
next_state <= S1;
end if;
when S2 => -- Moving servo to 90 degrees
if timer_a_timeout then
next_state <= S3;
else
next_state <= S2;
end if;
when S3 => -- Waiting for 10 seconds
if timer_b_timeout then
next_state <= S4;
else
next_state <= S3;
end if;
when S4 => -- Moving servo to start position
if timer_c_timeout then
next_state <= S0;
else
next_state <= S4;
end if;
when others =>
next_state <= S0;
end case;
end if;
end process;
--
-- Next outputs logic
--
process(reset, next_state)
begin
if reset = '1' then
next_outputs <= OUTPUTS_TABLE(S0);
else
next_outputs <= OUTPUTS_TABLE(next_state);
end if;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity TestBench is
end entity;
architecture V1 of TestBench is
constant SYS_CLOCK_FREQ: real := 100000000.0; -- Hz
constant SYS_CLOCK_PERIOD: time := 1.0 sec / SYS_CLOCK_FREQ;
signal halt_sys_clock: boolean := false;
signal sys_clock: std_logic;
signal reset: std_logic;
signal button: std_logic;
signal found_preamble: std_logic;
signal timer_a_timeout: std_logic;
signal timer_b_timeout: std_logic;
signal timer_c_timeout: std_logic;
constant NUM_STATES: natural := 5;
constant NUM_OUTPUTS: natural := 6;
signal state: natural range 0 to NUM_STATES;
signal outputs: std_logic_vector(NUM_OUTPUTS - 1 downto 0) := (others => '0');
signal led: std_logic;
signal find_preamble: std_logic;
signal servo_position: std_logic;
signal timer_a_enable: std_logic;
signal timer_b_enable: std_logic;
signal timer_c_enable: std_logic;
component StateMachineChallenge is
generic
(
NUM_STATES: natural := NUM_STATES;
NUM_OUTPUTS: natural := NUM_OUTPUTS
);
port
(
clock: in std_logic;
reset: in std_logic;
button: in std_logic;
found_preamble: in std_logic;
timer_a_timeout: in std_logic;
timer_b_timeout: in std_logic;
timer_c_timeout: in std_logic;
state: out natural range 0 to NUM_STATES := 0;
outputs: out std_logic_vector(NUM_OUTPUTS - 1 downto 0) := (others => '0')
);
end component;
begin
SysClockGenerator: process
begin
while not halt_sys_clock loop
sys_clock <= '1';
wait for SYS_CLOCK_PERIOD / 2.0;
sys_clock <= '0';
wait for SYS_CLOCK_PERIOD / 2.0;
end loop;
wait;
end process SysClockGenerator;
ResetProcess: process
begin
reset <= '0';
wait for 1 ns;
reset <= '1';
wait for 10 ns;
reset <= '0';
--wait for 21 ms;
wait for 1 ms;
halt_sys_clock <= true;
wait;
end process ResetProcess;
ButtonPress: process
begin
button <= '0';
wait for 1 us;
button <= '1';
wait for 1 us;
button <= '0';
wait;
end process ButtonPress;
FindPreamble: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and find_preamble = '1' then
count := count + 1;
end if;
if count = 17 * 50 then
found_preamble <= '1';
else
found_preamble <= '0';
end if;
end process FindPreamble;
TimerA: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and timer_a_enable = '1' then
count := count + 1;
end if;
if count = 200 then
timer_a_timeout <= '1';
else
timer_a_timeout <= '0';
end if;
end process TimerA;
TimerB: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and timer_b_enable = '1' then
count := count + 1;
end if;
if count = 1000 then
timer_b_timeout <= '1';
else
timer_b_timeout <= '0';
end if;
end process TimerB;
TimerC: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and timer_c_enable = '1' then
count := count + 1;
end if;
if count = 200 then
timer_c_timeout <= '1';
else
timer_c_timeout <= '0';
end if;
end process TimerC;
DUT: StateMachineChallenge
generic map
(
NUM_STATES => NUM_STATES,
NUM_OUTPUTS => NUM_OUTPUTS
)
port map
(
clock => sys_clock,
reset => reset,
button => button,
found_preamble => found_preamble,
timer_a_timeout => timer_a_timeout,
timer_b_timeout => timer_b_timeout,
timer_c_timeout => timer_c_timeout,
state => state,
outputs => outputs
);
(led, find_preamble, servo_position, timer_a_enable, timer_b_enable, timer_c_enable) <= outputs;
end architecture;
Синхронизация часов
![Clock Timings](https://i.stack.imgur.com/YMAd0.png)
VHDL для генерации тактовых импульсов
--
-- Clock Strobe
--
-- Generates a slow clock strobe from a fast clock.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ClockStrobe is
generic
(
max_count: natural
);
port
(
clock: in std_logic;
clock_strobe: out std_logic
);
end;
architecture V1 of ClockStrobe is
begin
-- Create clock strobe.
process(clock)
variable counter: natural range 0 to max_count := 0;
begin
if rising_edge(clock) then
counter := counter + 1;
if counter = max_count then
clock_strobe <= '1';
counter := 0;
else
clock_strobe <= '0';
end if;
end if;
end process;
end architecture;
--
-- Test Bench
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity TestBench is
end entity;
architecture V1 of TestBench is
constant SYS_CLOCK_FREQ: real := 100000000.0; -- Hz
constant SYS_CLOCK_PERIOD: time := 1.0 sec / SYS_CLOCK_FREQ;
constant MAX_COUNT_2MHz: natural := 50;
constant MAX_COUNT_50Hz: natural := 2000000;
signal stop_clock: boolean := false;
signal clock: std_logic;
signal clock_strobe_2MHz: std_logic;
signal clock_strobe_50Hz: std_logic;
component ClockStrobe is
generic
(
max_count: natural
);
port
(
clock: in std_logic;
clock_strobe: out std_logic
);
end component;
begin
ClockGenerator: process
begin
while not stop_clock loop
clock <= '0';
wait for SYS_CLOCK_PERIOD / 2.0;
clock <= '1';
wait for SYS_CLOCK_PERIOD / 2.0;
end loop;
wait;
end process ClockGenerator;
ClockStrobe2MHz: ClockStrobe
generic map
(
max_count => MAX_COUNT_2MHz
)
port map
(
clock => clock,
clock_strobe => clock_strobe_2MHz
);
ClockStrobe50Hz: ClockStrobe
generic map
(
max_count => MAX_COUNT_50Hz
)
port map
(
clock => clock,
clock_strobe => clock_strobe_50Hz
);
-- Preamble process.
process(clock)
begin
if rising_edge(clock) then
if clock_strobe_2MHz then
-- Process the next preamble bit.
end if;
end if;
end process;
-- Servo process.
process(clock)
begin
if rising_edge(clock) then
if clock_strobe_50Hz then
-- Process the servo.
end if;
end if;
end process;
end architecture;
Моделирование
Показывает только стробоскоп 2 МГц. ![Simulation showing 2 MHz strobe](https://i.stack.imgur.com/s72C2.png)