自学内容网 自学内容网

基于FPGA的DDS信号发生器(图文并茂+深度原理解析)

        篇幅有限,本文详细源文件已打包 至个人主页资源,需要自取......


前言

        DDS(直接数字合成)技术是先进的频率合成手段,在数字信号处理与硬件实现领域作用关键。它因低成本、低功耗、高分辨率以及快速转换时间等优点备受认可。

        本文着重探究基于 FPGA 的简易 DDS 信号发生器设计原理与流程,同时给出 Verilog 代码实例。从原理剖析到具体实现步骤逐步深入,阐述如何利用 FPGA 技术与 DDS 技术相结合,实现信号发生器功能,为相关领域技术人员提供有价值的参考与借鉴。

一、DDS是什么?

        DDS(Direct Digital Synthesizer,直接数字合成器)是一种数字合成技术,它利用数字方式生成模拟信号。

二、物理层

1.结构示意图

        DDS基本结构主要由相位累加器、相位调制器、波形数据表ROM、D/A转换器等四大结构组成。DDS结构示意图,如下图所示

        1.相位累加器(Phase Accumulator)

        作为DDS的核心,相位累加器负责生成相位码,其输入为频率字输入,位宽通常用N表示。相位累加器的输出是连续累加的结果,用于控制信号的频率。

        2.相位调制器(Phase Modulator)

        接收相位累加器的输出,并加上相位偏移值P,用于实现信号的相位调制
        3.波形数据表ROM(Waveform ROM)

        存储一个或多个周期的波形数据,如正弦波。ROM的地址由相位调制器的输出决定,从而读取相应的波形数据。
        4.数模转换器(D/A Converter)

        将波形数据表ROM输出的数字信号转换为模拟信号,即最终的输出信号CLK_OUT。

2.DDS工作原理

        DDS信号发生器基本原理是通过查找表法读取ROM中存储的三角波,方波,锯齿波等数据,通过处理,能做到输出的波形频率和相位可调制,主要步骤如下:

        1.系统时钟 CLK 为整个系统的工作时钟,频率为 fclk;

        2.频率字输入 F_WORD(用 K 表示),数值大小控制输出信号的频率大小,数值越大输出信号频率越高,反之,输出信号频率越低;

        频率字输入K,表示相位增量,设其位宽为N,满足等式K = 2N * fOUT / fCLK。

        3.相位字输入P_WORD(用 P 表示),为整数,数值大小控制输出信号的相位偏移,主要用于相位的信号调制;

        4.输出信号为 CLK_OUT,频率为 fout;

        5.相位累加器根据频率字输入K和系统时钟频率Fclk累加相位值,生成相位码。相位累加器是DDS信号发生器的核心部分,它的作用是逐周期地累积相位。相位累加器通常是一个N位的寄存器,其值在每个系统时钟周期CLK下累加频率控制字Fword。相位累加的过程可以用以下公式表示:

        Phase_Acc = Phase_Acc + Fword

其中,Phase_Acc是当前时钟周期的相位累加值,Fword是频率控制字,它决定了累加的步长。

        相位累加寄存器通常用于存储相位累加器的当前值,以便进行相位调制或作为查找ROM的地址,记为Phase_Reg。考虑到ROM表地址深度M的影响,相位累加寄存器取Phase_Acc高M比特,也就是Phase_Reg = Phase_Acc >> (N - M)

        6.相位调制器根据相位字输入P调整相位累加器的输出,实现相位调制。相位调制器接收相位寄存器的输出,并可能加上一个相位控制字Pword,用于实现信号的相位偏移或调制。相位调制可以用以下公式表示:

        Phase_Mod = Phase_Reg + Pword

Phase_Reg是相位寄存器的输出,Pword是相位控制字。

        7.波形数据表ROM根据相位调制器的输出地址Phase_Mod,读取对应的波形数据,将ROM表的地址位宽记为M。

        假设波形数据ROM的地址位宽为12位,存储数据位宽为8位,即ROM有212 = 4096个存储空间,每个存储空间可存储1字节数据。

        8.D/A转换器将ROM输出的数字波形数据转换为模拟信号CLK_OUT,频率为fOUT,计算公式如下: fOUT = K * fCLK / 2N。当K = 1时,可得DDS最小分辨率为:fOUT = fCLK / 2N,此时输出信号频率最低。根据采样定理,K的最大值应小于2N / 2。

三、设计思路

1.模块图

        

        key_ctrl模块:生成选择信号,选择输出的波形是三角波,方波还是锯齿波,同时实例化按键消抖模块

        dds_ctrl模块:对输入的按键选择信号控制rom的读取操作,生成需要的波形,同时能实现频率相位可调

2.时序图

3.代码实现

module dds_ctrl(
inputwiresys_clk,
inputwiresys_rst_n,
inputwire[3:0]wave_sel,
inputwiretouch_key1,
inputwiretouch_key2,

outputwire[7:0]dac_data,
outputwire[7:0]dac_data1
);

