本帖最后由 古彤821 于 2019-8-2 13:28 编辑
1. 实例说明 直接数字合成器 DDS ,是一种数字式的频率合成器,它的优点是易于控制,频率切换速度块,此实例通过 ROM 查找法用 VHDL 语言实现了 DDS 的功能。 2. 设计原理 DDS 要产生一个 sinwt 的正弦信号的方法是:在每次系统时钟的触发沿到来时,输出相应的幅度值,每次相应的增值为 wT ( T 为系统时钟周期)。要得到每次相应相位的幅度值,一种简单的方法是查表,即将 0—2π 的正弦函数值分为 n 份,将各点的幅度值存到 ROM 中,再用一个 相位累加器每次累加相位值 wT ,得到当前的相位值,通过查找 ROM 得到当前的幅度值 。 DDS 工作过程:每次系统时钟的上升沿到来时,相位累加器( 24 位)中的值累加上频率寄存器( 24 位)中的值,再用累加器的高 12 位作为地址进行 ROM 查表,查到的值送到 D/A 进行转换。 采用 ROM 压缩技术。将 0—2π 的幅度值只存储 0—π/2 的部分。 3. 程序说明: 程序分 3 个部分:数据输入部分,相位累加部分和 ROM 查找部分,系统时钟用 clk 表示; 在数据输入部分,输入信号 rec 高电平表示让系统读取新的频率控制字,只有在 clk 上升沿时 rec 为高电平才将输入的 ftw 信号读入频率寄存器中。读取后输出一个周期的 ack 高电平信号表示接收应答; 在相位累加部分,每次 clk 上升沿到来时,将频率寄存器的值加到相位累加器中,并将上一次的累加值高 12 位输出作为查找 ROM 地址使用。其中最高两位赋给信号 s_1 和 s_2 用来表示相位的区间,其他 10 位用来生成 ROM 地址; ROM 查找部分,对 s_1 和 s_2 进行判断,确定相位的区间,将各个区间的地址和 ROM 数据对应到 0—π/2 区间,因为 ROM 中实际上只存储了 0—π/2 区间的数据。区间 π/2—π 中与区间 0—π/2 幅度相同的相位相加为 π ,即区间 π/2—π 中地址为 x 的数据对应区间 0—π/2 中地址 3FF—x 的数据,可由 x 取反得到。区间 π—3π/2 的幅度为负,地址为 x 的数据对应区间 0—π/2 中相同地址的数据取反。区间 3π/2—2π 的幅度为负,地址为 x 的数据对应区间 0—π/2 中 3FF—x 地址的数据取反; ROM 中的数据均为有符号数据,最高位为符号位,“ 0 ”表示正,“ 1 ”表示负,负数用二进制补码形式表示。整数取反再加 1 ,得到相应的负数; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; entity dds_dds is port(ftw:in std_logic_vector(23 downto 0);-- 频率控制字 clk:in std_logic; -- 系统时钟 rec:in std_logic; -- 接收信号使能 out_q:out std_logic_vector(9 downto 0);-- 幅度值输出 ack:out std_logic); -- 接受应答信号 end dds_dds; architecture hev of dds_dds is signal rom_out:std_logic_vector(9 downto 0); signal frq_reg,phase_adder:std_logic_vector(23 downto 0); signal rom_address,address:std_logic_vector(9 downto 0); signal s_1,s_2,a_1,a_2,a:std_logic; component dds_dds_rom -- 元件例化 port(address:in std_logic_vector(9 downto 0); q:out std_logic_vector(9 downto 0)); end component; begin data:dds_dds_rom port map(address,rom_out); datain:process(clk,rec,a,clk) -- 数据输入部分 begin if clk'event and clk='1'then if rec='1'then --rec 为 1 则读取 ftw 数据 frq_reg<=ftw; ack<='1'; a<='1'; end if; if a='1'then --a 与 ack 内容相同,在判断是使用 ack<='0'; a<='0'; end if; end if; end process; phase_add:process(clk) -- 相位累加部分 begin if (clk'event and clk='1')then phase_adder<=phase_adder+frq_reg; -- 相位累加 rom_address(0)<=phase_adder(12); rom_address(1)<=phase_adder(13); rom_address(2)<=phase_adder(14); rom_address(3)<=phase_adder(15); rom_address(4)<=phase_adder(16); rom_address(5)<=phase_adder(17); rom_address(6)<=phase_adder(18); rom_address(7)<=phase_adder(19); rom_address(8)<=phase_adder(20); rom_address(9)<=phase_adder(21); s_2<=phase_adder(22); s_1<=phase_adder(23); end if; end process; lookfor_rom:process(clk,s_1,s_2,a_1,a_2,rom_out,rom_address)--ROM 查找部分 begin if clk'event and clk ='1'then a_1<=s_1; a_2<=s_2; end if; if s_1='0'and s_2='0'then -- 将各区间地址对应到 0—π/2 的地址 address(9 downto 0)<=rom_address(9 downto 0); elsif s_1='0'and s_2='1'then --not rom_address=3FF-rom_address address(9 downto 0)<=not rom_address(9 downto 0); elsif s_1='1'and s_2='0'then address(9 downto 0)<=rom_address(9 downto 0); elsif s_1='1'and s_2='1'then address(9 downto 0)<=not rom_address(9 downto 0); end if; if a_1='0'and a_2='0'then -- 将各区间幅度对应到 0—π/2 的幅度 out_q(9 downto 0)<=rom_out(9 downto 0); elsif a_1='0'and a_2='1'then out_q(9 downto 0)<=rom_out(9 downto 0); elsif a_1='1'and a_2='0'then out_q(9 downto 0)<=not rom_out(9 downto 0)+"0000000001"; elsif a_1='1'and a_2='1'then -- 负数通过对整数取反加 1 得到 out_q(9 downto 0)<=not rom_out(9 downto 0)+"0000000001"; end if; end process; end hev; library ieee; use ieee.std_logic_1164.all; entity dds_dds_rom is --ROM 元件创建 port(address:in std_logic_vector(9 downto 0); q:out std_logic_vector(9 downto 0)); end dds_dds_rom; architecture hev of dds_dds_rom is begin q<=address; end hev;
上面的笑脸是q : out 我这里分开了 不知道为什么发出来成为表情了
|