Traffic light junction in VHDL

62 Views Asked by At

I was given a task to try and make a three way traffic light junction in VHDl using a Preset CountDown Timer, the junction looks like the picture below. The blue rectangle is a car for which the light should turn on if it is there. enter image description here

The problem that I am having is that the output signal of the CountDown Timer is always 1 after it finished its first cycle with no way of resetting it aside from the input reset signal. Is there any way I could make it so that I know when each consecutive count is over? Here is the code for the counter. Do note that I cannot change the code of the counter, only of the traffic light system:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity PresetDownCounter is
generic(
    TIMER_BITS : natural := 4
);
port(
    clk : in std_logic;
    reset : in std_logic;
    timer_preset : in unsigned(TIMER_BITS-1 downto 0);
    timer_start : in std_logic;
    timer_finished : out std_logic
);
end entity PresetDownCounter;

architecture rtl of PresetDownCounter is
    -- Counting Register
    signal count_ff : unsigned(TIMER_BITS-1 downto 0) := (others => '0');
    signal count_nxt : unsigned(TIMER_BITS-1 downto 0);
begin
    -- Sequential process (Register)
    seq : process(clk, reset)
    begin
        if reset = '1' then
            count_ff <= (others => '0');
        elsif rising_edge(clk) then
            count_ff <= count_nxt;
        end if;
    end process seq;

    -- Combinatorial process
    comb : process(count_ff, timer_start, timer_preset)
    begin
        -- Standard assigment
        count_nxt <= count_ff;
        timer_finished <= '0';

        if count_ff /= 0 then
            -- Counting down until 0 is reached
            count_nxt <= count_ff - 1;
        else
            -- When 0 is reached, set the timer_finished output to 1
            timer_finished <= '1';
        end if;

        if timer_start = '1' then
            -- Input new value when timer is started again.
            count_nxt <= timer_preset;
        end if;
    end process comb;
end architecture rtl;

And here is the code for the traffic junction, to highlight the problem with the counter, note the logic may still not be completely correct:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity AmpelSteuerung4 is
    generic (
        CLK_HZ : natural := 7
    );
    port (
        clk : in std_logic;
        reset : in std_logic;
        haupt : out std_logic_vector(2 downto 0);
        neben : out std_logic_vector(2 downto 0);
        neben_anforderung : in std_logic
    );
end AmpelSteuerung4;

architecture rtl of AmpelSteuerung4 is
component PresetDownCounter is
        generic (
            TIMER_BITS : natural := 6
        );
        port(
            clk : in std_logic;
            reset : in std_logic;
            timer_preset : in unsigned(TIMER_BITS-1 downto 0);
            timer_start : in std_logic;
            timer_finished : out std_logic
        );
    end component;

-- Declaration of internal Signals
signal preset_intern : unsigned(5 downto 0) := (others => '0');
signal start_intern  : std_logic := '0';
signal finished_intern  : std_logic := '0';

-- States for the State machine
type zustand_t is (RED, RED_YELLOW, GREEN, YELLOW);
signal zustand_ff, zustand_nxt : zustand_t;
constant C_RED : std_logic_vector(2 downto 0) := "100";
constant C_RED_YELLOW : std_logic_vector(2 downto 0) := "110";
constant C_GREEN : std_logic_vector(2 downto 0) := "001";
constant C_YELLOW : std_logic_vector(2 downto 0) := "010";

begin

    PRESETDOWNCOUNTER1 : PresetDownCounter
    generic map (
        TIMER_BITS => 6
    )
    port map (
        clk => clk,
        reset => reset,
        timer_preset => preset_intern,
        timer_start => start_intern,
        timer_finished => finished_intern 
    );

    seq : process(clk)
    begin
        -- Reset Process
        if(rising_edge(clk)) then
            if reset = '1' then
                zustand_ff <= RED;
            else
                zustand_ff <= zustand_nxt;
            end if;
        end if;
    end process;

    fsm : process (clk, zustand_ff, neben_anforderung)
    begin
        -- State machine
        case zustand_ff is
            when RED =>
                haupt <= C_RED;
                neben <= C_GREEN;  
                preset_intern <= to_unsigned(7 * 4, 6); -- RED for 4 Seconds, multiply by 7 because of the 7 Hz tick rate of the clk input, to get 4 seconds
                start_intern <= '1';    
                if(finished_intern = '1') then
                    start_intern <= '0';
                    zustand_nxt <= RED_YELLOW; 
                end if;
            when RED_YELLOW =>
                haupt <= C_RED_YELLOW;
                neben <= C_YELLOW;
                preset_intern <= to_unsigned(7, 6); -- RED_YELLOW for 1 Seconds
                start_intern <= '1';
                if(finished_intern = '1') then
                    start_intern <= '0';
                    zustand_nxt <= GREEN;
                end if;
            when GREEN =>
                haupt <= C_GREEN;
                neben <= C_RED;
                -- Checking for the neben_anforderung input (blue car on the side)
                if neben_anforderung = '1' then
                    preset_intern <= to_unsigned(7 * 5, 6); -- GREEN for 5 Seconds
                    start_intern <= '1';
                    if(finished_intern = '1') then
                        start_intern <= '0';
                        zustand_nxt <= YELLOW;
                    end if;
                else
                    preset_intern <= to_unsigned(7 * 5, 6); -- GREEN for 5 Seconds
                    start_intern <= '1';
                    if(finished_intern = '1') then
                        start_intern <= '0';
                        zustand_nxt <= GREEN;
                    end if;
                end if;
            when YELLOW =>
                haupt <= C_YELLOW;
                neben <= C_RED_YELLOW;
                preset_intern <= to_unsigned(7, 6); -- YELLOW for 1 Second
                start_intern <= '1';
                if(finished_intern = '1') then
                    start_intern <= '0';
                    zustand_nxt <= RED;
                end if;
        end case;
    end process fsm;
end architecture rtl;

Here is a part of the Waveform as well, as you can see the start_intern is high for only one tick of the clk input and the finished_intern(output of the counter) is high all the time after that, even though the timer should be started again. enter image description here

0

There are 0 best solutions below