赞
踩
本文使用Altera公司生产的EP4CE22F17C6开发板和小梅哥的高速DAC,——ACM9767,基于Quartus18.1实现对DDS信号发生器的设计。
DDS同 DSP(数字信号处理)一样,是一项关键的数字化技术。DS芯片中主要包括频率控制寄存器、高速相位累加器和正弦计算器三个部分(如Q2220)。DDS是直接数字式频率合成器(Direct Digital Synthesizer)的英文缩写。与传统的频率合成器相比,DDS具有低成本、低功耗、高分辨率和快速转换时间等优点,广泛使用在电信与电子仪器领域,是实现设备全数字化的一个关键技术。
DDS的结构主要由相位累加器,相位调制器,波形数据表ROM,DAC组成。相位累加器和相位调制器的存在都是为了生成ROM的地址,与后续ROM的导入结合。
相位累加器为计数器对频率字输入的累加,其中加法器与寄存器均为N位(N一般取24~32位),在每个时钟的上升沿将频率控制字与寄存器中数据进行相加,相加结果再与下一个时钟上升沿的频率字相加,如此重复。频率控制字Fword与N决定了DDS输出的步频(频率),f out=Fword*f clk/2^N。
若ROM地址为M位,相位调制器则为取出相位累加器的高M位与相位控制字相加。Verilog里难以实现对于小数的除法,故对于缩小步频的操作可以使用结位的方法。Pword用于调制DDS输出相位。
ROM是只读储存器的简称,在ROM中一个地址对应一个输出值,基于相位累加器和相位调制器生成的地址,在ROM数据表内存入所输出波形的输出值。本文使用Quartus自带的IP核生成ROM,其中使用的mif文件使用Mif_maker生成。Mif_maker文件下载
在Mif_maker里可以设置所需波形类型,地址宽度,输出深度,生成mif文件后,在ROM中导入,在后续模块中例化使用。
采用了4个按键实现固定8个频率控制字和8个相位控制字的输入。
module DDS_top( clk, clkA, clkB, WRTA, WRTB, rst_n, FwordA_sel, FwordB_sel, PwordA_sel, PwordB_sel, model_selA, model_selB, dataA, dataB ); input clk; output clkA; output clkB; output WRTA; output WRTB; input rst_n; input [1:0]model_selA; input [1:0]model_selB; output [13:0]dataA; output [13:0]dataB; input FwordA_sel; input FwordB_sel; input PwordA_sel; input PwordB_sel; reg [31:0]FwordA; reg [31:0]FwordB; reg [11:0]PwordA; reg [11:0]PwordB; assign clkA=clk; assign clkB=clk; assign WRTA=clk; assign WRTB=clk; reg [2:0]r_FwordA;//使用按键实现8种频率和相位的循环切换 reg [2:0]r_FwordB; reg [2:0]r_PwordA; reg [2:0]r_PwordB; wire [3:0]key_flag; wire [3:0]key_state; always@(posedge clk or negedge rst_n) if(~rst_n) r_FwordA<=0; else if(key_flag[0]&&key_state[0]==0) r_FwordA<=r_FwordA+1; always@(posedge clk or negedge rst_n) if(~rst_n) r_FwordB<=0; else if(key_flag[1]&&key_state[1]==0) r_FwordB<=r_FwordB+1; always@(posedge clk or negedge rst_n) if(~rst_n) r_PwordA<=0; else if(key_flag[2]&&key_state[2]==0) r_PwordA<=r_PwordA+1; always@(posedge clk or negedge rst_n) if(~rst_n) r_PwordB<=0; else if(key_flag[3]&&key_state[3]==0) r_PwordB<=r_PwordB+1; always@(*)//85899.34592为1khz计算所得Fword case(r_FwordA) 0:FwordA=85900;//500hz 1:FwordA=85899;//1khz 2:FwordA=858993;//10khz 3:FwordA=8589935;//100khz 4:FwordA=85900346;//1Mhz 5:FwordA=85900346*4;//4Mhz 6:FwordA=85900346*5;//5Mhz 7:FwordA=85900346*12;//12Mhz endcase always@(*) case(r_FwordB) 0:FwordB=85900;//500hz 1:FwordB=85899;//1khz 2:FwordB=858993;//10khz 3:FwordB=8589935;//100khz 4:FwordB=85900346;//1Mhz 5:FwordB=85900346*4;//4Mhz 6:FwordB=85900346*5;//5Mhz 7:FwordB=85900346*12;//12Mhz endcase always@(*)//总地址为4096 case(r_PwordA) 0:PwordA=0;//0度 1:PwordA=512;//45度 2:PwordA=1024;//90度 3:PwordA=1365;//120度,计算所得为1365.333333333333 4:PwordA=2048;//180度 5:PwordA=3072;//270度 6:PwordA=3413;//300度,计算所得为3413.333333333333 7:PwordA=3641;//320度,计算所得为3640.8888888888889 endcase always@(*) case(r_PwordB) 0:PwordB=0;//0度 1:PwordB=512;//45度 2:PwordB=1024;//90度 3:PwordB=1365;//120度 4:PwordB=2048;//180度 5:PwordB=3072;//270度 6:PwordB=3413;//300度 7:PwordB=3641;//320度 endcase DDS_module DDS_moduleA( .clk(clkA), .rst_n(rst_n),//key_state[2]&key_state[3]调整相位时让两个DDS模块重新加载 .Fword(FwordA), .Pword(PwordA), .data(dataA), .model_sel(model_selA) ); DDS_module DDS_moduleB( .clk(clkB), .rst_n(rst_n), .Fword(FwordB), .Pword(PwordB), .data(dataB), .model_sel(model_selB) ); key_filter inst_key_filter0//对四个按键进行消抖 ( .clk (clk), .rst_n (rst_n), .key (FwordA_sel), .key_flag (key_flag[0]), .key_state (key_state[0]) ); key_filter inst_key_filter1 ( .clk (clk), .rst_n (rst_n), .key (FwordB_sel), .key_flag (key_flag[1]), .key_state (key_state[1]) ); key_filter inst_key_filter2 ( .clk (clk), .rst_n (rst_n), .key (PwordA_sel), .key_flag (key_flag[2]), .key_state (key_state[2]) ); key_filter inst_key_filter3 ( .clk (clk), .rst_n (rst_n), .key (PwordB_sel), .key_flag (key_flag[3]), .key_state (key_state[3]) ); endmodule
用4个拨码开关控制输出正弦波,三角波,方波,锯齿波。
module DDS_module( clk, rst_n, Fword, Pword, data, model_sel ); input clk,rst_n; input [31:0]Fword; input [11:0]Pword; input [1:0]model_sel; output reg [13:0]data; reg [31:0]F_cnt; reg [11:0]rom_adder; wire [13:0]sin_data; wire [13:0]square_data; wire [13:0]triangular_data; wire [13:0]sawtooth_data; always @(posedge clk or negedge rst_n) if(!rst_n) F_cnt<=0; else F_cnt<=F_cnt+Fword; always @(posedge clk or negedge rst_n) if(!rst_n) rom_adder <=0; else rom_adder<=Pword+F_cnt[31:20]; always@(*) case(model_sel) 0:data=sin_data; 1:data=square_data; 2:data=triangular_data; 3:data=sawtooth_data; endcase sin_rom sin_rom( .address(rom_adder), .clock(clk), .q(sin_data) ); square_rom square_rom( .address(rom_adder), .clock(clk), .q(square_data) ); triangular_rom triangular_rom( .address(rom_adder), .clock(clk), .q(triangular_data) ); sawtooth_rom sawtooth_rom( .address(rom_adder), .clock(clk), .q(sawtooth_data) ); endmodule
状态机实现按键消抖。
module key_filter ( input clk, // Clock input rst_n, // Asynchronous reset active low input key, output reg key_flag, output reg key_state ); reg [1:0]r_key; wire pose_key; wire nege_key; reg [1:0]state; reg [19:0]cnt;//需要存放20ms的计数单元 always@(posedge clk) r_key<={r_key[0],key};//实现上升沿或者下降沿的寄存 assign pose_key= (r_key==2'b01); assign nege_key= (r_key==2'b10); always @(posedge clk or negedge rst_n) begin if(~rst_n) begin// state<= 0; key_state<=1; key_flag<=0; cnt<=0; end else begin//状态1.3属于是计数状态,在跳转其他状态时需要对计数器实现清零 case(state) 0:begin key_flag=0;//key_flag触发为一个时钟的脉冲形式 if(nege_key) begin state<=1; end else state<=0; end 1: if((cnt<1000000)&&(pose_key)) begin state<=0; cnt<=0; end else if(cnt>=1000000) begin state<=2; key_flag<=1; key_state<=0; cnt<=0; end else begin cnt<=cnt+1; state<=1; end 2:begin key_flag=0; if(pose_key) state<=3; else state<=2; end 3: if((cnt<1000000)&&(nege_key)) begin state<=2; cnt<=0; end else if(cnt>=1000000) begin state<=0; key_flag=1; key_state=1; cnt<=0; end else begin state<=3; cnt<=cnt+1; end default:begin cnt<=0; key_flag<=0; key_state<=1; state<=0; end endcase // state end end endmodule
`timescale 1 ns/ 1 ns module DDS_module_tb(); reg clk; reg rst_n; reg [31:0]Fword; reg [11:0]Pword; reg [1:0]model_sel; wire [13:0]data; DDS_module inst1 ( .clk(clk), .rst_n(rst_n), .Fword(Fword), .Pword(Pword), .data(data), .model_sel(model_sel) ); initial clk=1; always #10 clk=~clk; initial begin rst_n=0; Fword=65536; Pword=0; model_sel=0; #201 rst_n=1; #5000000 model_sel=1; #5000000 model_sel=2; #5000000 model_sel=3; #10000000 $stop; end endmodule
DDS是大学学习FPGA以来第一个做的比较完整的模块, 跟着小梅哥的课,总算是有了一些自主能力。前路昭然,你我共进。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。