reg [11:0]F_WORD;
reg [11:0]P_WORD;
reg [23:0]fre_add;
reg [11:0]rom_add_reg;
reg [11:0]rom_add_reg1;
reg[13:0]rom_addr;
reg[13:0]rom_addr1;

wirekey_flag;
//wirekey_flag1;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
F_WORD <= 12'd500 ;
else if(F_WORD == 12'd4096)
F_WORD <= 12'd500 ;
else if(touch_key1 == 1'b0)
F_WORD <= F_WORD + 4'd10 ;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
P_WORD <= 12'd0 ;
else if(P_WORD == 12'd4095)
P_WORD <= 12'd0 ;
else if(key_flag == 1'b1)
P_WORD <= P_WORD + 10'd512 ;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
fre_add <= 24'd0 ;
else 
fre_add <= fre_add + F_WORD ;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
rom_add_reg <= 12'd0 ;
else 
rom_add_reg <= fre_add[23:12] + P_WORD ;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
rom_add_reg1 <= 12'd0 ;
else 
rom_add_reg1 <= fre_add[23:12] ;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
rom_addr <= 14'd0 ;
else 
case(wave_sel)
4'b0001:
rom_addr <= rom_add_reg ;
4'b0010:
rom_addr <= rom_add_reg + 14'd4096 ;
4'b0100: 
rom_addr <= rom_add_reg + 14'd8192 ;
4'b1000:
rom_addr <= rom_add_reg + 14'd12288 ;
default: rom_addr <= rom_add_reg ;
endcase

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
rom_addr1 <= 14'd0 ;
else 
case(wave_sel)
4'b0001:
rom_addr1 <= rom_add_reg1 ;
4'b0010:
rom_addr1 <= rom_add_reg1 + 14'd4096 ;
4'b0100: 
rom_addr1 <= rom_add_reg1 + 14'd8192 ;
4'b1000:
rom_addr1 <= rom_add_reg1 + 14'd12288 ;
default: rom_addr1 <= rom_add_reg1 ;
endcase

rom_waverom_wave_inst (
.address ( rom_addr ),
.clock  ( sys_clk  ),
.q  ( dac_data  )
);

rom_waverom_wave_inst1 (
.address ( rom_addr1 ),
.clock  ( sys_clk  ),
.q  ( dac_data1  )
);


touch_key touch_key_u1(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.key_in(touch_key2),
                 
.key_flag(key_flag)
);

/* touch_key touch_key_u2(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.key_in(touch_key1),
                 
.key_flag(key_flag1)
); */

endmodule  
module key_ctrl(
inputwiresys_clk,
inputwiresys_rst_n,
inputwire[3:0]key,

outputreg [3:0]wave_sel 
);

wirekey3;
wirekey2;
wirekey1;
wirekey0;

always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
wave_sel <= 4'b0001 ;
else if(key3 == 1'b1) 
wave_sel <= 4'b1000 ;//锯齿波
else if(key2 == 1'b1) 
wave_sel <= 4'b0100 ;//
else if(key1 == 1'b1) 
wave_sel <= 4'b0010 ;//
else if(key0 == 1'b1) 
wave_sel <= 4'b0001 ;//正弦波

key_filter
#(
.CNT_MAX (20'd9)//.CNT_MAX (20'd999_999)
)
key_filter_u1
(
.clk (sys_clk),
.rst_n   (sys_rst_n ),
.key_in  (key[3]  ),
          
.key_flag(key3    )
);

key_filter
#(
.CNT_MAX (20'd9)//.CNT_MAX (20'd999_999)
)
key_filter_u2
(
.clk (sys_clk),
.rst_n   (sys_rst_n ),
.key_in  (key[2]  ),
          
.key_flag(key2    )
);

key_filter
#(
.CNT_MAX (20'd9)//.CNT_MAX (20'd999_999)
)
key_filter_u3
(
.clk (sys_clk),
.rst_n   (sys_rst_n ),
.key_in  (key[1]  ),
          
.key_flag(key1    )
);

key_filter
#(
.CNT_MAX (20'd9)//.CNT_MAX (20'd999_999)
)
key_filter_u4
(
.clk (sys_clk),
.rst_n   (sys_rst_n ),
.key_in  (key[0]  ),
          
.key_flag(key0    )
);

endmodule

总结

DDS并不复杂,只需要搞清楚原理,很容易快速掌握。

1、通过调节频率控制字K,可以控制相位累加器的累加速度,进而ROM读取地址的速度,这样就可以控制输出波形频率了;

2、通过调节相位控制字P,可以控制相位调制器,进而控制ROM读取地址的初值,这样就可以控制输出波形的初值;

3、通过调整ROM表中的数据,可以通过matlab、python等生成不同的波形数据,进而输出不同的波形。


原文地址:https://blog.csdn.net/weixin_60580395/article/details/142864090

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!