DDS发生器的verilog实现(三)

前面讲解了正弦波发生器和DDS基础知识,这篇文章主要讲解如何在fpga上实现DDS发生器,同时对上一篇的文章进行补充。

确定频率控制字的DDS发生器

首先对初始条件做一假设:相位累加寄存器的位宽为n=32位,用来存储离散正弦波的RAM规格为256*8bit,使用的采样频率fc=50Mhz,要求DDS输出波形的频率为f0=1Mhz。则可以通过前面的公式f0 = fc * M / 2^n,可以计算出频率控制字M = 85899345,直接在正弦波发生器的代码上进行修改即可:

module ex_dds(input  wire            clk,   //50Mhzinput     wire            rst_n,output    wire    [7:0]   o_wave
);parameter FRQ_W = 32'd85899346;//频率控制字M,现在要求目标频率为1Mhz,相位累加器为32位,所以M=85899346;
reg     [31:0]  phase_sum;
wire    [7:0]   addr;//相位累加器
always @(posedge clk)beginif(!rst_n)phase_sum <= 32'd0;else phase_sum <= phase_sum + FRQ_W;
endassign addr = phase_sum[31:24];sp_ram_256x8 sp_ram_256x8_inst (.clka(clk), // input clka.wea(1'b0), // input [0 : 0] wea.addra(addr), // input [7 : 0] addra.dina(8'd0), // input [7 : 0] dina.douta(o_wave) // output [7 : 0] douta
);endmodule

注:在这里我们使用的离散正弦波和RAM IP核仍然是正弦波发生器部分的。

在modelsim中进行仿真,可以看到一个周期刚好1us:

频率控制字变化的DDS发生器

在很多地方,我们可能需要使用不同频率的输出波形,比如在FSK调制等地方,对信号进行调制时,使用的不是单一频率的波形,而是使用不同频率的波形对信号进行调制。此时,我们就需要DDS发生器输出的波形频率按照我们的需求变化,而不是一个确定的频率。因为频率控制字控制着DDS 所输出的正弦波的频率。因此,我们可以通过改变频率控制字的大小来改变输出波形的频率。

我们仍然在上面代码的基础上进行修改,每隔100个时钟周期改变一次输出波形的频率:

module ex_dds2(input wire            clk,    //50Mhzinput    wire            rst_n,output    wire    [7:0]   o_wave
);parameter FRQ_W = 32'd85899346;     //频率控制字M初始值,现在要求目标频率为1Mhz,相位累加器为32位
parameter   FRQ_ADD = 32'd85899346/2; //每次给频率控制字增加的量(自己根据需求设置)
reg     [31:0]  phase_sum;            //相位累加器
wire    [7:0]   addr;
reg     [31:0]  frq_word;             //变化的频率控制字
reg     [6:0]   div_cnt;
reg             div_flag;//分频器
always @(posedge clk)beginif(!rst_n)div_cnt <= 7'd0;else beginif(div_cnt == 7'd99)div_cnt <= 7'd0;else div_cnt <= div_cnt + 1'b1;end
end
always @(posedge clk)beginif(!rst_n)div_flag <= 1'b0;else beginif(div_cnt == 7'd99)div_flag <= 1'b1;else div_flag <= 1'b0;end
endalways @(posedge clk)beginif(!rst_n)frq_word <= FRQ_W;else if(div_flag)frq_word <= frq_word + FRQ_ADD;
end//相位累加器
always @(posedge clk)beginif(!rst_n)phase_sum <= 32'd0;else phase_sum <= phase_sum + frq_word;
endassign addr = phase_sum[31:24];sp_ram_256x8 sp_ram_256x8_inst (.clka(clk), // input clka.wea(1'b0), // input [0 : 0] wea.addra(addr), // input [7 : 0] addra.dina(8'd0), // input [7 : 0] dina.douta(o_wave) // output [7 : 0] douta
);endmodule

在modelsim中进行仿真:

我们只关注div_flag信号和o_wave信号。可以看到,div_flag每来一个高脉冲,o_wave的频率就会改变一次。

初始相位控制字

在前面的所有讨论中,都没有提及初始相位控制字,因为在前面的实现中,采用的初始相位都是0,即phase <= 32'd0,也可以通过仿真图看到o_wave波形都是从相位为零的位置开始输出。那么,当需要波形从相位为90度、180度等任意位置输出时该如何实现呢?

上面的框图就是带有初始相位控制字的DDS结构图。先对初始相位控制字、相位累加寄存器和RAM中存储的正弦波的关系进行理解。RAM中存储的是一个周期的正弦波,又因为正弦波就是一个圆周运动在一条直线上的投影,在这里引入一个动图便于理解:

所以我们将正弦波对应到一个圆上,因为相位累加器为32位,可以理解为将圆周等分成了2^32,从0到232-1,当在开始的时候,我们给相位累加器加上初始值0,正弦波就从相位为0的位置开始输出。因此当我们在开始时给相位累加器加上任意值,就可以让波形从任意相位开始输出。在开始时给相位累加器加的初始值就是这里的初始相位控制字。假设我们此时想让正弦波从相位为π的位置输出,对应到圆上,就是圆的180度的位置,此时是圆的相位的中间位置,因为相位累加器的位数决定了圆周等分的个数。如果将圆等分为232份,则180度对应的就是0到232-1的中间值,所以设置初始相位控制字为2^32/2 = 2^31;如果想让波形从相位为90度的位置开始输出,则对应的就是圆的相位的四分之一的位置,也就是0到232-1的四分之一的位置,可以设置初始相位累加器的值为2^32/4 = 2^30;其他位置计算方法相同。

下面用verilog实现带有初始相位控制字的DDS,继续在上面的代码上进行修改:

module ex_dds3(input wire            clk,            //50Mhzinput    wire            rst_n,output    wire    [7:0]   o_wave
);parameter FRQ_W       = 32'd85899346;     //频率控制字M,现在要求目标频率为1Mhz,相位累加器为32位,
parameter   FRQ_ADD     = 32'd85899346/2;   //每次给频率控制字增加的量(自己根据需求设置)
parameter   INIT_PHASE   = 32'd2147483648;   //初始相位,180度
//parameter     INIT_PHASE = 32'd1073741824;//初始相位,90度
reg     [31:0]  phase_sum;
wire    [7:0]   addr;
reg     [31:0]  frq_word;                    //变化的频率控制字
reg     [6:0]   div_cnt;
reg             div_flag;//分频器
always @(posedge clk)beginif(!rst_n)div_cnt <= 7'd0;else beginif(div_cnt == 7'd99)div_cnt <= 7'd0;else div_cnt <= div_cnt + 1'b1;end
end
always @(posedge clk)beginif(!rst_n)div_flag <= 1'b0;else beginif(div_cnt == 7'd99)div_flag <= 1'b1;else div_flag <= 1'b0;end
endalways @(posedge clk)beginif(!rst_n)frq_word <= FRQ_W;else if(div_flag)frq_word <= frq_word + FRQ_ADD;
end//相位累加器
always @(posedge clk)beginif(!rst_n)phase_sum <= INIT_PHASE;else phase_sum <= phase_sum + frq_word;
endassign addr = phase_sum[31:24];sp_ram_256x8 sp_ram_256x8_inst (.clka(clk), // input clka.wea(1'b0), // input [0 : 0] wea.addra(addr), // input [7 : 0] addra.dina(8'd0), // input [7 : 0] dina.douta(o_wave) // output [7 : 0] douta
);endmodule

在modelsim中进行仿真:

从图中可以看到输出波形o_wave初始相位发生了180度的翻转,

INIT_PHASE = 32'd1073741824时,输出波形的相位从90度开始:

