本帖最后由 IT举人 于 2015-5-16 23:07 编辑
在第二个贴中,如不错意外,大家应该已经可以在示波器输出正弦信号了,那么接下来我们就要考虑怎么把正弦信号和三角波信号进行比较输出spwm了(完成这一步,那么整个设计就基本搞定了:lol) 不过在此之前,有必要和大家说一下正弦信号的周期怎么算。周期就是输出一个完整正弦波所用的时间,也就说我们ROM中储存的512个正弦数据全部遍历完所用的时间。而每个数据都要和(0,255)这256个数据进行比较,所以正弦函数频率 f = 1 /(512 * 256 * t),t 为时钟周期(算出来可能和实际测量的不一样,那时因为时钟周期不准造成的,以测量的为准)。
我们来看一下spwm生成示意图
即是用正弦函数和周期比其小得多的三级波函数值比较,若正弦函数大于三角波,则输出高电平,反则输出低电平。而三角波数据同样存在ROM中(方法同(一)),峰峰值和正弦波相同,同样为256。而数据长度设置这里就要讲技巧了,因为要保证三角波的周期要小于正弦波,大家应该记得我们当初正弦波的数据长度为512,所以这里我们可以吧三角波数据长度设为64,然后我们以同步的时钟周期来同时读它们,这样正弦数据遍历一遍时,三角波已经遍历了16遍了,也即是正弦波的周期是三角波的16倍。下面是三角波ROM元件代码
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY sanjiaobo IS
PORT
(
address : IN STD_LOGIC_VECTOR (5 DOWNTO 0);
clock : IN STD_LOGIC := '1';
q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END sanjiaobo;
ARCHITECTURE SYN OF sanjiaobo IS
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0);
COMPONENT altsyncram
GENERIC (
clock_enable_input_a : STRING;
clock_enable_output_a : STRING;
init_file : STRING;
intended_device_family : STRING;
lpm_hint : STRING;
lpm_type : STRING;
numwords_a : NATURAL;
operation_mode : STRING;
outdata_aclr_a : STRING;
outdata_reg_a : STRING;
widthad_a : NATURAL;
width_a : NATURAL;
width_byteena_a : NATURAL
);
PORT (
address_a : IN STD_LOGIC_VECTOR (5 DOWNTO 0);
clock0 : IN STD_LOGIC ;
q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END COMPONENT;
BEGIN
q <= sub_wire0(7 DOWNTO 0);
altsyncram_component : altsyncram
GENERIC MAP (
clock_enable_input_a => "BYPASS",
clock_enable_output_a => "BYPASS",
init_file => "sanjiaobo.mif",
intended_device_family => "Cyclone II",
lpm_hint => "ENABLE_RUNTIME_MOD=NO",
lpm_type => "altsyncram",
numwords_a => 64,
operation_mode => "ROM",
outdata_aclr_a => "NONE",
outdata_reg_a => "CLOCK0",
widthad_a => 6,
width_a => 8,
width_byteena_a => 1
)
PORT MAP (
address_a => address,
clock0 => clock,
q_a => sub_wire0
);
END SYN;
三角波ROM元件建好后,我们需要的就是同步把正弦波和三角波中的ROM数据读出来,比较他们,根据比较结果即可生成spwm。修改一下(二)中的数据即可获得下面程序:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY spwm IS
PORT(sysclk :IN STD_LOGIC;
pwm_output :OUT STD_LOGIC;
spwm_output :OUT STD_LOGIC);
END ENTITY spwm;
ARCHITECTURE rlt OF spwm IS
COMPONENT sin_512 IS --声明ROM元件
PORT
(
address : IN STD_LOGIC_VECTOR (8 DOWNTO 0); --ROM地址信号
clock : IN STD_LOGIC := '1'; --时钟信号
q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ---输出信号
);
END COMPONENT;
COMPONENT sanjiaobo IS
PORT
(
address : IN STD_LOGIC_VECTOR (5 DOWNTO 0);
clock : IN STD_LOGIC := '1';
q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END COMPONENT;
SIGNAL counter :INTEGER RANGE 0 TO 256; --用于计数
SIGNAL sin_addr :STD_LOGIC_VECTOR (8 DOWNTO 0) ; --sin ROM地址
SIGNAL sin_rom_data :STD_LOGIC_VECTOR (7 DOWNTO 0) ; --sin ROM数据
SIGNAL san_addr :STD_LOGIC_VECTOR (5 DOWNTO 0) ; --三角波ROM地址
SIGNAL san_rom_data :STD_LOGIC_VECTOR (7 DOWNTO 0) ; --三角波ROM数据
BEGIN
u1: sanjiaobo PORT MAP(san_addr, sysclk, san_rom_data);
u2: sin_512 PORT MAP(sin_addr, sysclk, sin_rom_data); --实例化ROM元件
PROCESS(sysclk) IS
BEGIN
IF(sysclk'EVENT AND sysclk = '1') THEN
counter <= counter + 1;
IF(counter = 256) THEN
counter <= 0;
sin_addr <= sin_addr + 1; -- 比较完256个数据后sin ROM地址加1
san_addr <= san_addr + 1; -- 三角波ROM地址跟随sin ROM地址变化
END IF;
IF(sin_rom_data > counter)THEN --输出sin
pwm_output <= '1';
ELSE
pwm_output <= '0';
END IF;
IF(sin_rom_data > san_rom_data)THEN --输出spwm
spwm_output <= '1';
ELSE
spwm_output <= '0';
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
到此为止,课程的基本内容已经完成,编程思路有千万种,我的程序只是供大家参考,请勿直接套用,大家有什么问题欢迎回帖提问,我会尽快回答。 |