DDS发生器的verilog实现(三)
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实现(三)相关推荐
- DDS发生器的频率控制字原理和基本结构(二)
DDS发生器的频率控制字原理和基本结构(二) 在正弦波发生器的verilog实现(一)中已经实现了最基本的功能,这篇文章将主要讲解DDS发生器的频率控制字原理和基本结构. 在这里先给出DDS发生器的结 ...
- 题目:用Verilog实现三分频电路,要求输出50%占空比。
题目:用Verilog实现三分频电路,要求输出50%占空比. module Div_three(input clk,input rst_n,output div_three ); reg [1:0] ...
- 一、verilog编写三分频电路
1.目标:使用verilog编写三分频电路,要求占空比大小为50%. 2.方法:分别使用上升沿和下降沿计数cnt_p以及cnt_n,并且计数从0到N-1(N为分频的次数,此时为3):分别对clk_p以 ...
- Verilog VHDL三种建模描述方式——2选1数据选择器
标题Quartus II 标题 Verilog VHDL三种建模描述方式--2选1数据选择器 1,结构化描述方式: 是使用实例化低层次模块的方法,即调用其他已经定义过的低层次模块对整个电路的功能进行描 ...
- AD9910高速集成DDS芯片(verilog篇-串行模式篇-22个寄存器SPI通信周期控制)
文章目录 0.引言 1.verilog思路 2.modelsim调试 3.总结 0.引言 经过对疫情期间某天下午写的代码进行,多次调试后,终于输出了波形,下面我们逐步跟着思路,对22个寄存器不同长度的 ...
- verilog状态机 三段式 状态机 (代码 可以运行)
代码在git link "硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这就要用到状态机思想 ...
- 【数据分发服务DDS】软件定义汽车【三】-SOA 基础软件框架与参考实现
引言 上一篇文章对智能汽车软件的范围.软硬件升级.SOA的内涵进行了介绍,本篇将围绕 SOA的实现细节,重点阐述以下问题: SOA 基础软件框架 SOA 参考实现 SOA 实现所需相关技术 一.SOA ...
- Verilog有限状态机三段式描述方法【原创*改进】
1.好的状态机标准 好的状态机的标准很多,最重要的几个方面如下: 第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循 ...
- Verilog篇(三)仿真原理
首先引入一个例子: `timescale 1ns/100ps module TB; ...
最新文章
- 关于Linux前后台程序切换
- makefile 库目录
- html基础1-基本语法/段落标签/特殊符号
- golang map的定义语法
- java jaspersoft,Jaspersoft Studio
- 爬虫界又出神器|一款比selenium更高效的利器
- apache camel_使用Java的Apache Camel入门
- c语言sort函数_C语言的那些经典程序 第八期
- java实现缓存中间件,Redis,分布式系统中不可少的缓存中间件
- Docker技术入门与实战
- 一步一步 ITextSharp Anchor Image Chapter Section使用
- java毕业设计_基于ssm的毕业设计管理系统
- Python 输入整数进行排序
- 利用python-pptx包批量修改ppt格式
- 雨后小故事动态邪恶_当您遇到“邪恶”的问题时,使故事变小
- 适用mini SD卡的手机
- Flume OG和Flume NG的区别
- 量化交易策略matlab交易方案,Matlab量化交易策略之 GFTD+止损 附源码
- nyoj 125 盗梦空间
- 线程并发问题(线程安全)
热门文章
- click Edit button in Opportunity - why curr is displayed wrongly
- SAP UI5不支持delta render
- How is SCM product maintenance tcode redirecting access to MARA
- SAP CRM Product workflow debug
- SAP Leonardo图片处理相关的机器学习服务在SAP智能服务场景中的应用
- 得到application server上所有的logon user
- SAP Cloud for Customer Extensibility的设计与实现
- Inner Join, Left Outer Join和Association的区别
- python数据包pandas_python_pandas学习
- linux 内核启动调试,内核开发和调试的启动时参数