DDS(Direct Digital Synthesizer)直接数字式频率合成器
(1)事先波形数据存储在ROM里,每一个ROM地址对应一个波形数据(假设地址位宽8位,总共2^8=256)。DDR就是循环读取ROM里的数据。
(2)假设系统时钟为50MHZ,每个时钟地址+1,则获得频率 f o u t = 50 M h z 256 = 195.3 k h z   \ fout=\frac{50Mhz}{256}=195.3khz \, fout=25650Mhz=195.3khz.因此可以产生两种想法来改变频率
(a)改变采样时钟,即每两个时钟到来,地址+1,达到分频效果。
(b)改变地址采样间隔,即每个时钟地址+2,到底倍频效果(采样定理的存在,采样点数减少,容易使波形失真)
缺点:只能达到整数倍频或者分数分频。
(3)改变地址位宽实现任意分频:将原来地址[0:7]拓展成32位,读取数据时,只读取与之对应的原8位所对应的值,这样可达到 50 M h z 2 3 2 = 0.01164 h z   . \frac{50Mhz}{2^32}=0.01164hz\,. 23250Mhz=0.01164hz.假设此时需要1KHZ的频率,则每个时钟来临时地址+1000/0.01164=85911。
总结公式为
f o u t = f c l k 2 N ∗ K   \ fout=\frac{fclk}{2^N}*K\, fout=2Nfclk∗K
K为频率控制字,N为位宽。
假设ROM地址为8位
地 址 初 值 = 256 ∗ ( 初 始 相 位 / 360 ) \ 地址初值=256*(初始相位/360) 地址初值=256∗(初始相位/360)
x=linspace(0,2*pi,4096); %一个周期采样点取4096(2^12)个,数据量
y=sin(x)+1; %将函数平移到纵轴的正半轴。
y1=ceil(y*(2^8-1)) %将数据转化为整数,方便ROM存储
%matlab取整函数:
%fix(x)向零取整
%floor(x)向左取整
%ceil(x)向右取整
fid = fopen('cos_coe.coe','wt'); %生成cos函数coe文件
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n');%并不明白为什么要加这两句话
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');
for i = 1:1:2^12
fprintf(fid,'%16.0f',y3(i));
if i==2^12
fprintf(fid,';');
else
fprintf(fid,',');
end
if i%15==0
fprintf(fid,'\n');
end
end
fclose(fid);
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2018/04/11 09:42:14
// Design Name:
// Module Name: dds_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module dds_top(
input clk_50MHz, //输入时钟
input rst,//复位信号
input [31:0] freq_data,//频率控制字:就是多少个单位1,一般85899对应1KHz,
input [11:0] phase_data,//相位控制字
output [9:0] douta//输出
);
//dds rom
reg [31:0] fcnt;//拓展地址
wire [11:0] addra;//十二位数据地址(原理中使用的是8位)
wire [11:0] cos;
always @(posedge clk_50MHz or negedge rst)begin
if(!rst)
fcnt <= 32'd0;
else
fcnt <= fcnt + freq_data;
end
assign addra = fcnt[31:20] + phase_data;//说白了就是每隔[19:0]次位才发生地址变化,否则输出地址addra保持不变
//sin
blk_mem_sin blk_mem_sin_inst (
.clka(clk_50MHz), // input wire clka
.addra(addra), // input wire [11 : 0] addra
.douta(douta) // output wire [11 : 0] douta
);
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/04/14 21:48:50
// Design Name:
// Module Name: my_sim
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module my_sim(
);
reg clk_50MHz=0;
reg rst=0;
reg [31:0] freq_data;
reg [11:0] phase_data;
wire [9:0] douta;
dds_top dds_top_u1(
.clk_50MHz(clk_50MHz),
.rst(rst),
.freq_data(freq_data),
.phase_data(phase_data),
.douta(douta));
initial
begin
rst=0;
#10
rst=1;
freq_data=50000;
phase_data=0;
end
always #10 clk_50MHz=~clk_50MHz;
endmodule