前言
設(shè)計(jì)一個(gè)能產(chǎn)生頻率可變、相位可調(diào)的能產(chǎn)生正弦波、三角波、方波、鋸齒波的信號(hào)發(fā)生器。
一、DDS信號(hào)發(fā)生器
1.DDS是什么
DDS 是直接數(shù)字式頻率合成器(Direct Digital Synthesizer)的英文縮寫,是一項(xiàng)關(guān)鍵的數(shù)字化技術(shù)。與傳統(tǒng)的頻率合成器相比,DDS 具有低成本、低功耗、高分辨率和快速轉(zhuǎn)換時(shí)間等優(yōu)點(diǎn),廣泛使用在電信與電子儀器領(lǐng)域,是實(shí)現(xiàn)設(shè)備全數(shù)字化的一個(gè)關(guān)鍵技術(shù)。作為設(shè)計(jì)人員,我們習(xí)慣稱它為信號(hào)發(fā)生器,一般用它產(chǎn)生正弦、鋸齒、方波等不同波形或不同頻率的信號(hào)波形,在電子設(shè)計(jì)和測(cè)試中得到廣泛應(yīng)用。
注:圖片摘自《FPGA Verliog開發(fā)實(shí)戰(zhàn)指南》
圖中主要包括相位累加器、相位調(diào)制器、波形存儲(chǔ)器、數(shù)模轉(zhuǎn)換器四大結(jié)構(gòu)。
2.DDS工作原理
頻率字K,數(shù)值大小控制輸出信號(hào)的頻率大小,數(shù)值越大輸出信號(hào)頻率越高,反之越小。
相位字P,數(shù)值大小控制輸出信號(hào)的相位偏移,主要用于相位的信號(hào)調(diào)制。
相位累加器輸入為頻率字輸入K表示相位增量,設(shè)其位寬為N,滿足等式K=2^N*fout/fclk,其在輸入相位累加器之前,在系統(tǒng)時(shí)鐘同步下做數(shù)據(jù)寄存,數(shù)據(jù)改變時(shí)不會(huì)干擾相位累加器的正常工作。
波形數(shù)據(jù)表 ROM 中存有一個(gè)完整周期的正弦波信號(hào)。假設(shè)波形數(shù)據(jù) ROM 的地址位寬為 12 位,存儲(chǔ)數(shù)據(jù)位寬為 8 位,即 ROM 有 212 = 4096 個(gè)存儲(chǔ)空間,每個(gè)存儲(chǔ)空間可存儲(chǔ) 1字節(jié)數(shù)據(jù)。將一個(gè)周期的正弦波信號(hào),沿橫軸等間隔采樣 212 = 4096 次,每次采集的信號(hào)幅度用 1 字節(jié)數(shù)據(jù)表示,最大值為 255,最小值為 0。將 4096 次采樣結(jié)果按順序?qū)懭?ROM的 4096 個(gè)存儲(chǔ)單元,一個(gè)完整周期正弦波的數(shù)字幅度信號(hào)寫入了波形數(shù)據(jù)表 ROM 中。波形數(shù)據(jù)表 ROM 以相位調(diào)制器傳入的相位碼為 ROM 讀地址,將地址對(duì)應(yīng)存儲(chǔ)單元中的電壓幅值數(shù)字量輸出。
D/A 轉(zhuǎn) 換 器 將 輸 入 的 電 壓 幅 值 數(shù) 字 量 轉(zhuǎn) 換 為 模 擬 量 輸 出 , 就 得 到 輸 出 信 號(hào)CLK_OUT。
輸出信號(hào) CLK_OUT 的信號(hào)頻率 fOUT = K * fCLK / 2N。當(dāng) K = 1 時(shí),可得 DDS 最小分辨率為:fOUT = fCLK / 2N,此時(shí)輸出信號(hào)頻率最低。根據(jù)采樣定理,K 的最大值應(yīng)小于 2N / 2。
相位累加器每計(jì)數(shù) 2N 次,對(duì)應(yīng)一個(gè)正弦周期。而相位累加器 1 秒鐘計(jì)數(shù) fCLK次,在 k=1 時(shí),DDS 輸出的時(shí)鐘頻率就是頻率分辨率。頻率控制字 K 增加時(shí),相位累加器溢出的頻率增加,對(duì)應(yīng) DDS 輸出信號(hào) CLK_OUT 頻率變?yōu)?K 倍的 DDS 頻率分辨率。
DAC:自波形數(shù)據(jù)表 ROM 輸出的波形數(shù)據(jù)傳入 D/A 轉(zhuǎn)換器轉(zhuǎn)換為模擬信號(hào)。D/A 轉(zhuǎn)換器即數(shù)/模轉(zhuǎn)換器,簡稱 DAC(Digital to Analog Conver),是指將數(shù)字信號(hào)轉(zhuǎn)換為模擬信號(hào)的電子元件或電路。
DAC使用外部掛載的高速AD/DA板卡。
二、模塊代碼
1.調(diào)用rom模塊儲(chǔ)存波形圖
首先使用matlab產(chǎn)生四種波形的mif文件,深度為4096*4,matlab代碼見另一篇文章。
2.按鍵控制模塊
module key_ctrl(
input wire clk,
input wire rst_n,
input wire [3:0]key,
output reg [3:0]wave_select
);
wire key0;
wire key1;
wire key2;
wire key3;
parameter sin_wave=4'b0001, //正弦波
squ_wave=4'b0010, //方波
tri_wave=4'b0100, //三角波
saw_wave=4'b1000; //鋸齒波
key_filter key_filter0(
.clk(clk),
.rst_n(rst_n),
.key_in(key[0]),
.key_flag(key0)
);
key_filter key_filter1(
.clk(clk),
.rst_n(rst_n),
.key_in(key[1]),
.key_flag(key1)
);
key_filter key_filter2(
.clk(clk),
.rst_n(rst_n),
.key_in(key[2]),
.key_flag(key2)
);
key_filter key_filter3(
.clk(clk),
.rst_n(rst_n),
.key_in(key[3]),
.key_flag(key3)
);
always @(posedge clk or negedge rst_n)
if(!rst_n)
wave_select<=4'b0000;
else if(key0)
wave_select<=sin_wave;
else if(key1)
wave_select<=squ_wave;
else if(key2)
wave_select<=tri_wave;
else if(key3)
wave_select<=saw_wave;
else
wave_select<=wave_select;
endmodule
按下四個(gè)按鍵分別生成四種波形
2.按鍵消抖模塊
module key_filter
#(parameter CNT_MAX=999_999)
(
input wire clk,
input wire rst_n,
input wire key_in,
output reg key_flag
);
reg [19:0]cnt_20;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt_20<=1'b0;
else if(key_in==1'b1)
cnt_20<=1'b0;
else if(cnt_20==CNT_MAX && key_in==1'b0)
cnt_20<=cnt_20;
else
cnt_20<=cnt_20+1'b1;
always @(posedge clk or negedge rst_n)
if(!rst_n)
key_flag<=1'b0;
else if(cnt_20==CNT_MAX-1'b1)
key_flag<=1'b1;
else
key_flag<=1'b0;
endmodule
3.DDS生成模塊
module dds(
input wire clk,
input wire rst_n,
input wire [3:0]wave_select,
output wire [7:0]data_out
);
parameter sin_wave=4'b0001, //正弦波
squ_wave=4'b0010, //方波
tri_wave=4'b0100, //三角波
saw_wave=4'b1000; //鋸齒波
//本實(shí)驗(yàn),我們希望輸出一個(gè)頻率為 500Hz,初相位為π/2 的正弦波信號(hào)。
//計(jì)算參數(shù) FREQ_CTRL,即頻率輸入字 K。
//FREQ_CTRL = K = 2N * fOUT / fCLK,其中 N = 32(相位累加器輸出值 fre_add 的位寬)、 fOUT = 500Hz,
//fCLK = 50MHz,帶入公式,F(xiàn)REQ_CTRL = K = 42949.67296 ,取整數(shù)部分為42949;
//PHASE_CTRL = P = ? / (2π / 2M),其中 M =12(輸入 ROM 地址位寬)、? = π / 2,帶入公式,
//PHASE_CTRL = P = 1024。
//計(jì)算參數(shù) PHASE_CTRL,即相位輸入字 P。
parameter FREQ_CTRL=32'd42949,//相位累加器單次累加值,
PHASE_CTRL=12'd1024;//相位偏移量
reg [31:0]fre_add; //相位累加器
reg [11:0]rom_addr_reg; //相位調(diào)制后的相位碼
reg [13:0]rom_addr; //ROM讀地址
//相位累加器
always @(posedge clk or negedge rst_n)
if(!rst_n)
fre_add<=1'b0;
else
fre_add<=fre_add+FREQ_CTRL;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
rom_addr<=1'b0;
rom_addr_reg<=1'b0;
end
else
case(wave_select)
sin_wave:
begin
rom_addr_reg<=fre_add[31:20]+PHASE_CTRL;
rom_addr<=rom_addr_reg;
end
squ_wave:
begin
rom_addr_reg<=fre_add[31:20]+PHASE_CTRL;
rom_addr<=rom_addr_reg+14'd4096;
end
tri_wave:
begin
rom_addr_reg<=fre_add[31:20]+PHASE_CTRL;
rom_addr<=rom_addr_reg+14'd8192;
end
saw_wave:
begin
rom_addr_reg<=fre_add[31:20]+PHASE_CTRL;
rom_addr<=rom_addr_reg+14'd12288;
end
default:
begin
rom_addr_reg<=fre_add[31:20]+PHASE_CTRL;
rom_addr<=rom_addr_reg;
end
endcase
wave_ip wave_ip0(
.address(rom_addr),
.clock(clk),
.q(data_out)
);
endmodule
4.頂層模塊
module dds_top(
input wire clk,
input wire rst_n,
input wire [3:0]key,
output wire dac_clk, //輸出DAC模塊時(shí)鐘
output wire [7:0]dac_data
);
wire [3:0]wave_select;
assign dac_clk=~clk;
dds dds0(
.clk(clk),
.rst_n(rst_n),
.wave_select(wave_select),
.data_out(dac_data)
);
key_ctrl key_ctrl0(
.clk(clk),
.rst_n(rst_n),
.key(key),
.wave_select(wave_select)
);
endmodule
5.RTL視圖
三、仿真測(cè)試模塊
1.仿真測(cè)試代碼
`timescale 1ns/1ns
`define clk_period 20
module dds_top_tb;
reg clk;
reg rst_n;
reg [3:0]key;
wire dac_clk; //輸出DAC模塊時(shí)鐘
wire [7:0]dac_data;
reg [21:0]tb_cnt;
reg key_in;
reg [1:0]cnt_key;
defparam dds_top_inst.key_ctrl0.key_filter0.CNT_MAX=24,
dds_top_inst.key_ctrl0.key_filter1.CNT_MAX=24,
dds_top_inst.key_ctrl0.key_filter2.CNT_MAX=24,
dds_top_inst.key_ctrl0.key_filter3.CNT_MAX=24;
parameter CNT_1MS = 20'd19000 ,
CNT_11MS = 21'd69000 ,
CNT_41MS = 22'd149000 ,
CNT_51MS = 22'd199000 ,
CNT_60MS = 22'd249000 ;
dds_top dds_top_inst(
.clk(clk),
.rst_n(rst_n),
.key(key),
.dac_clk(dac_clk), //輸出DAC模塊時(shí)鐘
.dac_data(dac_data)
);
initial clk=1'b1;
always #(`clk_period/2) clk=~clk;
initial begin
rst_n=1'b0;
#(`clk_period*20+1);
rst_n=1'b1;
end
//tb_cnt:按鍵過程計(jì)數(shù)器,通過該計(jì)數(shù)器的計(jì)數(shù)時(shí)間來模擬按鍵的抖動(dòng)過程
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
tb_cnt <= 22'b0;
else if(tb_cnt == CNT_60MS)
tb_cnt <= 22'b0;
else
tb_cnt <= tb_cnt + 1'b1;
//key_in:產(chǎn)生輸入隨機(jī)數(shù),模擬按鍵的輸入情況
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
key_in <= 1'b1;
else if((tb_cnt >= CNT_1MS && tb_cnt <= CNT_11MS) || (tb_cnt >= CNT_41MS && tb_cnt <= CNT_51MS))
key_in <= {$random} % 2;
else if(tb_cnt >= CNT_11MS && tb_cnt <= CNT_41MS)
key_in <= 1'b0;
else
key_in <= 1'b1;
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
cnt_key <= 2'd0;
else if(tb_cnt == CNT_60MS)
cnt_key <= cnt_key + 1'b1;
else
cnt_key <= cnt_key;
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
key <= 4'b1111;
else
case(cnt_key)
0: key <= {3'b111,key_in};
1: key <= {2'b11,key_in,1'b1};
2: key <= {1'b1,key_in,2'b11};
3: key <= {key_in,3'b111};
default:key <= 4'b1111;
endcase
endmodule
2.仿真波形圖
可以看到,第一部分波形為正弦波,第二部分為方波,第三部分為三角波,第四部分為鋸齒波,設(shè)計(jì)成功。文章來源:http://www.zghlxwxcb.cn/news/detail-781102.html
總結(jié)
可以通過dds代碼中頻率字與相位字的改變來實(shí)現(xiàn)更多的波形變化。文章來源地址http://www.zghlxwxcb.cn/news/detail-781102.html
到了這里,關(guān)于FPGA之簡易DDS信號(hào)發(fā)生器設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!