**这是本文档旧的修订版!**
在电赛训练板上实现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转换器位数