PWM
的设计
一、实验原理
脉宽调制是工业上常见的电机控制方法。其基本原理是用脉冲的宽度表征被测量的大小。实现上
常用一个等幅周期信号去采样调制信号,比较调制信号和载波信号的大小,将其转化为零一的数字信
号,即实现了脉宽调制。
二、系统描述
三角波发生器
比较器
CLKData[0...7]输出
图
1
PWM
原理图
一个基本的
PWM
发生器需要一个标准信号和目标信号进行比较,这里选择常用的三角波信号,
这样系统的描述就至少一个三角波发生器和一个比较器。其结构如图所示。
三、模块设计
1.
三角波发生器
三角波发生器实质上是一个计数器,
在时钟信号下,计数器不断进行进行加一和减一的操作,通
过另一个信号逻辑,其在零和一是分别进行加一和减一;在计数值达到最大时该逻辑变反,在此基础
上定义好电路的初始条件,就能实现周期三角波了。
定义
复位端口
rst
、时钟
端口
clk
和
输出端口
tri_data
;定义标示加或减的逻辑信号
updown
和
输出寄存器
tri_data_temp
。在行为中分别定义两个
process
描述计数器累加和递减的过程。
用语言写的时候需要注意的是输出初值的选取,选择零或者一要根据判断跳转条件对应,否则可
能会持续在零或者三角波最大值处而无法跳转。
2.
比较器
比较器
调用
QuatusII
的
MegaWizard Plug
-
In Manager
库中的比较器
LPM_COMPARE
设
置为八位,比较输出为大于的信号,定义输出
VHDL
语言源文件
。
3.
顶层工程
捕获.PNG
在顶层工程中,调用先前写好的三角波发生器和比较器。定义系统端口为复位信号
rst
、时钟信
号
clk
,输入调制信号
ADC_data(
来自模数转换的调制信号
)
和系统输出
pwm_output
。定义中间信
号
Triangle_data
和
pwm_data
连接器件。
通过
component
语句引用三角波发生器和比较器模块,通过
port map
连接器件。就将系统连
接好了。
四、实验结果
方便起见,测试信号输入给出一个周期
256
倍于时钟信号的三角波信号作为调制信号,进而得
到仿真结果如图
2
所示。
五、问题与展望
图
2
PWM
仿真波形图
这个实验
比较简单,
整个系统逻辑非常清晰,系统结构也不复杂,所以这个实验过程比较顺利就
完成了
。测试的波形经过简单的代码修改,就得到了正确的仿真结果。但是我想它的主要问题就在于
它真的有点简单了。我想一个实际的用作控制的
PWM
发生器,加入采集的信号我们事先不是很清楚,
那么电路比较器的同步就比较难于控制,这样实际的电
路我想还需要一个频率计来测试输入信号,将
频率反馈结果用于控制三角波发生器以得到相应的
PWM
波形。不过通过频率计测频率以控制电路,
电路
中相当加入
反馈环节,实现起来比较困难,就没有去做了。不过这个简单的系统还是体现出了
PWM
的核心思想的。
附源代码
1.
Triangle.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;
ENTITY Triangle IS
port(
rst
: in std_logic;
clk
: in std_logic;
tri_data: out std_logic_vector( 7 downto 0 )
);
end Triangle;
architecture behav of Triangle is
constant up
: std_logic := '0';
--
* rising slope *
--
constant down : std_logic := '1';
--
* descending slope *
--
signal updown : std_logic;
signal
tri_data_temp : std_logic_vector(7 downto 0);
begin
process( rst, clk )
begin
if rst = '0' then
updown <= up;
elsif clk'event and clk = '1' then
case updown is
when up =>
if tri_data_temp >= B"11111110" then
updown <= down;
end if;
when down =>
if tri_data_temp <= B"00000001" then
updown <= up;
end if;
when others =>
end case;
end if;
tri_data <= tri_data_temp;
end process;
process ( rst, clk )
begin
if rst = '0' then
tri_data_temp <= B"00000001";
elsif clk'event and clk = '1' then
case updown is
when up =>
tri_data_temp <= tri_data_temp + 1;
when down =>
tri_data_temp <= tri_data_temp
-
1;
when others =>
end case;
end if;
--
tri_data <=
tri_data_temp;
end process;
end behav;
2.
Compare.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY lpm;
USE lpm.all;
ENTITY Compare IS
PORT
(
dataa
: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
datab
: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
AgB
: OUT STD_LOGIC
);
END Compare;
ARCHITECTURE SYN OF compare IS
SIGNAL sub_wire0
: STD_LOGIC ;
COMPONENT lpm_compare
GENERIC (
lpm_representation
: STRING;
lpm_type
: STRING;
lpm_width
: NATURAL
);
PORT (
dataa
: IN STD_LOGIC_VECTOR (7
DOWNTO 0);
datab
: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
AgB
: OUT STD_LOGIC
);
END COMPONENT;
BEGIN
AgB <= sub_wire0;
lpm_compare_component : lpm_compare
GENERIC MAP (
lpm_representation => "UNSIGNED",
lpm_type => "LPM_COMPARE",
lpm_width => 8
)
PORT MAP (
dataa => dataa,
datab => datab,
AgB => sub_wire0
);
END SYN;
3.
PWM.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;
entity PWM is
port(
clk : in std_logic;
rst : in std_logic;
ADC_data : in std_logic_vector ( 7 downto 0 );
--
Triangle_data : in std_logic_vector ( 7 downto 0 );
pwm_output : out std_logic
);
end PWM;
architecture behav of PWM is
signal Triangle_data : std_logic_vector( 7 downto 0
);
signal pwm_data : std_logic;
component Triangle is
port(
rst : in std_logic;
clk : in std_logic;
tri_data : out std_logic_vector ( 7 downto 0 )
);
end component;
component Compare is
port(
dataa : in std_logic_vector( 7 downto
0 );
datab : in std_logic_vector( 7 downto 0 );
AgB : out std_logic
);
end component;
begin
Triangel_inst : Triangle
port map(
rst => rst,
clk => clk,
tri_data => Triangle_data
);
Compare_inst : Compare
port map(
dataa
=> ADC_data,
datab => Triangle_data,
AgB => pwm_data
);
pwm_output <= pwm_data;
end behav;
A Work By TX