本帖最后由 雾盈 于 2016-8-28 13:39 编辑
基于FPGA实现频率相位可调的DDS波形发生器(Verilog) 雾盈 2016-08-02
雾盈FPGA笔记汇总目录
一、原理
让我们先理解以下几个概念:
1)何为DDS?
DDS是直接数字式频率合成器(Direct Digital Synthesizer)的英文缩写。与传统的频率合成器相比,DDS具有低成本、低功耗、高分辨率和快速转换时间等优点,广泛使用在电信与电子仪器领域,是实现设备全数字化的一个关键技术。
2)什么是波形发生器?
波形发生器是一种数据信号发生器,在调试硬件时,常常需要加入一些信号,以观察电路工作是否正常。加入的信号有:正弦波、三角波、方波和任意波形等等。
3)什么是相位可调?
相位(phase)是对于一个波,特定的时刻在它循环周期中的位置:一种它是否在波峰、波谷或它们之间的某点的标度。相位描述信号波形变化的度量,通常以度(角度)作为单位,也称作相角。 当信号波形以周期的方式变化,波形循环一周即为360°。那么相位可调也可以简单的理解为:改变初始相位。4)什么是频率可调?
频率,是单位时间内完成周期性变化的次数,是描述周期运动频繁程度的量,常用符号f或ν表示,单位为秒分之一,符号为s-1。频率可调也就是改变单位时间内完成周期性变化的次数。
二、系统框架
理解了几个概念后,我们来看一下框图,对系统整体有个初步的了解
由框图可以看出,这个系统分为两个模块,dds_ctrl控制地址输出模块和存储有波形数据mif文件的rom(调用IP核)。
三、载有波形数据的mif文件制作
首先,我们先来制作载有波形数据的mif文件,这里会使用一个小软件———mifmake,是专门用来生成mif文件的,软件压缩包我会挂在后面。
打开mifmake ,点击全局参数,如图:
弹出全局参数设置窗口,如图:
选择想要的长度和宽度,格式选择无符号10进制。
点击设定波形,选择想要生成的波形,我这里选择正弦波,
出现波形后,点击保存。
至此,这样就生成了一个载有正弦波数据的mif文件,打开mif文件,里面是这样的,如下图:这时,这个mif文件还不能直接被使用,我们先通过quartus新建一个空白mif文件,随意输入数据后保存,然后打开这个新的mif文件。
把之前我们生成的载有波形数据mif的内容,全选复制粘贴替换掉新mif文件相应的部分。如图部分:
最后,在调用IP核ROM的使用,将这个mif文件包含进去。一个载有正弦波数据的ROM存储器就制作完了。
四、相位可调,频率可调
相位可调实际是改变波形的初相,也就是改变复位时的初始地址。
if(!rst_n)
begin
cnt_addr <= 1'b0;
addr_out <= PWORD;
end
这里,改变PWORD的值就能改变初相。PWORD的值在0—255之间。
频率可调一个完整周期的正弦波形里系统时钟计数了256次,可计算地址输出频率公式:
如果想要改变输出的频率,我们可以选择改变时钟或者输出点的个数!显而易见,我们的设计不能够时时刻刻去改变时钟的频率,那么想要输出别的频率,我们只能改变输出的点的个数,也就是改变有效地址的数量。
我们可以定义一个位宽为N(N>8)的地址计数器,让地址计数器每次增加一定的值,然后把高八位当作有效地址输送给rom,这样的话,就实现了降低地址改变的频率,进而达到降低输出波形的频率。
[table]
我们使用的是50MHz的晶振,周期为20ns,假设fword为1,地址计数器的输出为N位的,那么每20ns,地址计数器加1,要加到2^N,需要20ns x 2^N 时间,这个时间就是输出.一个完整信号的周期,那么我们可以知道,输出信号的频率为 Fout = Fclk/2^N,其中,Fclk为我们的晶振频率,再假如,fword= B的时候,地址间隔提高 B 倍,因此计满一个周期的时间缩小了 B 倍,频率提高的 B 倍。综上所述,我们得出了输出信号的频率计算公式:
由此公式,可以计算出任意频率值所对应的B值。其实,不想费心理解,只要熟记这个公式就可以了。
再然后,我们取地址计数器的前八位,相当于把一个波形的相位分成了256个点,每个点对应一个数据,正好和我们的波形数据点的个数是一样的。
仿真波形如下图:
经测试得输出波形频率确为5KHZ。
初相地址为128。
附:源代码
- module dds_ctrl(
- // system signal
- input clk,
- input rst_n,
- // 输出地址
- output reg [7:0] addr_out
- );
- /*=========================================================================================================
- ************************** Define parameter and internal signals *********************************
- =========================================================================================================*/
- parameter PWORD = 8'd128; // 可调相位初值
- parameter FWORD = 20'd105; // B=21 可调频率控制字
- parameter CNT_MAX = 20'hf_ffff;
- reg [19:0] cnt_addr; // 地址计数器 fout = B * ( fclk / 2^N) N=20 目标频率fout=5000hz 得B=21
- /*=========================================================================================================
- ************************** Main code *********************************
- =========================================================================================================*/
- // 地址计数器
- always @ (posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- begin
- cnt_addr <= 1'b0;
- addr_out <= PWORD;
- end
- else begin
- if( cnt_addr < CNT_MAX )
- begin
- cnt_addr <= cnt_addr + FWORD;// 改变频率控制字来改变计数器达到最大值的时间,从而改变输出波形的频率
- addr_out <= cnt_addr[19:12]; // 让输出的地址取地址计数器的高八位,刚好256个点
- end
- else begin
- cnt_addr <= 1'b0;
- addr_out <= PWORD;
- end
- end
- end
- endmodule
复制代码 |