DDS 设计

[复制链接]

1

主题

1

帖子

84

积分

一粒轻沙

Rank: 1

积分
84
查看: 2406回复: 0 发表于 2019-8-2 13:26:39   只看该作者
本帖最后由 古彤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   我这里分开了 不知道为什么发出来成为表情了

快速回复 返回顶部 返回列表