# Issues with combining counters for traffic light

I am trying to implement something as simple as the controller for one single traffic light by using two counters (one for green/red and one for yellow), but I don't seem to be getting the timing right.

My first counter looked something like

entity counter is
generic (
max_count : integer := 50
);
port (
clk : in std_ulogic;
rst : in std_ulogic;
count_value : out integer := '0';
flag : out std_ulogic := '0'
);
end entity;

architecture behav of counter is
signal count : natural := 0;
begin
count_value <= count

process (rst, clk)
begin
if rst = '0' then
flag <= '0';
count <= 0;
elsif rising_edge(clk) then
count <= (count + 1) mod max_count;
if count = 0 then
-- set flag value for one cycle
flag <= '1';
else
flag <= '0';
end if;
end if;
end process;
end architecture behav;


which also sets the flag value when it starts to count.

When I tried to implement the traffic light (simply a state machine) by means of this counter, I got stuck. When I just start the red/green counter c_redgreen once, i.e. the counter is never reset. The problem with this approach is of course that the time where the traffic light is yellow is not taken into account (e.g. the light starts with red and stays in that state for 50 cycles, then it becomes yellow for 5 cycles, but then there are only 45 cycles green, because the counter was not paused during the yellow time etc...). I thought this could be simply worked around by resetting c_redgreen while the light is yellow, but immediately after the reset, the flag is immediately set and therefore I can't use something like if rising_edge(rg_flag) then ..., because the rising edge comes immediately (because the counter sets the flag as it starts).

After these troubles, I thought it would be better to reformulate my counter as follows

...
elsif rising_edge(clk) then
temp := (count + 1) mod max_count;
count <= temp
if temp = 0 then
...


to avoid the flag being set when starting, but when I start the clock (in the testbench) with 0, the first red light does not last 50 cycles, but only 49. Also I am not sure whether it is a good idea for a counter to do nothing until it has reached max_count.

My question is thus how I can combine two counters (with or without start-flag) so that I can make my red/green lights shine for n cycles and my yellow light for m cycles. I hope I have been clear enough. If the code for my traffic light would be necessary, I can add it (I just didn't want to make this question even longer). I also don't necessarily need a traffic light, I just want to have these counters running in parallel in some way. Thanks in advance

• For a long time the code for traffic lights was written in assembler for a simple CPU/MPU. The reason was pure simplicity. No need to over-complicate this rather simple sequence. – Sparky256 May 14 '16 at 22:56

You're way over-thinking this. There's no reason to make the counter a separate entity; you just end up writing a lot of code to do explicitly what the synthesis tools can do for you implicitly.

Also, for the example of traffic lights, you really only need one counter, because you only need one delay at a time. The same counter can handle different delays for different states.

Just make the counter part of the main state machine, something like this:

entity traffic_light is
generic (
green_time  : natural := 50;
yellow_time : natural := 20;
);
port (
clk         : in std_ulogic;
rst         : in std_ulogic;
-- lights are 3-bit fields that control red, yellow, green
ns_lights   : out std_logic_vector (2 downto 0);
ew_lights   : out std_logic_vector (2 downto 0);
);
end entity;

architecture behav of traffic_light is
signal state : natural;
signal count : natural;
begin
process (clk)
begin
if rising_edge(clk) then
if rst = '1' then         -- active-high synchronous reset
state <= 0;
ns_lights <= "100";
ew_lights <= "100";
count <= 100;
else
case state is

when 0 =>               -- special start-up state; all lights red
if count = 0 then
ns_lights <= "001"; -- switch NS to green
ew_lights <= "100";
state <= 1;
count <= green_time;
else
count <= count - 1;
end if;

when 1 =>               -- NS green, EW red
if count = 0 then
ns_lights <= "010"; -- switch NS to yellow
ew_lights <= "100";
state <= 2;
count <= yellow_time;
else
count <= count - 1;
end if;

when 2 =>               -- NS yellow, EW red
if count = 0 then
ns_lights <= "100"; -- switch NS to red
ew_lights <= "001"; -- switch EW to green
state <= 3;
count <= green_time;
else
count <= count - 1;
end if;

when 3 =>               -- NS red, EW green
if count = 0 then
ns_lights <= "100";
ew_lights <= "010"; -- switch EW to yellow
state <= 4;
count <= yellow_time;
else
count <= count - 1;
end if;

when 4 =>               -- NS red, EW yellow
if count = 0 then
ns_lights <= "001"; -- switch NS to green
ew_lights <= "100"; -- switch EW to red
state <= 1;
count <= green_time;
else
count <= count - 1;
end if;

when others =>
state <= 0;
ns_lights <= "100";   -- switch NS to red
ew_lights <= "100";   -- switch EW to red
count <= 100;
end case;
end if;
end if;
end process;
end architecture behav;

• I see... I already implemented a traffic light like this, but thought it might make sense to work more modularly. If this would be a more complicated circuit than this traffic light, would it be possible to use counters (I suppose you would need two in that case) together so that one counts when the other one is "paused"? – Mr Tsjolder May 15 '16 at 5:38