EDA实验之在FPGA上设计一个DDS模块,dds模块 2023-10-14 16:22:35 0 0 一、实验内容 在FPGA上设计一个DDS模块,在DE0 开发板上运行,在FPGA芯片内部合成出数字波形即可。不用输出模拟信号,本模块满足以下条件: 使用板载晶振的50MHz时钟,合成以下频率的信号 - 1 、500KHz 正弦波信号。 2、1MHz 正弦波信号。 3、3MHz 正弦波信号。 -频率字字长32位,波表ROM尺寸为 10比特地址,1024个word - 波形格式为2补码格式,12比特量化 - 每个CLK输出一个有效样点。 - 输入信号为频率字和频率字输入使能信号 - 使用板载的拨码开关(Switch)控制生成的波形信号的不同频率。 二、设计思路RTL电路图 设计中根据DDS输出波形频率的计算公式: 确定输出频率。 上式中为输出频率,为输入频率,即为系统基准时钟频率50MHz。m为地址加法器的宽度,K为频率控制字。设计中通过控制K的大小控制输出频率,由于K只能取整数,输出频率可能会有一定偏差。 三、Quartus扫描生成的RTL电路图 四、实验相关程序代码 1、地址加法器模块 module addr_cnt(CLK,sel_K,CLR,En,ROMaddr); input CLK; input [1:0] sel_K; input En,CLR; output [9:0] ROMaddr; reg [9:0] cnt_out; assign ROMaddr=cnt_out; always @ (posedge CLK or negedge CLR) if(~CLR) cnt_out《=10‘d0; else if(~En) cnt_out《=cnt_out; else begin case(sel_K) 2’b00:cnt_out《=cnt_out+10‘b00000_01010; 2’b01:cnt_out《=cnt_out+10‘b00000_10100; default:cnt_out《=cnt_out+10’b00001_11101; endcase end endmodule123456789101112131415161718192021222324 2、顶层设计模块 module Sine_Signal (Dout,ROMaddr,CLK,CLR,En,sel_K); //顶层模块 output [11:0] Dout; //离散的正弦波形输出 output [9:0] ROMaddr; //ROM的地址 input CLK /* synthesis chip_pin=“G21” */ ; //50MHz时钟 input CLR /* synthesis chip_pin=“H2” */ ; //清零KEY0 input En /* synthesis chip_pin=“J6” */; //使能SW0 input [1:0] sel_K /* synthesis chip_pin=“H6,H5” */; //输出频率控制字选择SW2、SW1 addr_cnt U0_inst( //实例引用地址计数器模块 .CLK(CLK), .CLR(CLR), .En(En), .sel_K(sel_K), .ROMaddr(ROMaddr) ); myROM myROM_inst( //实例引用上面定制的ROM模块 .address(ROMaddr), //ROM的地址输入端 .clken(En), .clock(CLK), //时钟输入端 .q(Dout) //数据输出端 ); endmodule123456789101112131415161718192021 3、正弦波形存储模块C语言程序 #include《stdio.h》 #include《math.h》 #define PI 3.141593 #define DEPTH 1024 /* 数据深度,即存储单元的个数 */ #define WIDTH 12 /* 存储单元的宽度 */ int main(void) { int n,temp; float v; FILE * fp; /* 建立文件名为sine1024.mif新文件,允许写入数据, 文件名随意,但扩展名必须为.mif */ fp = fopen(“sine1024.mif”,“w+”); if(NULL==fp) printf(“Can not creat file!”); else { printf(“File created successfully!”); /* 生成文件头,注意不要忘了“;” */ fprintf(fp,“DEPTH=%d;”,DEPTH); fprintf(fp,“WIDTH=%d;”,WIDTH); fprintf(fp,“ADDRESS_RADIX = HEX;”); fprintf(fp,“DATA_RADIX = HEX;”); fprintf(fp,“CONTENT”); fprintf(fp,“BEGIN”); /* 以十六进制输出地址和数据 */ for(n=0;n《DEPTH;n++) { /* 周期为1024个点的正弦波 */ v=sin(2*PI*n/DEPTH); /* 将-1~1之间的正弦波的值扩展到0~4095之间 */ temp=(int)((v+1)*4095/2); //v+1将数值平移到0~2之间 /* 以十六进制输出地址和数据 */ fprintf(fp,“%x:%x;”,n,temp); } fprintf(fp,“END;”); fclose(fp); //关闭文件 } }123456789101112131415161718192021222324252627282930313233343536373839 4、matlab正弦波频谱分析程序 将signal tap采集的正弦波数据生成.txt文件保存,导入到matlab中分析频谱。 clear all; close all; varnum; %调用signal tap 采集的正弦波数据,列矢量 signal=transpose(VarName); %转置 fs=50E6; %采样频率 N=1024; %采样点数 t=[0:1/fs:(N-1)/fs]; %采样时刻 figure(1);plot(t,signal); title(‘正弦波信号’); xlabel(‘Time (s)’); ylabel(‘Magnitude’); Y = fft(signal,N); %做FFT变换 Ayy = abs(Y); %取模 Ayy=Ayy/(N/2); %换算成实际的幅度 Ayy(1)=Ayy(1)/2; F=([1:N]-1)*fs/N; %换算成实际的频率值,Fn=(n-1)*Fs/N figure(2); stem(F(1:N/2),Ayy(1:N/2)); %显示换算后的FFT模值结果 axis([0 5E6 0 2500]); title(‘正弦信号频谱图’); xlabel(‘Frequency (Hz)’); ylabel(‘Magnitude’);12345678910111213141516171819202122 五、实验结果 1、signal tap 数据截图 (1)f1=500kHz正弦波,地址位宽m=10,频率控制字K=10 (2)f2=1MHz正弦波,地址位宽m=10,频率控制字K=20 (2)f2=3MHz正弦波,地址位宽m=10,频率控制字K=61 2、matlab频谱分析 由频谱图可以看出DDS输出的频率略小于实验要求的频率。这是由于实验中频率控制字只能取整数,略去了小数位,实际取值小于理论计算值。实验结果与理论推算结果是一致的。 收藏(0)