本帖最后由 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;
复制代码 到此为止,课程的基本内容已经完成,编程思路有千万种,我的程序只是供大家参考,请勿直接套用,大家有什么问题欢迎回帖提问,我会尽快回答。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
啊里卡多,wenjugeg威武,如果频率很快,每次多计一个值还是会有影响吧?
一周热门 更多>