DDS直接数字式频率合成器(Direct Digital Synthesizer)。本文完成一个具有能够频率可调、相位可调的正余弦、方波、三角波的DDS。
DDS的原理如下图,累加器每次累加一个频率操控字,调理频率操控字的数值,能够改动累加器的累加速度,从而能够调理从ROM查找表中读取波形数据的速度。即频率操控字越大,频率越高。相位操控字能够用来调理初始相位,即ROM地址自加的初始值。
从查找表读取出来的数据,经DA转化芯片能够直接输出进行滤波或其他操作,最终可运用示波器进行调查波形改变。
DDS 模块的输出频率是体系作业频率、相位累加器比特数N以及频率操控字K三者的一个函数,其数学关系由式如下。
DDS的频率分辨率,即频率改变距离。
本规划是调用Xilinx Vivado供给的ROM IP Core来存储波形数据,首先要生成波形数据并增加至IP Core中,Xilinx的文件类型为coe格局。
MATLAB代码
此MATLAB代码供给正余弦、方波、三角波四种波形的coe文件输出,MATLAB脚本语言并不是很难,有编程根底很快就能看懂,MATLAB供给的函数很多,哪里不会Google哪里。
x=linspace(0,2*pi,4096);%6.28为2pi,一个周期采样点取4096个
y1=cos(x)+1; %将函数平移到纵轴的正半轴。
y2=sin(x)+1;
y3=ceil(y1*511);
y4=ceil(y2*511);
%生成cos函数coe文件
fid = fopen(‘cos_coe.coe’,‘wt’);
fprintf(fid,‘MEMORY_INITIALIZATION_RADIX=10;\n’);
fprintf(fid,‘MEMORY_INITIALIZATION_VECTOR=\n’);
%fprintf(fid,‘%16.0f\n’,y3);
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);
%生成sin函数coe文件
fid = fopen(‘sin_coe.coe’,‘wt’);
fprintf(fid,‘MEMORY_INITIALIZATION_RADIX=10;\n’);
fprintf(fid,‘MEMORY_INITIALIZATION_VECTOR=\n’);
for i = 1:1:2^12
fprintf(fid,‘%16.0f’,y4(i));
if i==2^12
fprintf(fid,‘;’);
else
fprintf(fid,‘,’);
end
if i%15==0
fprintf(fid,‘\n’);
end
end
fclose(fid);
%生成方波
t=1:1:2^12;
y=(t r=ceil(y*(2^9-1));
fid = fopen(‘square.coe’,‘w’); %写到square.coe,用来初始化rom_square
fprintf(fid,‘MEMORY_INITIALIZATION_RADIX=10;\n’);
fprintf(fid,‘MEMORY_INITIALIZATION_VECTOR=\n’);
for i = 1:1:2^12
fprintf(fid,‘%d’,r(i));
if i==2^12
fprintf(fid,‘;’);
else
fprintf(fid,‘,’);
end
if i%15==0
fprintf(fid,‘\n’);
end
end
fclose(fid);
%生成三角波
t=1:1:2^12;
y=[0.5:0.5/1024:1-0.5/1024, 1-0.5/1024:-0.5/1024:0, 0.5/1024:0.5/1024:0.5];
r=ceil(y*(2^9-1));
fid = fopen(‘triangular.coe’,‘w’); %写到triangular.coe,初始化三角波rom
fprintf(fid,‘MEMORY_INITIALIZATION_RADIX=10;\n’);
fprintf(fid,‘MEMORY_INITIALIZATION_VECTOR=\n’);
for i = 1:1:2^12
fprintf(fid,‘%d’,r(i));
if i==2^12
fprintf(fid,‘;’);
else
fprintf(fid,‘,’);
end
if i%15==0
fprintf(fid,‘\n’);
end
end
fclose(fid);
linspace函数
生成一个等差数列
y = linspace(x1,x2)
y = linspace(x1,x2,n)
y = linspace(x1,x2) 回来包括 x1 和 x2 之间的 100 个等距离点的行向量。
示例
y = linspace(x1,x2,n) 生成 n 个点。这些点的距离为 (x2-x1)/(n-1)。
y1 = linspace(-5,5,7)
y1 = 1×7
-5.0000 -3.3333 -1.6667 0 1.6667 3.3333 5.0000 ⋯
https://ww2.mathworks.cn/help/matlab/ref/linspace.html?requestedDomain=zh
Verilog完成
生成coe文件后调用ROM IP Core,需求生成个ROM的读取地址,首要代码如下。
//freq_data为频率操控字,phase_data为相位操控字。
always @(posedge clk_50MHz or negedge rst)begin
if(!rst)
fcnt else
fcnt end
assign addra = fcnt[31:20] + phase_data;
blk_mem_sin blk_mem_sin_inst (
.clka(clk_50MHz), // input wire clka
.addra(addra), // input wire [11 : 0] addra
.douta(sin) // output wire [11 : 0] douta
);
本规划调用了四个IP,将四种波形一起出处,然后用一个四选一的选择器输出给DA模块至示波器显现,仿真截图如下。
DA转化
D/A转化器选用的是ADI公司的双通道12位21.3MSPS高速DAC转化器AD5447,FPGA 输出的12位数字信号进入AD5447后,通过两个锁存器,转化为差分信号输出芯片内部结构图如图所示。
时序图如图所示。能够看到数据写入芯片的的进程也是非常简略,只需CS拉低就能够进行读操作或写操作。
芯片的输入数据是并行的,我这儿输入的数据便是MATLAB的直接生成的12bit的数据,输出电压的幅值手册给出了计算公式,明晰明晰。
Sin和Cos的波形是相同的,将三种波形输出用示波器检查。波形很漂亮。
这个工程,我放在GitHub上了。订阅号后台回复“DDS”即可取得这个工程。
GitHub 正式宣告了 GitHub Free 以及 GitHub Enterprise。GitHub Free:包括不定量的私有库房,每个私有库房里的项目最多能够与 3 人共享协作。