Reputation: 3
I'm really new in vhdl, and I want to do some kind of KIT led mechanizm. My code should work like this- I use 18 different states for light up leds from led0 to led7, and it comes back from led7 to led0, etc. Acctually my states, and with select function did what I want, and it worked like a dream, but I wanted to turbo this mod, and add 2 other pwm signal for this code. I wrote the pwm signals but cant use those at the with case state.
It depends on current state. For example. when I'm in s5, I want to do some like this-
led5-100% led4-60% led3-20%
Is the problem that I have to write the pwm signals in other 2 proccesses, or what should I do with it to work? Thanks for the help.
Here is my code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
entity knight_rider is
port(
LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7: out std_logic;
clk, reset: in std_logic);
end knight_rider;
architecture Behavioral of knight_rider is
type state_type is (start0,s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16);
signal current_s: state_type;
signal Counter: std_logic_vector(24 downto 0);
signal temp1_20: std_logic;
signal temp1_60: std_logic;
signal temp2_20: std_logic;
signal temp2_60: std_logic;
signal temp3_20: std_logic;
signal temp3_60: std_logic;
signal counter1_20: integer range 0 to 2048 := 0; -- counter1 for 20% bright
signal counter1_60: integer range 0 to 2048 := 0; -- counter1 for 60% bright
signal counter2_20: integer range 0 to 2048 := 0; -- counter2 for 20% bright
signal counter2_60: integer range 0 to 2048 := 0; -- counter2 for 60% bright
signal clkout60,clkout20: std_logic;
begin
knight_rider: process (clk, reset)
begin
if (reset='1') then
current_s <=start0;
elsif rising_edge(clk) then
counter1_60<=counter1_60 + 1; --pwm for 60% briht
if (counter1_60 = 2048) then
temp1_60 <= '1';
counter1_60 <= 0;
end if;
if temp1_60 = '1' then
temp3_60 <='1';
temp2_60 <= '1';
temp1_60 <='0';
end if;
if temp3_60 = '1' then
counter2_60 <=counter2_60 + 1;
if (counter2_60 =1230) then
temp2_60 <= '0';
temp3_60 <='0';
counter2_60 <= 0;
clkout60<=temp2_60;
end if;
end if;
counter1_20<=counter1_20 + 1; --pwm for 20% bright
if (counter1_20 = 2048) then
temp1_20 <= '1';
counter1_20 <= 0;
end if;
if temp1_20 = '1' then
temp3_20 <='1';
temp2_20 <= '1';
temp1_20 <='0';
end if;
if temp3_20 = '1' then
counter2_20 <=counter2_20 + 1;
if (counter2_20 <=410) then
temp2_20 <= '0';
temp3_20 <='0';
counter2_20 <= 0;
clkout20<=temp2_20;
end if;
end if;
Counter<= Counter + 1; -- statements: From here, its actually do what I want...
if Counter="10011000100101101000000" then -- but with clkout20, and clkout60 something's wrong
Counter<="0000000000000000000000000";
case current_s is
when start0 =>
current_s <=s0;
when s0 =>
if (reset ='0') then
current_s <=s1;
else
current_s <= start0;
end if;
when s1 =>
if (reset = '0') then
current_s <=s2;
else
current_s <= s0;
end if;
when s2 =>
if (reset = '0') then
current_s <=s3;
else
current_s <= s1;
end if;
when s3 =>
if (reset = '0') then
current_s <=s4;
else
current_s <= s2;
end if;
when s4 =>
if (reset = '0') then
current_s <=s5;
else
current_s <= s3;
end if;
when s5 =>
if (reset = '0') then
current_s <=s6;
else
current_s <= s4;
end if;
when s6 =>
if (reset = '0') then
current_s <=s7;
else
current_s <= s5;
end if;
when s7 =>
if (reset = '0') then
current_s <=s8;
else
current_s <= s6;
end if;
when s8 =>
if (reset = '0') then
current_s <=s9;
else
current_s <= s7;
end if;
when s9 =>
if (reset = '0') then
current_s <=s10;
else
current_s <= s8;
end if;
when s10 =>
if (reset = '0') then
current_s <=s11;
else
current_s <= s9;
end if;
when s11 =>
if (reset = '0') then
current_s <=s12;
else
current_s <= s10;
end if;
when s12 =>
if (reset = '0') then
current_s <=s13;
else
current_s <= s11;
end if;
when s13 =>
if (reset = '0') then
current_s <=s14;
else
current_s <= s12;
end if;
when s14 =>
if (reset = '0') then
current_s <=s15;
else
current_s <= s13;
end if;
when s15 =>
if (reset = '0') then
current_s <=s16;
else
current_s <= s14;
end if;
when s16=> current_s <= s0;
when others => null;
end case;
end if;
end if;
end process;
with current_s select
LED0 <= '1' when s0|s15,
'clkout60' when s1,
'clkout20' when s2,
'0' when others;
with current_s select
LED1 <= '1' when s1|s14,
'temp2_60' when s2|s15,
'clkout20' when s3,
'0' when others;
with current_s select
LED2 <= '1' when s2|s13,
'clk_out_60' when s3|s14,
'clk_out_20' when s4|s15,
'0' when others;
with current_s select
LED3 <= '1' when s3|s12,
'clk_out_60' when s4|13,
'clk_out_20' when s5|s14,
'0' when others;
with current_s select
LED4 <= '1' when s4|s11,
'clk_out_60' when s5|12,
'clk_out_20' when s6|s13,
'0' when others;
with current_s select
LED5 <= '1' when s5|s10,
'clk_out_60' when s6|s11,
'clk_out_20' when s7|s12,
'0' when others;
with current_s select
LED6 <= '1' when s6 | s9,
'clk_out_60' when s7|s10,
'clk_out_20' when s8|s11,
'0' when others;
with current_s select
LED7 <= '1' when s7 |s8,
'clk_out_60' when s9,
'clk_out_20' when s10,
'0' when others;
end Behavioral;
Upvotes: 0
Views: 712
Reputation: 15924
It is not required that you rewrite the code with PWM to a separate process, but it may help on structure and readability, thus making it easier for you to get the code to work. Some observations and suggestions:
Create the PWM outputs in a separate process, since generation of the different PWM signals is not directly tied to the state update or LED drive, so it is probably easier for you to keep a good overview if you separate unrelated functionality in separate processes.
reset signal check for '0' can be removed from the case in the knight_rider process, since reset is used as asynchronous reset through the first part of the if in that process, so when the second part takes effect, it is always '0'.
Instead of the 18 states in state_type, you may consider using a std_logic_vector controlled as an up-down counter, since it appears you use the states that way.
Make the LED as std_logic_vector(0 to 7)
instead of separate outputs,
and the use the std_logic_vector state suggested above, to index the LEDs,
so explicit drive of each LED can be avoided in code.
Instead of Counter = "10011000100101101000000"
use
CONV_STD_LOGIC_VECTOR(5000000, Counter'length)
, since this makes reading
the value much easier.
Instead of Counter <= "0000000000000000000000000"
use Counter <= (others
=> '0')
or CONV_STD_LOGIC_VECTOR(0, Counter'length), for readability.
You can significantly improve readability of your code if you use consistent
indentation, e.g. not having the three end case; end if; end if;
all at
same level. Also use only space for indent, to avoid any weird formatting
that may occur when using tabs.
Syntax error in with ... select
, since clkout60 and clkout20 should not
be 'clkout60' and 'clkout20', just plain clkout60 and clkout20.
The clk_out_20 and clk_out_60 in with ... select
does not exist, but that
is probably work in progress.
Upvotes: 1