**这是本文档旧的修订版!**

在电赛训练板上实现DDS的功能

关于用FPGA实现DDS的过程可以参考文档:DDS生成任意波形的方法及Verilog代码实例

顶层模块

module top(clk_in,sys_rst_n,key_a,key_b,key_ok,dac_data,dac_clk,oled_rst,oled_dcn,oled_clk,oled_dat);
input			clk_in,sys_rst_n,key_a,key_b,key_ok;
//input	[3:0]	sw;
output	[9:0]	dac_data;
output  		dac_clk;
output			oled_rst;		
output			oled_dcn;	
output			oled_clk;	
output			oled_dat;
 
wire			L_pulse,R_pulse,O_pulse;
wire			clk120,clk60,clk96;
 
wire	locked;
wire	rst_n;
 
assign	led=8'hff;
assign	rgbled=6'b111111;
 
wire	[1:0]	wave;
wire	[26:0]  WaveFreq;
 
OLED12864	OLED12864_u1 (
			.clk     (clk_in) ,		
			.rst_n   (rst_n),		
 
			//.sw      (cnt_seg),		
			.wave	(wave),
			//.oled_csn(oled_csn),		
			.WaveFreq(WaveFreq),
			.oled_rst(oled_rst),			
			.oled_dcn(oled_dcn),	
			.oled_clk(oled_clk),	
			.oled_dat(oled_dat)		
);
 
assign			dac_clk=clk120;
 
dds dds_u(
	.clk_in	 (clk120)	,
	.rst_n	 (rst_n)	,
	.O_pulse (O_pulse)	,
	.L_pulse (L_pulse)	,
	.R_pulse (R_pulse)	,
	.dac_data(dac_data) ,
	.wave	 (wave),
	.WaveFreq(WaveFreq)
	);//
 
assign	rst_n=sys_rst_n&locked;	
pll1	pll1_inst (
	.areset ( ~sys_rst_n ),
	.inclk0 ( clk_in ),
	.c0 ( clk120 ),
	.locked ( locked )
	);			
 
Encoder		Encoder_u(
		.clk_in		(clk120),			
		.rst_n_in	(rst_n),		
		.key_a		(key_a),			
		.key_b		(key_b),			
		.key_ok		(key_ok),			
		.Left_pulse	(L_pulse),		
		.Right_pulse(R_pulse),	
		.OK_pulse	(O_pulse)	
);
 
endmodule

DDS核心模块

// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: dds
// 
// Author: Step
// 
// Description: dds
// 
// Web: www.stepfapga.com
// 
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2021.11.27   |Initial ver
// --------------------------------------------------------------------
module dds(clk_in,rst_n,O_pulse,L_pulse,R_pulse,dac_data,wave,WaveFreq);//
 
localparam  SIN = 2'b00, SAW = 2'b01, TRI = 2'b10, SQU = 2'b11;
input 			clk_in;                 // 小脚丫FPGA的外部时钟频率为12MHz
input			rst_n;
input	wire 	O_pulse,L_pulse,R_pulse;
 
output 	reg		[9:0] 	dac_data;        // 10位数据输出送给外部的DAC
output reg 	[1:0] 	wave;
output reg	[26:0]  WaveFreq;
 
reg 	[23:0] 	phase_acc;            //增加相位累加器位数使得分辨率提高
wire	[23:0]	phase;
reg 	[23:0]	f_inc;
 
assign phase=phase_acc;
 
always @(posedge clk_in) 	phase_acc <= phase_acc + f_inc;		//f_inc=24'd27962;主时钟为12MHz,则产生20KHz的正弦波信号  
 
wire [9:0] sin_dat; //正弦波
wire [9:0] saw_dat = phase[23:14];  //锯齿波
wire [9:0] tri_dat = phase[23]? (~phase[22:13]) : phase[22:13]; //三角波
wire [9:0] squ_dat = phase[23]? 10'h3ff : 10'h000;  //方波 
 
always @(*) begin
    case(wave)
        2'b00: dac_data = sin_dat;   //正弦波       
		2'b01: dac_data = saw_dat;   //锯齿波       
		2'b10: dac_data = tri_dat;   //三角波       
		2'b11: dac_data = squ_dat;   //方波
        default: dac_data = sin_dat; //正弦波   
	endcase
end
 
lookup_tables u_lookup_tables(.phase(phase_acc[23:16]), .sin_out(sin_dat)); 
 
//波形输出选择
always @(posedge clk_in or negedge rst_n) begin
    if(!rst_n) wave <= SIN;
    else if(O_pulse)begin
        case(wave)
            SIN: wave <= SAW;
            SAW: wave <= TRI;
            TRI: wave <= SQU;
            SQU: wave <= SIN;
            default: wave <= SIN;
        endcase
    end else wave <= wave;
end
//频率控制
always@(posedge clk_in or negedge rst_n) begin
    if(!rst_n) begin
		f_inc <= 24'h22222;
		WaveFreq<=1_000_000;
	end 
    else if(L_pulse==1'b1) begin
        if(f_inc <= 24'h369d) f_inc <= f_inc;
        else begin
			f_inc <= f_inc - 24'h369d;
			WaveFreq<=WaveFreq-100000;
		end 
    end 
	else if(R_pulse==1'b1) begin
        if(f_inc >= 24'h155554) f_inc <= f_inc;
        else begin
			f_inc <= f_inc + 24'h369d;
			WaveFreq<=WaveFreq+100000;
		end 
    end 
	else f_inc <= f_inc;
end
endmodule
//dds时钟频率给定后,输出信号的频率取决于频率控制字,
//	频率分辨率取决于累加器位数,
//	相位分辨率取决于ROM的地址线位数,
//	幅度量化噪声取决于ROM的数据位字长和D/A转换器位数

编码器输入模块

 

OLED显示模块