一、實驗內(nèi)容
在FPGA上設(shè)計一個DDS模塊,在DE0 開發(fā)板上運行,在FPGA芯片內(nèi)部合成出數(shù)字波形即可。不用輸出模擬信號,本模塊滿足以下條件:
使用板載晶振的50MHz時鐘,合成以下頻率的信號
- 1 、500KHz 正弦波信號。 2、1MHz 正弦波信號。 3、3MHz 正弦波信號。
-頻率字字長32位,波表ROM尺寸為 10比特地址,1024個word
- 波形格式為2補碼格式,12比特量化
- 每個CLK輸出一個有效樣點。
- 輸入信號為頻率字和頻率字輸入使能信號
- 使用板載的撥碼開關(guān)(Switch)控制生成的波形信號的不同頻率。
二、設(shè)計思路RTL電路圖
設(shè)計中根據(jù)DDS輸出波形頻率的計算公式:
確定輸出頻率。
上式中為輸出頻率,為輸入頻率,即為系統(tǒng)基準時鐘頻率50MHz。m為地址加法器的寬度,K為頻率控制字。設(shè)計中通過控制K的大小控制輸出頻率,由于K只能取整數(shù),輸出頻率可能會有一定偏差。
三、Quartus掃描生成的RTL電路圖
四、實驗相關(guān)程序代碼
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、頂層設(shè)計模塊
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( //實例引用地址計數(shù)器模塊
.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) //數(shù)據(jù)輸出端
);
endmodule123456789101112131415161718192021
3、正弦波形存儲模塊C語言程序
#include《stdio.h》
#include《math.h》
#define PI 3.141593
#define DEPTH 1024 /* 數(shù)據(jù)深度,即存儲單元的個數(shù) */
#define WIDTH 12 /* 存儲單元的寬度 */
int main(void)
{
int n,temp;
float v;
FILE * fp;
/* 建立文件名為sine1024.mif新文件,允許寫入數(shù)據(jù),
文件名隨意,但擴展名必須為.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 ”);
/* 以十六進制輸出地址和數(shù)據(jù) */
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將數(shù)值平移到0~2之間
/* 以十六進制輸出地址和數(shù)據(jù) */
fprintf(fp,“%x : %x; ”,n,temp);
}
fprintf(fp,“END; ”);
fclose(fp); //關(guān)閉文件
}
}123456789101112131415161718192021222324252627282930313233343536373839
4、matlab正弦波頻譜分析程序
將signal tap采集的正弦波數(shù)據(jù)生成.txt文件保存,導入到matlab中分析頻譜。
clear all; close all;
varnum; %調(diào)用signal tap 采集的正弦波數(shù)據(jù),列矢量
signal=transpose(VarName); %轉(zhuǎn)置
fs=50E6; %采樣頻率
N=1024; %采樣點數(shù)
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; %換算成實際的頻率值,F(xiàn)n=(n-1)*Fs/N
figure(2);
stem(F(1:N/2),Ayy(1:N/2)); %顯示換算后的FFT模值結(jié)果
axis([0 5E6 0 2500]);
title(‘正弦信號頻譜圖’);
xlabel(‘Frequency (Hz)’);
ylabel(‘Magnitude’);12345678910111213141516171819202122
五、實驗結(jié)果
1、signal tap 數(shù)據(jù)截圖
(1)f1=500kHz正弦波,地址位寬m=10,頻率控制字K=10
(2)f2=1MHz正弦波,地址位寬m=10,頻率控制字K=20
(2)f2=3MHz正弦波,地址位寬m=10,頻率控制字K=61
2、matlab頻譜分析
由頻譜圖可以看出DDS輸出的頻率略小于實驗要求的頻率。這是由于實驗中頻率控制字只能取整數(shù),略去了小數(shù)位,實際取值小于理論計算值。實驗結(jié)果與理論推算結(jié)果是一致的。
評論
查看更多