文章目录[隐藏]
目录
工程下载地址:https://download.csdn.net/download/qq_33231534/12848911
一、DDS原理
DDS全称为直接数字频率合成(Direct Digital Synthesis),其基本原理是在一个周期波形数据下,通过选取其中全部数据或抽样部分数据组成新的波形,由奈奎斯特采样定理可知,最低两个采样点就可以组成一个波形,但实际上最少需要4个点。其原理框图如下:
其主要由相位控制字、频率控制字、相位累加器、波形存储器几部分组成。
波形存储器:存储一个周期波形的离散信号;
频率控制字:用以控制生成的波形频率。
相位累加器:用来控制波形的相位累加,组成完整的波形显示。
相位控制字:用以控制波形起始位置。
二、整体系统设计
1、现有条件
本实验平台是小梅哥的AC620开发板,板载12位采样精度的DAC芯片TLV5618,输出电压范围为0V~4.096V,其最高时钟频率为20MHz。
2、实验性能分析
由于板载的DAC芯片最高采样频率为20MHz,为了设计余量,同时只是为了验证设计的正确性,这里将DAC采样频率设定为10MHz,同时TLV5618的DAC芯片采用的是SPI借口通信,传输一次数据需要差不多16个时钟周期,这里将其看成20个时钟周期,因此接收数据的最高频率为10/20=0.5MHz。因此本实验信号发生器最高生成的频率设置为0.5MHz。
3、系统模块设计
这里没有做DAC驱动模块,在我前面的博客数据采集系统中有用到DAC驱动模块,由于我身边没有示波器,无法测波形,只能通过仿真软件测试设计的正确性,因此这里不做DAC驱动模块。下边将对各个模块分别讲解:
(1)频率设置模块(f_word_set.v)
这里通过按键依次对频率进行改变,这里设置可支持的频率包括 1Hz、10Hz、100Hz、500Hz、1KHz、5KHz、10KHz、50KHz、100KHz、200KHz、500KHz 共11种不同的选择,按键按下依次切换。
这里对不同频率波形的频率控制字进行计算。为了获取1Hz、10Hz等低频信号,在对其进行相位累加的时候,需要进行其他的计数,这里选取20位宽供其累加,还有12位供波形数据累加,共32位数据进行累加操作,例如fre_acc[31:0],其中低20位数据作为补充累加,高12位作为波形数据累加。对于要生成1Hz波形来说,假设每次需要加x个时钟周期,1Hz周期为T=1/f(此处周期用ns表示),在Tns后32位数据加满,采用50MHz系统时钟,1系统时钟周期20ns,因此有:(T/20)*x=2^32,因此频率控制字计算公式为: x = (2^32)*20/T = (2^32)*20*f(hz)/1000000000 ;
最后得出的各个频率的控制字数据为:
1Hz~86;10Hz~859;100Hz~8590;500Hz~42950;1000Hz~85899;5000Hz~429497;10KHz~858993;50KHz~4294967;100KHz~8589935;200KHz~17179869;500KHz~42949673。
代码如下,其中里边按键消抖模块采用前面博客写的按键消抖模块。
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-04 15:25:53
// Revise Data : 2020-09-04 17:06:45
// File Name : F_word_set.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description : 频率控制字的生成
module F_word_set(
input clk ,
input rst_n ,
input key1_in ,
output reg [25:0] f_word
);
wire key_flag ;
wire key_state ;
reg [3:0] cnt ;
key_filter fword_key (
.clk (clk),
.rst_n (rst_n),
.key_in (key1_in),
.key_flag (key_flag),
.key_state (key_state)
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 4'd0;
end
else if (key_flag) begin
if (cnt==4'd10) begin
cnt <= 4'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
f_word <= 0;
end
else begin
case(cnt)
4'd0:f_word = 26'd86; //1Hz
4'd1:f_word = 26'd859; //10Hz
4'd2:f_word = 26'd8590; //100Hz
4'd3:f_word = 26'd42950; //500Hz
4'd4:f_word = 26'd85899; //1kHz
4'd5:f_word = 26'd429497; //5kHz
4'd6:f_word = 26'd858993; //10kHz
4'd7:f_word = 26'd4294967; //50kHz
4'd8:f_word = 26'd8589935; //100kHz
4'd9:f_word = 26'd17179869; //200kHz
4'd10:f_word = 26'd42949673;//500kHz
default:;
endcase
end
end
endmodule
(2)波形设置模块(wave_set.v)
这里主要通过按键设置4种波形:正弦波、三角波、锯齿波、方波。这里通过按键按下,改变波形控制字的数据,这里没有放各个波形的ROM模块,ROM模块放在DDS模块中,以便进行数据输出。
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-04 15:10:48
// Revise Data : 2020-09-04 15:23:44
// File Name : wave_set.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description : dds信号发生器的波形选择,按键按下切换波形
module wave_set(
input clk ,
input rst_n ,
input key0_in ,
output reg [1:0] wave_c //wave_c oo~正弦波 01~三角波 10~锯齿波 11~方波
);
wire key_flag ;
wire key_state ;
key_filter wave_key (
.clk (clk),
.rst_n (rst_n),
.key_in (key0_in),
.key_flag (key_flag),
.key_state (key_state)
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wave_c <= 0; //默认正弦波
end
else if (key_flag) begin
wave_c <= wave_c + 1'b1;
end
end
endmodule
(3)幅度设置模块(amplitude_set.v)
通过按键控制波形幅度设置,这里可以设置为原波形的1倍、1/2倍、1/4倍、1/8倍、1/16倍。
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-05 09:35:58
// Revise Data : 2020-09-05 09:35:58
// File Name : amplitude_set.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description : 信号电压幅度设置 1/2/4/8/16分之一
module amplitude_set(
input clk ,
input rst_n ,
input key2_in ,
output reg [4:0] amplitude
);
reg [2:0] cnt ;
wire key_flag ;
wire key_state ;
key_filter amplitude_key (
.clk (clk),
.rst_n (rst_n),
.key_in (key2_in),
.key_flag (key_flag),
.key_state (key_state)
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 3'd0;
end
else if (key_flag) begin
if (cnt == 3'd4) begin
cnt <= 3'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
amplitude <= 0;
end
else begin
case(cnt)
3'd0: amplitude <= 5'd1;
3'd1: amplitude <= 5'd2;
3'd2: amplitude <= 5'd4;
3'd3: amplitude <= 5'd8;
3'd4: amplitude <= 5'd16;
default:amplitude <= 5'd1;
endcase
end
end
endmodule
(4)DDS模块(DDS.v)
这个模块例化四个波形存储ROM模块(ROM模块很简单,在数据采集系统里也写过,这里不再赘述),同时进行DDS的相位累加,通过查找表,读出ROM中的数据。
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-04 17:09:55
// Revise Data : 2020-09-04 17:31:29
// File Name : DDS.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description : DDS模块
module DDS(
input clk ,
input rst_n ,
input [25:0] f_word ,
input [1:0] wave_c ,
input [11:0] p_word ,
input [4:0] amplitude ,
output reg [11:0] dac_data
);
localparam DATA_WIDTH = 4'd12;
localparam ADDR_WIDTH = 4'd12;
reg [11:0] addr ;
wire [11:0] dac_data0;
wire [11:0] dac_data1;
wire [11:0] dac_data2;
wire [11:0] dac_data3;
//波形选择
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dac_data <= 12'd0;
end
else begin
case(wave_c)
2'b00:dac_data <= dac_data0/amplitude; //正弦波
2'b01:dac_data <= dac_data1/amplitude; //三角波
2'b10:dac_data <= dac_data2/amplitude; //锯齿波
2'b11:dac_data <= dac_data3/amplitude; //方波
default:;
endcase
end
end
//相位累加器
reg [31:0] fre_acc;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
fre_acc <= 0;
end
else begin
fre_acc <= fre_acc + f_word;
end
end
//生成查找表地址
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
addr <= 0;
end
else begin
addr <= fre_acc[31:20] + p_word;
end
end
//正弦波
sin_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_sin_rom (
.addr (addr),
.clk (clk),
.q (dac_data0)
);
//三角波
sanjiao_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_sanjiao_rom (
.addr (addr),
.clk (clk),
.q (dac_data1)
);
//锯齿波
juchi_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_juchi_rom (
.addr (addr),
.clk (clk),
.q (dac_data2)
);
//方波
fangbo_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_fangbo_rom (
.addr (addr),
.clk (clk),
.q (dac_data3)
);
endmodule
(5)顶层模块(DDS_top.v)
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-04 18:32:24
// Revise Data : 2020-09-04 19:03:10
// File Name : DDS_top.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description :
module DDS_top(
input clk ,
input rst_n ,
input key0_in ,
input key1_in ,
input key2_in ,
output wire [11:0] dac_data
);
wire [1:0] wave_c ;
wire [25:0] f_word ;
wire [4:0] amplitude ;
DDS inst_DDS
(
.clk (clk),
.rst_n (rst_n),
.f_word (f_word),
.wave_c (wave_c),
.p_word (12'd0),
.amplitude(amplitude),
.dac_data (dac_data)
);
F_word_set inst_F_word_set
(
.clk(clk),
.rst_n(rst_n),
.key1_in(key1_in),
.f_word(f_word)
);
wave_set inst_wave_set
(
.clk(clk),
.rst_n(rst_n),
.key0_in(key0_in),
.wave_c(wave_c)
);
amplitude_set inst_amplitude_set(
.clk (clk) ,
.rst_n (rst_n) ,
.key2_in(key2_in) ,
.amplitude(amplitude)
);
endmodule
4、仿真验证
由于仿真时间会比较长,因此对不同波形,不同功能分开测试,其主要代码如下:
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-04 19:07:11
// Revise Data : 2020-09-04 22:50:36
// File Name : DDS_top_tb.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description :
`timescale 1ns/1ns
module DDS_top_tb();
reg clk ;
reg rst_n ;
reg key0_in ;
reg key1_in ;
reg key2_in ;
wire [11:0] dac_data ;
localparam clk_period = 20;
DDS_top inst_DDS_top
(
.clk (clk),
.rst_n (rst_n),
.key0_in (key0_in),
.key1_in (key1_in),
.key2_in (key2_in),
.dac_data (dac_data)
);
initial clk = 0;
always #(clk_period/2) clk = ~clk;
initial begin
#1;
rst_n = 0;
key0_in = 1;
key1_in = 1;
key2_in = 1;
#(clk_period*20);
rst_n = 1;
#(clk_period*10);
// key0_in = 0;
// #30000000;
// key0_in = 1;
// #30000000;
// key0_in = 0;
// #30000000;
// key0_in = 1;
// #30000000;
// key0_in = 0;
// #30000000;
// key0_in = 1;
//#2000000000;
key1_in = 0;
#30000000;
key1_in = 1;
#30000000;
//#200000000;
key1_in = 0;
#30000000;
key1_in = 1;
#30000000;
//#20000000;
key1_in = 0;
#30000000;
key1_in = 1;
#30000000;
#4000000;
key2_in = 0;
#30000000;
key2_in = 1;
#30000000;
#4000000;
key2_in = 0;
#30000000;
key2_in = 1;
#30000000;
#4000000;
key2_in = 0;
#30000000;
key2_in = 1;
#30000000;
#4000000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #2000000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #400000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #200000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #40000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #20000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #10000;
// key1_in = 0;
// #30000000;
// key1_in = 1;
// #30000000;
// #4000;
#(clk_period*20);
$stop;
end
endmodule
仿真波形:
(1)1Hz正弦波
(2)1Hz三角波
(3)1Hz锯齿波
(4)1Hz方波
(5)不同频率方波
(6)不同频率方波
(7)不同频率正弦波
(8)不同频率三角波
(9)不同频率锯齿波
(10)不同幅度正弦波
三、总结
整个设计从仿真来看,符合预期条件,但是没有通过DAC模块进行上板测试。此设计基本完成了DDS信号发生器的设计,有其他不足之处,敬请指正。
版权声明:本文为CSDN博主「panhongfeng111」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33231534/article/details/108424647
暂无评论