0

我正在尝试使用 100khz 时钟和 0.6 毫秒到 2.4 毫秒的 PWM 创建一个 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>

尝试合成时出现错误的同步错误

4

1 回答 1

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从“0”变为“1”,您将如何做到这一点:

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 等进行修改。支持使用寄存器驱动时钟信号(不幸的是),但该工具无法像对全局时钟那样分析网络,即您的设计可能会在没有工具告诉您的情况下失败。如果要“划分”时钟,请使用时钟使能:

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_CONSTis时分配"001", "010", etc。不这样做会导致闩锁元件,这是坏的!

于 2015-04-14T01:34:49.617 回答