我正在尝试创建一个使用100khz时钟和PWM范围从.6ms到2.4ms的PWM发生器但是我坚持将其实现为vhdl我一直在尝试使用状态机来执行此操作但它具有变得比它应该更复杂。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity PWM is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
pwm_out : out STD_LOGIC;
PWM_CONST : STD_LOGIC_VECTOR(2 downto 0));
end PWM;
architecture Behavioral of PWM is
type State_type is (LOW,HIGH,Counting); --States
signal Sreg, Snext : State_type; --Curent state and next state
signal t20ms,t100ms,t_6ms,t_825ms,t1_05ms,t1_275ms,t1_5ms,t1_725ms,t1_95ms,t2_175ms,t2_4ms: STD_LOGIC;
signal twenty : STD_LOGIC;
signal count_flag : STD_LOGIC;
begin
-------------------------Clock Dividers for timing---------------------------------------
process(clk,reset)
variable toggle_20ms,toggle_1666hz,toggle_1212hz,toggle_952hz,toggle_785hz,toggle_666hz,toggle_579hz,toggle_512hz,toggle_460hz,toggle_416hz : STD_LOGIC :='0';
variable counter_20ms : integer range 0 to 999;
variable counter_1666hz : integer range 0 to 29;
variable counter_1212hz : integer range 0 to 40;
variable counter_952hz : integer range 0 to 51;
variable counter_785hz : integer range 0 to 63;
variable counter_666hz : integer range 0 to 74;
variable counter_579hz : integer range 0 to 85;
variable counter_512hz : integer range 0 to 96;
variable counter_460hz : integer range 0 to 107;
variable counter_416hz : integer range 0 to 119;
begin
if reset = '1' then
t_6ms<='0';
t_825ms<='0';
t1_05ms<='0';
t1_275ms<='0';
t1_5ms<='0';
t1_725ms<='0';
t1_95ms<='0';
t2_175ms<='0';
t2_4ms<='0';
twenty<='0';
else
if(clk'event and clk = '1') then
counter_20ms := counter_20ms+1;
counter_1666hz := counter_1666hz+1;
counter_1212hz := counter_1212hz+1;
counter_952hz := counter_952hz+1;
counter_785hz := counter_785hz+1;
counter_666hz := counter_666hz+1;
counter_579hz := counter_579hz+1;
counter_512hz := counter_512hz+1;
counter_460hz := counter_460hz+1;
counter_416hz := counter_416hz+1;
counter_20ms := counter_20ms+1;
if (counter_1666hz = 29) then
toggle_1666hz := not toggle_1666hz;
counter_1666hz := 0;
end if;
if (counter_1212hz = 40) then
toggle_1212hz := not toggle_1212hz;
counter_1212hz := 0;
end if;
if (counter_952hz = 51) then
toggle_952hz := not toggle_952hz ;
counter_952hz := 0;
end if;
if (counter_785hz = 63) then
toggle_785hz := not toggle_785hz;
counter_785hz := 0;
end if;
if (counter_666hz = 74) then
toggle_666hz := not toggle_666hz;
counter_666hz := 0;
end if;
if (counter_579hz = 85) then
toggle_579hz := not toggle_579hz;
counter_579hz := 0;
end if;
if (counter_512hz = 96) then
toggle_512hz := not toggle_512hz;
counter_512hz := 0;
end if;
if (counter_460hz = 107) then
toggle_460hz := not toggle_460hz;
counter_460hz := 0;
end if;
if (counter_416hz = 119) then
toggle_416hz := not toggle_416hz;
counter_416hz := 0;
end if;
if (counter_20ms = 999) then
toggle_20ms := not toggle_20ms;
counter_20ms := 0;
end if;
t_6ms<=toggle_1666hz;
t_825ms<=toggle_1212hz;
t1_05ms<=toggle_952hz;
t1_275ms<=toggle_785hz;
t1_5ms<=toggle_666hz;
t1_725ms<=toggle_579hz;
t1_95ms<=toggle_512hz;
t2_175ms<=toggle_460hz;
t2_4ms<=toggle_416hz;
twenty<=toggle_20ms;
end if;
end if;
end process;
-------------------------Next State Logic----------------------------------
process(Sreg,reset,PWM_CONST)
begin
case Sreg is
when LOW => if (rising_edge(twenty)) then Snext <= HIGH;
else Snext <= LOW;
end if;
when HIGH => if reset = '1' then Snext <= LOW;
else Snext <= Counting;
end if;
when Counting => if count_flag = '1' then Snext <= Counting;
else Snext <= LOW;
end if;
end case;
end process;
-----------------------Update State----------------------------------------
process(clk)
begin
if (clk'event and clk='1') then
Sreg <= Snext;
end if;
end process;
------------------------Count_flag---------------------------------------------
process(clk,PWM_CONST)
begin
case PWM_CONST is
when "000"=> t_6ms <= count_flag;
when "001"=> t_825ms <= count_flag;
when "010"=> t1_05ms <= count_flag;
when "011"=> t1_275ms <= count_flag;
when "100"=> t1_5ms <= count_flag;
when "101"=> t1_725ms <= count_flag;
when "110"=> t1_95ms <= count_flag;
when "111"=> t2_175ms <= count_flag;
when others => t2_4ms <= count_flag;
end case;
end process;
----------------------Output Logic-----------------------------------------
with Sreg select -- output logic based on state only
pwm_out <= '1' when HIGH | Counting,
'0' when LOW,
'0' when others;
---------------------------------------------------------------------------
end Behavioral;
<code>
当我尝试合成
时出现错误的同步错误答案 0 :(得分:1)
您的代码至少存在三个主要问题。第一个是你的下一个州过程:
process(Sreg,reset,PWM_CONST)
begin
case Sreg is
when LOW => if (rising_edge(twenty)) then Snext <= HIGH;
else Snext <= LOW;
end if;
when HIGH => if reset = '1' then Snext <= LOW;
else Snext <= Counting;
end if;
when Counting => if count_flag = '1' then Snext <= Counting;
else Snext <= LOW;
end if;
end case;
end process;
在案件中你不能拥有rising_edge
,我不确定它代表什么样的电子元件。使用rising_edge
时,所有语句都必须包含在其中(异步复位除外),就像你的时钟分频器和更新状态进程一样。
如果您想检测信号twenty
来自&#39; 0&#39;到&#39; 1&#39;,在这里你将如何做到这一点:
process(reset, clk)
begin
if reset = '1' then
twenty_dl <= '0';
elsif rising_edge(clk) then
twenty_dl <= twenty; -- Delayed version of twenty
if twenty_dl = '0' and twenty = '1' then -- twenty is rising
-- Insert logic here
end if;
end if;
end process;
作为旁注,由寄存器驱动的信号绝不能用作时钟。时钟是合理的,它们来自fpga上的时钟使能引脚,并通过PLL等进行修改。支持使用寄存器来驱动时钟信号(不幸的是),但该工具不能像对全局时钟那样分析网络,即如果没有工具告诉您,您的设计可能会失败。如果你想&#34;划分&#34;时钟,使用时钟启用:
process(reset, clk)
begin
if reset = '1' then
cnt <= (others => '0');
elsif rising_edge(clk) then
if cnt = 199 then -- Divide the clock by 200
clk_div_200_en <= '1';
cnt <= (others => '0');
else
clk_div_200_en <= '0';
cnt <= cnt + 1;
end if;
end if;
end process;
process(clk)
begin
if rising_edge(clk) and clk_div_200_en = '1' then
-- Insert logic here
end if;
end process;
您的代码的第二个主要问题是您有多个驱动程序用于信号t_6ms
和cie。时钟分频器进程和count_flag进程都会分配这些信号。在VHDL中,信号的所有分配必须在单个过程中完成。否则,您将获得多个驱动程序,这些驱动程序通常在综合中不受支持,并且可能导致网络冲突。
第三个主要问题是count_flag进程。这个过程是组合的(没有时钟)。在组合过程中,过程分配的任何信号必须在整个过程的每条路径中分配。这意味着,t_6ms
为PWM_CONST
时必须分配"001", "010", etc
。如果不这样做会导致闩锁元素,这很糟糕!