概要信息
代码功能
该工程实现一个基于数控直接数字合成(DDS)的波形发生器,能输出正弦、方波、三角波和锯齿波四种波形;通过按键选择波形并通过加/减键调整输出频率;波形数据经 ROM 查表后送往 DAC 接口,同时将频率在 6 位数码管上实时显示。即实现了下图中的基本要求(不含发挥)

代码实现思路
整体采用分层模块化设计:顶层 top.v负责端口映射,top_dds.v集成子模块并生成 DAC 时钟。核心dds.v使用 32 位相累加器(fre_add)累加步长FREQ_CTRL以控制频率,将高位作为 ROM 地址并通过地址偏移选择不同波形(各波形在 ROM 中按区间排列)。rom_wave提供 8-bit 波形点序列。按键经key_filter去抖并由key_ctl解码为波形选择信号,f_word_set根据加/减键调整FREQ_CTRL并维护显示计数;seg_led 负责多位数码管的分时驱动与数字解码。
简单模块连接示意:
top.v
└─ top_dds.v
├─ dds.v ── rom_wave (ROM)
├─ key_ctl.v
├─ key_filter.v (用于按键去抖,f_word_set 中亦实例化)
├─ f_word_set.v
└─ seg_led.v / count.v(用于数码管显示和计时)
该方法优点:结构清晰、易扩展(增加波形或改变ROM深度只需修改ROM与地址映射);基于查表的波形输出效率高,适合 FPGA 实时输出。注意相位偏移(PHASE_CTRL)与 ROM 地址位宽需一致以保证波形连续性。
上板演示
本代码已在开发板验证


代码结构(各模块一句话说明)
top.v:顶层端口映射,实例化top_dds并连接外设引脚(DAC、按键、数码管)。top_dds.v:系统整合模块,生成 DAC 时钟并把子模块(DDS、按键控制、数码管驱动、频率设置)串联起来。dds.v:DDS 核心;32 位相累加器加步进量FREQ_CTRL,通过高位索引rom_wave并用地址偏移区分四种波形,输出 8-bit 波形数据给 DAC。rom_wave.*(ROM/初始化文件):查表存储波形数据(多个波形按地址区分),供dds.v读取。key_filter.v:按键消抖模块,计时确认按键按下以产生稳定的按键触发信号。key_ctl.v:根据按键编码产生波形选择信号wave_select。f_word_set.v:频率步进管理,响应加/减键修改FREQ_CTRL并维护显示计数cn。seg_led.v:数码管显示驱动,完成多位分时扫描和七段编码显示(包括小数点/符号处理)。count.v:定时/采样模块,用于按周期输出当前FREQ_CTRL到显示或上层逻辑(与seg_led/f_word_set配合)。
设计注意点与建议
-
ROM 地址映射:当前设计将四种波形放在 ROM 的不同时段(偏移 0/4096/8192/12288),如需扩展精度应同时调整相位累加位宽与地址偏移量。 -
定时与去抖: key_filter使用计数器去抖,门限(CNT_MAX)应与系统时钟匹配以获得期望的按键响应时间。 -
固定参数: PHASE_CTRL等常量影响相位偏移,若需要相对相位控制或相位同步,建议增加相位寄存与外部控制接口。 -
仿真与验证:建议对 dds.v做时序仿真,观察相位累加器、ROM 读出与输出波形的一致性;在硬件上观察 DAC 输出并用示波器验证频率与波形类型。
关键源文件
trl/top.v, trl/top_dds.v, trl/dds.v, trl/key_ctl.v, trl/key_filter.v, trl/f_word_set.v, trl/seg_led.v, trl/count.v
`timescale 1ns/1ns
module dds
(
input wire sys_clk ,//系统时钟,50MHz
input wire sys_rst_n ,//复位信号,低电平有效
input wire [1:0] wave_select ,//输出波形选择,通过之前的key_trl选好了波形
input wire [31:0] FREQ_CTRL,//频率选择,通过之前的f_word_set选好频率了
output reg sin_wave_lab,
output reg squ_wave_lab,
output reg tri_wave_lab,
output reg saw_wave_lab,
output wire dac_clk,//输入DAC模块时钟
output wire [7:0] data_out //波形输出
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter sin_wave =2'b11 ,//正弦波
squ_wave =2'b10 ,//方波
tri_wave =2'b01 ,//三角波
saw_wave =2'b00 ;//锯齿波
//FREQ_CTRL=32'd42949,//相位累加器单次累加值500HZ
parameter PHASE_CTRL =12'd1024 ;//相位偏移量
//reg define
reg [31:0] fre_add ;//相位累加器
reg [11:0] rom_addr_reg;//相位调制后的相位码
reg [13:0] rom_addr ;//ROM读地址
assign dac_clk=~sys_clk;
//reg sin_wave_lab=1'b1;
//reg squ_wave_lab=1'b1;
//reg tri_wave_lab=1'b1;
//reg saw_wave_lab=1'b1;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//fre_add:相位累加器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
fre_add<=32'd0;
else
fre_add<=fre_add + FREQ_CTRL;//频率选择,通过之前的f_word_set选好频率了
//rom_addr:ROM读地址
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
begin
rom_addr <=14'd0;
rom_addr_reg <=11'd0;
end
else
case(wave_select)
sin_wave://正弦波
begin
squ_wave_lab <=1'b0;
tri_wave_lab <=1'b0;
saw_wave_lab <=1'b0;
rom_addr_reg <= fre_add[31:20]+ PHASE_CTRL;//相位偏移量PHASE_CTRL
rom_addr <= rom_addr_reg;
sin_wave_lab <=1'b1;
end
squ_wave://方波
begin
sin_wave_lab <=1'b0;
tri_wave_lab <=1'b0;
saw_wave_lab <=1'b0;
rom_addr_reg <= fre_add[31:20]+ PHASE_CTRL;
rom_addr <= rom_addr_reg +14'd4096;
squ_wave_lab <=1'b1;
end
tri_wave://三角波
begin
sin_wave_lab <=1'b0;
squ_wave_lab <=1'b0;
saw_wave_lab <=1'b0;
rom_addr_reg <= fre_add[31:20]+ PHASE_CTRL;
rom_addr <= rom_addr_reg +14'd8192;
tri_wave_lab <=1'b1;
end
saw_wave://锯齿波
begin
sin_wave_lab <=1'b0;
squ_wave_lab <=1'b0;
tri_wave_lab <=1'b0;
rom_addr_reg <= fre_add[31:20]+ PHASE_CTRL;
rom_addr <= rom_addr_reg +14'd12288;
saw_wave_lab <=1'b1;
end
default://正弦波
begin
squ_wave_lab <=1'b0;
tri_wave_lab <=1'b0;
saw_wave_lab <=1'b0;
rom_addr_reg <= fre_add[31:20]+ PHASE_CTRL;
rom_addr <= rom_addr_reg;
sin_wave_lab <=1'b1;
end
endcase
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------- rom_wave_inst ------------------------
rom_wave rom_wave_inst
(
.address(rom_addr ),//ROM读地址
.clock(sys_clk ),//读时钟
.q(data_out )//读出波形数据
);
endmodule
代码下载(付费可见):
点击链接获取代码文件:http://www.hdlcode.com/index.php?m=home&c=View&a=index&aid=1547
920