DDS发生器的verilog实现(三)相关推荐

  1. DDS发生器的频率控制字原理和基本结构(二)

    DDS发生器的频率控制字原理和基本结构(二) 在正弦波发生器的verilog实现(一)中已经实现了最基本的功能,这篇文章将主要讲解DDS发生器的频率控制字原理和基本结构. 在这里先给出DDS发生器的结 ...

  2. 题目:用Verilog实现三分频电路,要求输出50%占空比。

    题目:用Verilog实现三分频电路,要求输出50%占空比. module Div_three(input clk,input rst_n,output div_three ); reg [1:0] ...

  3. 一、verilog编写三分频电路

    1.目标:使用verilog编写三分频电路,要求占空比大小为50%. 2.方法:分别使用上升沿和下降沿计数cnt_p以及cnt_n,并且计数从0到N-1(N为分频的次数,此时为3):分别对clk_p以 ...

  4. Verilog VHDL三种建模描述方式——2选1数据选择器

    标题Quartus II 标题 Verilog VHDL三种建模描述方式--2选1数据选择器 1,结构化描述方式: 是使用实例化低层次模块的方法,即调用其他已经定义过的低层次模块对整个电路的功能进行描 ...

  5. AD9910高速集成DDS芯片(verilog篇-串行模式篇-22个寄存器SPI通信周期控制)

    文章目录 0.引言 1.verilog思路 2.modelsim调试 3.总结 0.引言 经过对疫情期间某天下午写的代码进行,多次调试后,终于输出了波形,下面我们逐步跟着思路,对22个寄存器不同长度的 ...

  6. verilog状态机 三段式 状态机 (代码 可以运行)

    代码在git link "硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这就要用到状态机思想 ...

  7. 【数据分发服务DDS】软件定义汽车【三】-SOA 基础软件框架与参考实现

    引言 上一篇文章对智能汽车软件的范围.软硬件升级.SOA的内涵进行了介绍,本篇将围绕 SOA的实现细节,重点阐述以下问题: SOA 基础软件框架 SOA 参考实现 SOA 实现所需相关技术 一.SOA ...

  8. Verilog有限状态机三段式描述方法【原创*改进】

    1.好的状态机标准 好的状态机的标准很多,最重要的几个方面如下: 第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循 ...

  9. Verilog篇(三)仿真原理

    首先引入一个例子: `timescale  1ns/100ps module   TB;                                                         ...

最新文章

  1. 关于Linux前后台程序切换
  2. makefile 库目录
  3. html基础1-基本语法/段落标签/特殊符号
  4. golang map的定义语法
  5. java jaspersoft,Jaspersoft Studio
  6. 爬虫界又出神器|一款比selenium更高效的利器
  7. apache camel_使用Java的Apache Camel入门
  8. c语言sort函数_C语言的那些经典程序 第八期
  9. java实现缓存中间件,Redis,分布式系统中不可少的缓存中间件
  10. Docker技术入门与实战
  11. 一步一步 ITextSharp Anchor Image Chapter Section使用
  12. java毕业设计_基于ssm的毕业设计管理系统
  13. Python 输入整数进行排序
  14. 利用python-pptx包批量修改ppt格式
  15. 雨后小故事动态邪恶_当您遇到“邪恶”的问题时,使故事变小
  16. 适用mini SD卡的手机
  17. Flume OG和Flume NG的区别
  18. 量化交易策略matlab交易方案,Matlab量化交易策略之 GFTD+止损 附源码
  19. nyoj 125 盗梦空间
  20. 线程并发问题(线程安全)

热门文章

  1. click Edit button in Opportunity - why curr is displayed wrongly
  2. SAP UI5不支持delta render
  3. How is SCM product maintenance tcode redirecting access to MARA
  4. SAP CRM Product workflow debug
  5. SAP Leonardo图片处理相关的机器学习服务在SAP智能服务场景中的应用
  6. 得到application server上所有的logon user
  7. SAP Cloud for Customer Extensibility的设计与实现
  8. Inner Join, Left Outer Join和Association的区别
  9. python数据包pandas_python_pandas学习
  10. linux 内核启动调试,内核开发和调试的启动时参数