EDA实验之在FPGA上设计一个DDS模块

EDA/IC设计

1063人已加入

描述

一、实验内容

在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输出的频率略小于实验要求的频率。这是由于实验中频率控制字只能取整数,略去了小数位,实际取值小于理论计算值。实验结果与理论推算结果是一致的。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分