目录
前言
第二个案例来了!做一个函数信号发生器,实现产生四种波形(正弦波、方波、三角波、反三角),输出频率可变以及幅值可变。
一、设计思路
在数字电路中实现函数信号发生器,直接数字式频率合成(DDS)是最常见的方法。DDS的主要模型如下:
由相位累加器、ROM查找表和数模转换器组成,核心为相位累加器和ROM查找表。
对于一段正弦信号来说,其幅度值是非线性的,但是其相位的值却是线性增加的。因此DDS的核心便是通过固定步长产生均匀相位,然后将相位作为地址码去查找该相位的幅度值,从而得到波形。
二、完整代码
module DDS(data,clk,reset);
output [7:0] data;//幅值数据
input clk;
input reset;
input switch_wave_type;//波形类别
wire clk_300M;//300M时钟
reg [23:0] step_length = 24'h00FFFF;//固定的步长
wire[31:0] addr_Phase;//相位
wire[8:0] addr;//地址码
Pll(.refclk(clk),.rst(reset),.outclk_0(clk_300M));
Phase_accumulator(addr_Phase,step_length,clk_300M);
Rom(.address(addr),.clock(clk_300M),.q(data));
assign addr={switch_wave_type,addr_Phase[31:24]};//低位相位和高位波形拼接成ROM地址码
endmodule
module Phase_accumulator(addr_Phase,step_length,clk);
output reg[31:0] addr_Phase;
input[23:0] step_length;
input clk;
//循环产生相位
always@(posedge clk)
begin
if(addr_Phase>=32'hff000000)
addr_Phase<=32'h0;
else
addr_Phase<=addr_Phase+step_length;
end
endmodule
三、代码诠释
PLL和ROM都是调用Altera的IP核,有效地减小了工程量,使用PLL,将50M的时钟倍频到300M,从而提高输出波形频率的上限。使用ROM提前存储波形幅值数据。对于PLLIP核的调用在之前有所提及,而ROM IP核的调用则需要提前写好.mif文件,用来初始化ROM。
因此需要注重的是相位累加器的编写。
相位累加器等同于一个计数器,在本次案例中我设置了32bits的计数存储单元Cnt。由于我一个波形采样了256个点,因此地址码需要八位,所以我令高八位作为地址码,低二十四位便是步长的变化范围。相位累加器通过累加步长,使得高八位均匀进位,从而得到均匀的地址码。再通过地址码寻址,输出波形幅值数据,最后经DAC转换得到模拟电压。
特别的是,我在主模块最后有一句assign语句,此语句是八位地址码和波形类型相拼接。原理是我在ROM中连续存储多个波形的幅值,每个波形都是256个点,因此我可以用更高位来区分我在ROM中查询的是哪种波形。
assign addr={switch_wave_type,addr_Phase[31:24]};
四、其他模块
在本次案例中,上述代码仅实现了输出波形。为了方便调节步长大小,我选择LCD1602作为显示器,使用状态机编写了LCD1602的驱动模块。此内容今后会单独写成文章。