基于FPGA的直接数字频率合成器

这篇具有很好参考价值的文章主要介绍了基于FPGA的直接数字频率合成器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

本实验利用FPGAA芯片设计一款直接数字频率合成器(DDS)
发开板:EGO1(xc7a35tcst324-1)
开发软件:Vivado,Vscode
实现功能
1、设计测频电路,将测量的波形频率值显示在实验板卡的右面4位数码管;
2、基于DDS原理,计算波形频率的;理论值,将理论计算值显示在实验板卡上的左面4位数码管上;
3、输出三角波、锯齿波、方波等多种波形。

前期准备

利用"mif精灵"生成容量为 2 8 × 8 2^{8}\times8 28×8的.coe文件
基于FPGA的直接数字频率合成器,fpga开发,学习
整体设计框架如下
基于FPGA的直接数字频率合成器,fpga开发,学习

开始设计电路

分频器模块

分频电路模块利用系统时钟的100MHz信号,分出10KHz和0.5Hz两种时钟信号,以便用于后续模块中。其中sys_clk为输入的系统时钟信号,大小为100MHz,clk_10k为分频器输出的10kHz的时钟信号,clk_05为分频器输出的0.5Hz的时钟信号。
基于FPGA的直接数字频率合成器,fpga开发,学习
源代码如下

`timescale 1ns / 1ps  
module f_div(  
    input sys_clk,      //系统输入时钟信号  
  
    output reg clk_10k=0,     //输出10KHz  
    output reg clk_05=0      //输出0.5Hz  
  
  );  
  reg[13:0] cnt_10k=0;//分频计数  
  reg[27:0] cnt_05=0;//分频计数  
  parameter div_10k=4999;    //分频数 从100MHz分出10KHz的  
  parameter div_05=99999999;    //分频数 从100MHz分出0.5Hz的  
  always @(posedge sys_clk)  
  begin  
    //分频器 分出10KHz  
    cnt_10k=cnt_10k+1;  
    if(cnt_10k==div_10k)  
    begin  
      clk_10k<=~clk_10k;  
      cnt_10k<=0;  
    end  
    //分频器 分出0.5Hz  
    cnt_05=cnt_05+1;  
    if(cnt_05==div_05)  
    begin  
      clk_05<=~clk_05;  
      cnt_05<=0;  
    end  
  end  
endmodule  

激励脚本如下

`timescale 1ns / 1ps  
module f_div_tb;  
reg  sys_clk;  
wire  clk_10k;  
wire  clk_05;  
f_div  f_div_inst (  
  .sys_clk(sys_clk),  
  .clk_10k(clk_10k),  
  .clk_05(clk_05)  
);  
initial begin  
    sys_clk=0;  
end  
always #5  sys_clk = ! sys_clk ;  
endmodule  

仿真结果如下

基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习

累加器模块

累加器模块利用分频器模块产生的10kHz时钟信号与8个拨码开关输入的频率控制字作为累加步长,输出8位的累加和。
基于FPGA的直接数字频率合成器,fpga开发,学习
以输入端口clk_10k输入的10KHz时钟信号作为触发,将地址与拨码开关的输入key_in相加,由此得到新的地址信号,不断地累加,从而使地址信号不断变大,当地址信号产生溢出时,又重复进行累加操作,从而实现地址信号以一定步长进行循环递增。
源代码如下

1.	`timescale 1ns / 1ps  
2.	module forever_adder(  
3.	    input clk_10k,  //分频电路输入的10KHz频率  
4.	    input [7:0] key_in,     //8个拨码开关的输入 频率控制字  
5.	  
6.	    output reg [7:0] address=0    //8位累加和,即所需要寻找的寄存器的地址  
7.	  );  
8.	  always @(posedge clk_10k)  
9.	  begin  
10.	    address<=address+key_in;//累加输入信号Key  
11.	  end  
12.	endmodule  

激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module forever_adder_tb;  
3.	reg  clk_10k;  
4.	reg [7:0] key_in;  
5.	wire [7:0] address;  
6.	forever_adder  forever_adder_inst (  
7.	  .clk_10k(clk_10k),  
8.	  .key_in(key_in),  
9.	  .address(address)  
10.	);  
11.	initial begin  
12.	    clk_10k=0;  
13.	    key_in<=8'b0;  
14.	    #10  
15.	    key_in<=8'b00000001;  
16.	    #10  
17.	    key_in<=8'b00000000;  
18.	    #10  
19.	    key_in<=8'b00000001;  
20.	    #10  
21.	    key_in<=8'b00000000;  
22.	    #10  
23.	    key_in<=8'b00000001;  
24.	    #10  
25.	    key_in<=8'b00000000;  
26.	end  
27.	always #5  clk_10k = ! clk_10k ;  
28.	endmodule 

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习

ROM波形存储器模块

基于FPGA的直接数字频率合成器,fpga开发,学习
在设计ROM波形存储器之前,首先要利用程序生成一个容量为2^8\times8的.coe正弦波、三角波、方波、锯齿波文件,然后生成存储器IP核,将.coe文件导入进去。最后在程序中调用IP核,读取波形数据,最后生成波形。
先生成4种波形存储器的IP核,然后在源文件中调用这些IP核,将该模块的输入信号address送入各IP核的地址信号中。不同模块在模块内引入不同的输出信号sin_bo、triangular_bo、square_bo、swatooth_bo,最后利用case语句,根据波形选通信号sel,选择不同波形的数据传送给模块的输出端口sin,从而实现不同波形的输出。当sel=2’b00时,输出正弦波,当sel=2’b01时,输出三角波,当sel=2’b10时,输出方波,当sel=2’b11时,输出锯齿波。
源代码如下

1.	`timescale 1ns / 1ps  
2.	module ip_rom(  
3.	    input[7:0] address,     //输入累加器和  
4.	    input[1:0] sel,         //选通信号,选择输出哪种波形  
5.	  
6.	    output reg[7:0] sin         //输出读取的sin值  
7.	  );  
8.	  
9.	  wire[7:0] sin_bo;          //sin信号  
10.	  wire[7:0] triangular_bo;   //三角波  
11.	  wire[7:0] square_bo;      //方波  
12.	  wire[7:0] swatooth_bo;    //锯齿波  
13.	  //正弦波  
14.	  rom_256x8b u0 (  
15.	               .a(address),      // input wire [7 : 0] a  
16.	               .spo(sin_bo)  // output wire [7 : 0] spo  
17.	             );  
18.	  //三角波  
19.	  triangular_rom256x8 u1 (  
20.	                        .a(address),      // input wire [7 : 0] a  
21.	                        .spo(triangular_bo)  // output wire [7 : 0] spo  
22.	                      );  
23.	  //方波  
24.	  square_256x8b u2 (  
25.	                        .a(address),      // input wire [7 : 0] a  
26.	                        .spo(square_bo)  // output wire [7 : 0] spo  
27.	                      );  
28.	  //锯齿波  
29.	  sawtooth_256x8b u3(  
30.	                        .a(address),      // input wire [7 : 0] a  
31.	                        .spo(swatooth_bo)  // output wire [7 : 0] spo  
32.	                      );  
33.	  always @(*)  
34.	  begin  
35.	    case (sel)  
36.	      0:            //输出正弦波  
37.	      begin  
38.	        sin<=sin_bo;  
39.	      end  
40.	      1:            //输出三角波  
41.	      begin  
42.	        sin<=triangular_bo;  
43.	      end  
44.	      2:            //输出方波  
45.	      begin  
46.	        sin<=square_bo;  
47.	      end  
48.	      3:            //输出锯齿波  
49.	      begin  
50.	        sin<=swatooth_bo;  
51.	      end  
52.	      default:sin<=0;  
53.	    endcase  
54.	  end  
55.	endmodule 

激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module ip_rom_tb;  
3.	reg [7:0] address;  
4.	reg [1:0] sel;  
5.	wire [7:0] sin;  
6.	reg clk;  
7.	ip_rom  ip_rom_inst (  
8.	  .address(address),  
9.	  .sel(sel),  
10.	  .sin(sin)  
11.	);  
12.	initial begin  
13.	    address<=0;  
14.	    clk=0;  
15.	    sel<=2'b11;  
16.	end  
17.	always #5  clk = ! clk ;  
18.	always @(posedge clk) begin  
19.	    if(address==8'd255)  
20.	        address<=0;  
21.	    else  
22.	        address<=address+1'b1;  
23.	end  
24.	endmodule 

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
注意
1、在生成方波时,可能仿真出的波形是三角波的形状
基于FPGA的直接数字频率合成器,fpga开发,学习

这时右键点击sin[7:0],选择“Waveform Style”下面的“Analog Settigns”
基于FPGA的直接数字频率合成器,fpga开发,学习

在“Interpolation style”选项中选择“Hold”,这样就可以变成方波了。
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习

理论频率计算模块

理论频率计算模块,是根据8位频率控制字的输入k,从而计算产生波形的理论值。该模块基于公式 k f c 2 n \frac{kf_c}{2^n} 2nkfc进行频率理论值的计算。
基于FPGA的直接数字频率合成器,fpga开发,学习
源代码如下

1.	`timescale 1ns / 1ps  
2.	module lilun_f(  
3.	    input clk_10k,          //分频器输入的10kHz频率  
4.	    input [7:0] key_in,     //频率控制字  
5.	  
6.	    output reg [12:0] li_lun_zhi=0     //信号频率理论值 0~5000hz  
7.	  );  
8.	  always @(posedge clk_10k)  
9.	  begin  
10.	    if (key_in==8'b0)                       //还没拨码,显示0  
11.	    begin  
12.	      li_lun_zhi<=0;  
13.	    end  
14.	    else  
15.	      li_lun_zhi<=(10000*key_in)>>8;       //计算理论频率值  右移8位相当于除以2^8  
16.	  end  
17.	endmodule

在Verilog中,一个数除以2的n次方,与右移8位的计算结果相同,但是移位操作占用资源较少,所以优先选择使用移位操作对数据进行计算。
激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module lilun_f_tb;  
3.	reg  clk_10k;  
4.	reg [7:0] key_in;  
5.	wire  [12:0] li_lun_zhi;  
6.	lilun_f  lilun_f_inst (  
7.	  .clk_10k(clk_10k),  
8.	  .key_in(key_in),  
9.	  .li_lun_zhi(li_lun_zhi)  
10.	);  
11.	initial begin  
12.	    clk_10k=0;  
13.	    key_in<=8'b0;  
14.	    #10   
15.	    key_in <= 8'b1;  
16.	    #10   
17.	    key_in <= 8'b00000010;  
18.	    #10   
19.	    key_in <= 8'b01111111;  
20.	    #10   
21.	    key_in <= 8'b11111111;  
22.	    #10   
23.	    key_in <= 8'b10000000;  
24.	end  
25.	always #5  clk_10k = ! clk_10k ;  
26.	endmodule 

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习

测频电路模块

测频电路在使能信号有效时,利用0.5Hz的信号,在1s的高电平时间内,对ROM波形存储器产生的波形进行计数,从而得到ROM波形存储器产生信号的实际频率。
基于FPGA的直接数字频率合成器,fpga开发,学习
源代码如下

1.	`timescale 1ns / 1ps  
2.	module measure_shiji_f(  
3.	    input clk_05,           //输入的0.5Hz时钟信号  
4.	    input [7:0] sin,        //波形存储器输入的波形数据  
5.	    input   rst_n_shiji,    //使能信号  
6.	  
7.	    output reg [12:0] shi_ji_zhi=0       //信号频率的实际值  
8.	  );  
9.	  reg wave_s=0;             //整形后的方波信号  
10.	  reg [12:0] freq_m=0;      //频率计数  
11.	  reg [12:0] lock=0;        //锁存信号  
12.	  //将输入信号整形为 方波  
13.	  always @(*)  
14.	  begin  
15.	    if(sin>8'd127)  
16.	      wave_s<=1;  
17.	    if(sin<8'd127)  
18.	      wave_s<=0;  
19.	  end  
20.	  always @(posedge wave_s)  
21.	  begin  
22.	    if(rst_n_shiji)  
23.	    begin  
24.	      if(clk_05==1 && lock==0)  
25.	      begin  
26.	        freq_m<=freq_m+1;  
27.	      end  
28.	      else if(clk_05==1 && lock>0)  
29.	      begin  
30.	        shi_ji_zhi<=freq_m;  
31.	        freq_m<=1;  
32.	        lock<=0;  
33.	      end  
34.	      if(clk_05==0)  
35.	      begin  
36.	        lock<=lock+1;  
37.	        shi_ji_zhi<=freq_m;  
38.	      end  
39.	    end  
40.	    else  
41.	      shi_ji_zhi<=0;  
42.	  end  

激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module measure_shiji_f_tb;  
3.	reg  clk_05;  
4.	reg [7:0] sin;  
5.	reg  rst_n_shiji;  
6.	wire [12:0] shi_ji_zhi;  
7.	measure_shiji_f  measure_shiji_f_inst (  
8.	  .clk_05(clk_05),  
9.	  .sin(sin),  
10.	  .rst_n_shiji(rst_n_shiji),  
11.	  .shi_ji_zhi(shi_ji_zhi)  
12.	);  
13.	initial begin  
14.	    clk_05=0;  
15.	    sin<=8'b0;  
16.	    rst_n_shiji=1;  
17.	end  
18.	always  begin  
19.	  #100 clk_05=~clk_05;  
20.	end  
21.	always  begin  
22.	  #10 sin<=8'd1;  
23.	  #10 sin<=8'd128;  
24.	  #100  
25.	  #20 sin<=8'd1;  
26.	  #20 sin<=8'd128;  
27.	end  
28.	endmodule 

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习

显示模块

显示模块利用分频器产生的10kHz的信号作时钟信号,测频电路测量出的信号频率实际值与理论频率计算电路输出的信号频率的理论值作为输入,输出七段显示译码器的位码与段码。
基于FPGA的直接数字频率合成器,fpga开发,学习

进制转换器

进制转换器的作用是将频率计算模块或者测频模块输出13位无符号二进制数,转换为对应十进制数的8421BCD码。
源代码如下

1.	`timescale 1ns / 1ps  
2.	module binary_bcd(  
3.	    input [12:0] bin_in,    //输入的二进制数  
4.	  
5.	    output [15:0] bcd_out  //输出的8421BCD码  
6.	  );  
7.	reg [3:0] ones;             //个位  
8.	reg [3:0] tens;             //十位  
9.	reg [3:0] hundreds;         //百位  
10.	reg [3:0] thousands;        //千位  
11.	integer i;  
12.	always @(bin_in) begin  
13.	    ones        = 4'd0;  
14.	    tens        = 4'd0;  
15.	    hundreds    = 4'd0;  
16.	  thousands = 4'd0;  
17.	    for(i = 12; i >= 0; i = i - 1) begin  
18.	        if (ones >= 4'd5)        ones = ones + 4'd3;  
19.	        if (tens >= 4'd5)        tens = tens + 4'd3;  
20.	        if (hundreds >= 4'd5)    hundreds = hundreds + 4'd3;  
21.	    if(thousands >= 4'd5) thousands = thousands + 4'd3;  
22.	    thousands = {thousands[1:0],hundreds[3]};  
23.	        hundreds = {hundreds[2:0],tens[3]};  
24.	        tens     = {tens[2:0],ones[3]};  
25.	        ones     = {ones[2:0],bin_in[i]};  
26.	    end  
27.	end   
28.	assign bcd_out = {thousands, hundreds, tens, ones};  
29.	endmodule  

激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module binary_bcd_tb;  
3.	reg [12:0] bin_in;  
4.	wire [15:0] bcd_out;  
5.	binary_bcd  binary_bcd_inst (  
6.	  .bin_in(bin_in),  
7.	  .bcd_out(bcd_out)  
8.	);  
9.	initial begin  
10.	    bin_in<=0;  
11.	    while (1) begin  
12.	        #100  
13.	        bin_in<={$random};  
14.	    end  
15.	end  
16.	endmodule 

仿真结果
基于FPGA的直接数字频率合成器,fpga开发,学习

BCD码翻译电路

BCD码翻译电路是将进制转换器产生的16位8421BCD码,按照个十百千位转换成用于在七段数码管上显示的段码。
源代码如下

1.	`timescale 1ns / 1ps  
2.	module trans_BCD(  
3.	    input [15:0] BCD_in,    //输入的16位BCD码  
4.	  
5.	    output  reg[27:0] show_in  //数码管显示电路输入信号  
6.	  );  
7.	  reg[3:0] thousand;       //千位  
8.	  reg[3:0] hundred;         //百位  
9.	  reg[3:0] tens;            //十位  
10.	  reg[3:0] units;           //个位  
11.	  //转换部分  
12.	  always @(*)  
13.	  begin  
14.	    thousand<=BCD_in[15:12];  
15.	    hundred<=BCD_in[11:8];  
16.	    tens<=BCD_in[7:4];  
17.	    units<=BCD_in[3:0];  
18.	    //个位  
19.	    case (units)  
20.	      0:  
21.	        show_in[6:0]<= 7'b1111110;//0  
22.	      1:  
23.	        show_in[6:0]<= 7'b0110000;//1  
24.	      2:  
25.	        show_in[6:0]<= 7'b1101101;//2  
26.	      3:  
27.	        show_in[6:0]<= 7'b1111001;//3  
28.	      4:  
29.	        show_in[6:0]<= 7'b0110011;//4  
30.	      5:  
31.	        show_in[6:0]<= 7'b1011011;//5  
32.	      6:  
33.	        show_in[6:0]<= 7'b1011111;//6  
34.	      7:  
35.	        show_in[6:0]<= 7'b1110000;//7  
36.	      8:  
37.	        show_in[6:0]<= 7'b1111111;//8  
38.	      9:  
39.	        show_in[6:0]<= 7'b1111011;//9  
40.	      default:  
41.	        show_in[6:0]<= 7'b1111110;//不显示  
42.	    endcase  
43.	    //十位  
44.	    case (tens)  
45.	      0:  
46.	        show_in[13:7]<= 7'b1111110;//0  
47.	      1:  
48.	        show_in[13:7]<= 7'b0110000;//1  
49.	      2:  
50.	        show_in[13:7]<= 7'b1101101;//2  
51.	      3:  
52.	        show_in[13:7]<= 7'b1111001;//3  
53.	      4:  
54.	        show_in[13:7]<= 7'b0110011;//4  
55.	      5:  
56.	        show_in[13:7]<= 7'b1011011;//5  
57.	      6:  
58.	        show_in[13:7]<= 7'b1011111;//6  
59.	      7:  
60.	        show_in[13:7]<= 7'b1110000;//7  
61.	      8:  
62.	        show_in[13:7]<= 7'b1111111;//8  
63.	      9:  
64.	        show_in[13:7]<= 7'b1111011;//9  
65.	      default:  
66.	        show_in[13:7]<= 7'b0000000;//不显示  
67.	    endcase  
68.	    //百位  
69.	    case (hundred)  
70.	      0:  
71.	        show_in[20:14]<= 7'b1111110;//0  
72.	      1:  
73.	        show_in[20:14]<= 7'b0110000;//1  
74.	      2:  
75.	        show_in[20:14]<= 7'b1101101;//2  
76.	      3:  
77.	        show_in[20:14]<= 7'b1111001;//3  
78.	      4:  
79.	        show_in[20:14]<= 7'b0110011;//4  
80.	      5:  
81.	        show_in[20:14]<= 7'b1011011;//5  
82.	      6:  
83.	        show_in[20:14]<= 7'b1011111;//6  
84.	      7:  
85.	        show_in[20:14]<= 7'b1110000;//7  
86.	      8:  
87.	        show_in[20:14]<= 7'b1111111;//8  
88.	      9:  
89.	        show_in[20:14]<= 7'b1111011;//9  
90.	      default:  
91.	        show_in[20:14]<= 7'b0000000;//不显示  
92.	    endcase  
93.	    //千位  
94.	    case (thousand)  
95.	      0:  
96.	        show_in[27:21]<= 7'b1111110;//0  
97.	      1:  
98.	        show_in[27:21]<= 7'b0110000;//1  
99.	      2:  
100.	        show_in[27:21]<= 7'b1101101;//2  
101.	      3:  
102.	        show_in[27:21]<= 7'b1111001;//3  
103.	      4:  
104.	        show_in[27:21]<= 7'b0110011;//4  
105.	      5:  
106.	        show_in[27:21]<= 7'b1011011;//5  
107.	      6:  
108.	        show_in[27:21]<= 7'b1011111;//6  
109.	      7:  
110.	        show_in[27:21]<= 7'b1110000;//7  
111.	      8:  
112.	        show_in[27:21]<= 7'b1111111;//8  
113.	      9:  
114.	        show_in[27:21]<= 7'b1111011;//9  
115.	      default:  
116.	        show_in[27:21]<= 7'b0000000;//不显示  
117.	    endcase  
118.	  end  
119.	endmodule 

激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module trans_BCD_tb;  
3.	reg [15:0] BCD_in;  
4.	wire [27:0] show_in;  
5.	trans_BCD  trans_BCD_inst (  
6.	  .BCD_in(BCD_in),  
7.	  .show_in(show_in)  
8.	);  
9.	initial begin  
10.	    BCD_in<=16'b1000_1000_1000_1000;  
11.	    #100  
12.	    BCD_in<=16'b0001_0010_0011_0100;  
13.	end  
14.	endmodule  

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习

动态显示部分

利用输入的28位七段数码的段码,在数码管上显示频率的理论值与实际值。
源代码如下

1.	`timescale 1ns / 1ps  
2.	module show(  
3.	    input [27:0] f_lilun_value,       //信号频率理论值  从trans_BCD模块输入       
4.	    input [27:0] f_shiji_value,       //信号频率实际值  从trans_BCD模块输入  
5.	    input clk_10k,                    //从分频器输入的10KHz信号  
6.	      
7.	    //数码管输出  
8.	    //控制左边4个数码管的输出信号  
9.	    output reg[3:0] l_dis=0,    //选通数码管的信号(动态显示)  
10.	    output reg[6:0] l_seg=0,    //控制数码管亮哪些段的信号  
11.	  
12.	    //控制右边4个数码管的输出信号  
13.	    output reg[3:0] r_dis=0,    //选通数码管的信号(动态显示)  
14.	    output reg[6:0] r_seg=0     //控制数码管亮哪些段的信号  
15.	  );  
16.	  reg[1:0] sel=0; //数码管选通信号  
17.	  always @(posedge clk_10k)  
18.	  begin  
19.	    sel=sel+1;  
20.	    //左边数码管的显示频率的 理论值  
21.	    case (sel)  
22.	      0:  
23.	      begin  
24.	        l_dis<=4'b1000;  
25.	        l_seg<=f_lilun_value[27:21];  
26.	      end  
27.	      1:  
28.	      begin  
29.	        l_dis<=4'b0100;  
30.	        l_seg<=f_lilun_value[20:14];  
31.	      end  
32.	      2:  
33.	      begin  
34.	        l_dis<=4'b0010;  
35.	        l_seg<=f_lilun_value[13:7];  
36.	      end  
37.	      3:  
38.	      begin  
39.	        l_dis<=4'b0001;  
40.	        l_seg<=f_lilun_value[6:0];  
41.	      end  
42.	      default:  
43.	      begin  
44.	        l_dis<=4'b1000;  
45.	        l_seg<=7'b0000000;  
46.	      end  
47.	    endcase  
48.	    //右边数码管显示频率的 实际值  
49.	    case (sel)  
50.	      0:  
51.	      begin  
52.	        r_dis<=4'b1000;  
53.	        r_seg<=f_shiji_value[27:21];  
54.	      end  
55.	      1:  
56.	      begin  
57.	        r_dis<=4'b0100;  
58.	        r_seg<=f_shiji_value[20:14];  
59.	      end  
60.	      2:  
61.	      begin  
62.	        r_dis<=4'b0010;  
63.	        r_seg<=f_shiji_value[13:7];  
64.	      end  
65.	      3:  
66.	      begin  
67.	        r_dis<=4'b0001;  
68.	        r_seg<=f_shiji_value[6:0];  
69.	      end  
70.	      default:  
71.	      begin  
72.	        r_dis<=4'b1000;  
73.	        r_seg<=7'b0000000;  
74.	      end  
75.	    endcase  
76.	  end  
77.	endmodule

激励脚本如下

1.	module show_tb;  
2.	  reg [27:0] f_lilun_value;  
3.	  reg [27:0] f_shiji_value;  
4.	  reg  clk_10k;  
5.	  wire [3:0] l_dis;  
6.	  wire [6:0] l_seg;  
7.	  wire [3:0] r_dis;  
8.	  wire [6:0] r_seg;  
9.	  initial  
10.	  begin  
11.	    clk_10k=0;  
12.	    f_lilun_value<=0;  
13.	    f_shiji_value<=0;  
14.	    #50  
15.	    f_lilun_value<=28'b0110000_1101101_1111001_0110011;  
16.	    f_shiji_value<=28'b0110000_1101101_1111001_0110011;  
17.	    #50  
18.	    f_lilun_value<=28'b1011011_1011111_1110000_1111111;  
19.	    f_shiji_value<=28'b1011011_1011111_1110000_1111111;  
20.	  end  
21.	  always #5  clk_10k = ! clk_10k ;  
22.	  show  show_inst (  
23.	          .f_lilun_value(f_lilun_value),  
24.	          .f_shiji_value(f_shiji_value),  
25.	          .clk_10k(clk_10k),  
26.	          .l_dis(l_dis),  
27.	          .l_seg(l_seg),  
28.	          .r_dis(r_dis),  
29.	          .r_seg(r_seg)  
30.	        );  
31.	endmodule 

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习

TOP顶层文件

将上面完成的各模块按照下图在顶层实体中连接起来。
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
其中,sys_clk是板载100MHz时钟信号,key_in为8位拨码开关作为频率控制字的输入,sel为2位的拨码开关输入,作为波形选通信号,用于选择产生不同波形,rst_n_shiji为测频电路的使能信号,控制测频电路是否能够工作。
源代码如下

1.	`timescale 1ns / 1ps  
2.	module DDS_top(  
3.	    input   sys_clk,        //板载时钟信号  
4.	    input[7:0]  key_in,     //8个拨码开关  
5.	    input   [1:0]sel,       //输出波形的选通信号  
6.	    input   rst_n_shiji,    //测频电路的使能信号  
7.	    //控制左边4个数码管的输出信号  
8.	    output [3:0] l_dis,    //选通数码管的信号(动态显示)  
9.	    output [6:0] l_seg,    //控制数码管亮哪些段的信号  
10.	    //控制右边4个数码管的输出信号  
11.	    output [3:0] r_dis,    //选通数码管的信号(动态显示)  
12.	    output [6:0] r_seg,    //控制数码管亮哪些段的信号  
13.	    //波形存储器输出,连接到AD转换器  
14.	    output [7:0] sin,  
15.	    output [4:0] rst_n_AD   //AD转换器的一些使能信号  
16.	  );  
17.	  ///  
18.	  wire clk_10k;               //10kHz时钟信号  
19.	  wire clk_05;                //0.5Hz时钟信号  
20.	  wire[7:0] address;          //波形存储器需要的地址信号  
21.	  wire[12:0] bin_in_lilun;    //理论频率计算模块 与 进制转换器 之间的连线  
22.	  wire[15:0] bcd_in_lilun;    //理论频率计算中 进制转换器 与 BCD翻译 之间的连线  
23.	  wire[27:0] f_lilun_value;   //BCD码翻译电路 与 显示模块 之间的连线  
24.	  wire[12:0] bin_in_shiji;    //测频模块 与 进制转换器 之间的连线  
25.	  wire[15:0] bcd_in_shiji;    //测频模块中 进制转换器 与 BCD翻译 之间的连线  
26.	  wire[27:0] f_shiji_value;   //BCD码翻译电路 与 显示模块 之间的连线  
27.	  ///  
28.	  //实例化分频器模块  
29.	  f_div fen_pin_qi            //分频器  
30.	        (  
31.	          .sys_clk(sys_clk),      //系统时钟信号  
32.	          //.rst_n(rst_n),          //使能信号  
33.	  
34.	          .clk_10k(clk_10k),      //10kHz时钟信号  
35.	          .clk_05(clk_05)         //0.5Hz时钟信号  
36.	        );  
37.	  //实例化累加器模块  
38.	  forever_adder leijiaqi      //累加器  
39.	                (  
40.	                  .clk_10k(clk_10k),      //累加器输入10KHz时钟信号  
41.	                  .key_in(key_in),        //外部8个拨码开关输入  
42.	  
43.	                  .address(address)       //累加器输出的ROM地址  
44.	                );  
45.	  //实例化ROM波形存储器  
46.	  ip_rom rom  
47.	         (  
48.	           .address(address),      //读取存储器地址  
49.	           .sel(sel),              //输出波形的选通信号  
50.	  
51.	           .sin(sin)               //波形输出值  
52.	         );  
53.	  //  
54.	  //实例化理论频率计算模块  
55.	  lilun_f lilun_f_inst  
56.	          (  
57.	            .clk_10k(clk_10k),          //输入10k时钟信号  
58.	            .key_in(key_in),            //输入8个拨码开关信号  
59.	  
60.	            .li_lun_zhi(bin_in_lilun)   //输出计算的频率理论值  
61.	          );  
62.	  //实例化进制转换器模块,将13位无符号二进制数转换为对应十进制数的8421BCD码  
63.	  binary_bcd binary_bcd_inst_lilun    //频率理论值的转换  
64.	             (  
65.	               .bin_in(bin_in_lilun),      //输入的13位二进制数  
66.	  
67.	               .bcd_out(bcd_in_lilun)      //输出的16位二进制数对应十进制数的BCD码  
68.	             );  
69.	  //实例化BCD码翻译电路,将BCD码翻译成适合于直接用在显示电路上的二进制码  
70.	  trans_BCD trans_BCD_inst_lilun      //理论频率BCD转换为数码管二进制  
71.	            (  
72.	              .BCD_in(bcd_in_lilun),      //输入的16位BCD码  
73.	  
74.	              .show_in(f_lilun_value)     //将BCD输入到显示模块中  
75.	            );  
76.	  ///  
77.	  //实例化测频电路(测量实际频率的电路)  
78.	  measure_shiji_f measure_shiji_f_inst  
79.	                  (  
80.	                    .clk_05(clk_05),            //输入的0.5Hz时钟信号  
81.	                    .sin(sin),                  //输入 波形存储器输出 的信号  
82.	                    .rst_n_shiji(rst_n_shiji),  //测频电路的使能信号  
83.	  
84.	                    .shi_ji_zhi(bin_in_shiji)   //输出测量的频率值  
85.	                  );  
86.	  //实例化进制转换器模块,将13位无符号二进制数转换为对应十进制数的8421BCD码  
87.	  binary_bcd binary_bcd_inst_shiji    //频率理论值的转换  
88.	             (  
89.	               .bin_in(bin_in_shiji),      //输入的13位二进制数  
90.	  
91.	               .bcd_out(bcd_in_shiji)      //输出的16位二进制数对应十进制数的BCD码  
92.	             );  
93.	  //实例化BCD码翻译电路,将BCD码翻译成适合于直接用在显示电路上的二进制码  
94.	  trans_BCD trans_BCD_inst_shiji      //理论频率BCD转换为数码管二进制  
95.	            (  
96.	              .BCD_in(bcd_in_shiji),      //输入的16位BCD码  
97.	  
98.	              .show_in(f_shiji_value)     //将BCD输入到显示模块中  
99.	            );  
100.	  ///  
101.	  //显示模块,左边显示理论值,右边显示实际值  
102.	  show show_inst  
103.	       (  
104.	         .f_lilun_value(f_lilun_value),  //频率理论值  
105.	         .f_shiji_value(f_shiji_value),  //频率实际值  
106.	         .clk_10k(clk_10k),              //输入10k时钟信号  
107.	  
108.	         .l_dis(l_dis),                  //输出左边数码管位码  
109.	         .l_seg(l_seg),                  //输出左边数码管对应值  
110.	         .r_dis(r_dis),                  //输出右边数码管位码  
111.	         .r_seg(r_seg)                  //输出右边数码管对应值  
112.	       );  
113.	    
114.	  assign rst_n_AD=5'b00001;  
115.	endmodule  

激励脚本如下

1.	`timescale 1ns / 1ps  
2.	module DDS_top_tb;  
3.	reg  sys_clk;  
4.	reg [7:0] key_in;  
5.	reg [1:0] sel;  
6.	reg  rst_n_shiji;  
7.	wire [3:0] l_dis;  
8.	wire [6:0] l_seg;  
9.	wire [3:0] r_dis;  
10.	wire [6:0] r_seg;  
11.	wire [7:0] sin;  
12.	wire [4:0] rst_n_AD;  
13.	DDS_top  DDS_top_inst (  
14.	  .sys_clk(sys_clk),  
15.	  .key_in(key_in),  
16.	  .sel(sel),  
17.	  .rst_n_shiji(rst_n_shiji),  
18.	  .l_dis(l_dis),  
19.	  .l_seg(l_seg),  
20.	  .r_dis(r_dis),  
21.	  .r_seg(r_seg),  
22.	  .sin(sin),  
23.	  .rst_n_AD(rst_n_AD)  
24.	);  
25.	initial begin  
26.	    sys_clk=0;  
27.	    key_in<=8'b0000_0000;  
28.	    sel<=2'b01;  
29.	    rst_n_shiji<=1;  
30.	    #10  
31.	    key_in<=8'b0000_0001;  
32.	end  
33.	always #5  sys_clk = ! sys_clk ;  
34.	  
35.	endmodule

仿真结果如下
基于FPGA的直接数字频率合成器,fpga开发,学习
上图为运行3s后的波形
顶层模块的约束文件

1.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[7]}]  
2.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[6]}]  
3.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[5]}]  
4.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[4]}]  
5.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[3]}]  
6.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[2]}]  
7.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[1]}]  
8.	set_property IOSTANDARD LVCMOS33 [get_ports {key_in[0]}]  
9.	set_property IOSTANDARD LVCMOS33 [get_ports {l_dis[3]}]  
10.	set_property IOSTANDARD LVCMOS33 [get_ports {l_dis[2]}]  
11.	set_property IOSTANDARD LVCMOS33 [get_ports {l_dis[1]}]  
12.	set_property IOSTANDARD LVCMOS33 [get_ports {l_dis[0]}]  
13.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[6]}]  
14.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[5]}]  
15.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[4]}]  
16.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[3]}]  
17.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[2]}]  
18.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[1]}]  
19.	set_property IOSTANDARD LVCMOS33 [get_ports {l_seg[0]}]  
20.	set_property IOSTANDARD LVCMOS33 [get_ports {r_dis[3]}]  
21.	set_property IOSTANDARD LVCMOS33 [get_ports {r_dis[2]}]  
22.	set_property IOSTANDARD LVCMOS33 [get_ports {r_dis[1]}]  
23.	set_property IOSTANDARD LVCMOS33 [get_ports {r_dis[0]}]  
24.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[6]}]  
25.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[5]}]  
26.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[4]}]  
27.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[3]}]  
28.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[2]}]  
29.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[1]}]  
30.	set_property IOSTANDARD LVCMOS33 [get_ports {r_seg[0]}]  
31.	set_property IOSTANDARD LVCMOS33 [get_ports {rst_n_AD[4]}]  
32.	set_property IOSTANDARD LVCMOS33 [get_ports {rst_n_AD[3]}]  
33.	set_property IOSTANDARD LVCMOS33 [get_ports {rst_n_AD[2]}]  
34.	set_property IOSTANDARD LVCMOS33 [get_ports {rst_n_AD[1]}]  
35.	set_property IOSTANDARD LVCMOS33 [get_ports {rst_n_AD[0]}]  
36.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[7]}]  
37.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[6]}]  
38.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[5]}]  
39.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[4]}]  
40.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[3]}]  
41.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[2]}]  
42.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[1]}]  
43.	set_property IOSTANDARD LVCMOS33 [get_ports {sin[0]}]  
44.	set_property IOSTANDARD LVCMOS33 [get_ports rst_n_shiji]  
45.	set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]  
46.	set_property PACKAGE_PIN P5 [get_ports {key_in[7]}]  
47.	set_property PACKAGE_PIN P4 [get_ports {key_in[6]}]  
48.	set_property PACKAGE_PIN P3 [get_ports {key_in[5]}]  
49.	set_property PACKAGE_PIN P2 [get_ports {key_in[4]}]  
50.	set_property PACKAGE_PIN R2 [get_ports {key_in[3]}]  
51.	set_property PACKAGE_PIN M4 [get_ports {key_in[2]}]  
52.	set_property PACKAGE_PIN N4 [get_ports {key_in[1]}]  
53.	set_property PACKAGE_PIN R1 [get_ports {key_in[0]}]  
54.	set_property PACKAGE_PIN U3 [get_ports rst_n_shiji]  
55.	set_property PACKAGE_PIN P17 [get_ports sys_clk]  
56.	set_property PACKAGE_PIN G2 [get_ports {l_dis[3]}]  
57.	set_property PACKAGE_PIN C2 [get_ports {l_dis[2]}]  
58.	set_property PACKAGE_PIN C1 [get_ports {l_dis[1]}]  
59.	set_property PACKAGE_PIN H1 [get_ports {l_dis[0]}]  
60.	set_property PACKAGE_PIN B4 [get_ports {l_seg[6]}]  
61.	set_property PACKAGE_PIN A3 [get_ports {l_seg[4]}]  
62.	set_property PACKAGE_PIN B1 [get_ports {l_seg[3]}]  
63.	set_property PACKAGE_PIN A1 [get_ports {l_seg[2]}]  
64.	set_property PACKAGE_PIN A4 [get_ports {l_seg[5]}]  
65.	set_property PACKAGE_PIN B3 [get_ports {l_seg[1]}]  
66.	set_property PACKAGE_PIN B2 [get_ports {l_seg[0]}]  
67.	set_property PACKAGE_PIN G1 [get_ports {r_dis[3]}]  
68.	set_property PACKAGE_PIN F1 [get_ports {r_dis[2]}]  
69.	set_property PACKAGE_PIN E1 [get_ports {r_dis[1]}]  
70.	set_property PACKAGE_PIN G6 [get_ports {r_dis[0]}]  
71.	set_property PACKAGE_PIN D4 [get_ports {r_seg[6]}]  
72.	set_property PACKAGE_PIN E3 [get_ports {r_seg[5]}]  
73.	set_property PACKAGE_PIN D3 [get_ports {r_seg[4]}]  
74.	set_property PACKAGE_PIN F4 [get_ports {r_seg[3]}]  
75.	set_property PACKAGE_PIN F3 [get_ports {r_seg[2]}]  
76.	set_property PACKAGE_PIN E2 [get_ports {r_seg[1]}]  
77.	set_property PACKAGE_PIN D2 [get_ports {r_seg[0]}]  
78.	set_property PACKAGE_PIN V7 [get_ports {rst_n_AD[4]}]  
79.	set_property PACKAGE_PIN R6 [get_ports {rst_n_AD[3]}]  
80.	set_property PACKAGE_PIN V6 [get_ports {rst_n_AD[2]}]  
81.	set_property PACKAGE_PIN N6 [get_ports {rst_n_AD[1]}]  
82.	set_property PACKAGE_PIN R5 [get_ports {rst_n_AD[0]}]  
83.	set_property PACKAGE_PIN U9 [get_ports {sin[7]}]  
84.	set_property PACKAGE_PIN V9 [get_ports {sin[6]}]  
85.	set_property PACKAGE_PIN U7 [get_ports {sin[5]}]  
86.	set_property PACKAGE_PIN U6 [get_ports {sin[4]}]  
87.	set_property PACKAGE_PIN R7 [get_ports {sin[3]}]  
88.	set_property PACKAGE_PIN T6 [get_ports {sin[2]}]  
89.	set_property PACKAGE_PIN R8 [get_ports {sin[1]}]  
90.	set_property PACKAGE_PIN T8 [get_ports {sin[0]}]  
91.	  
92.	set_property IOSTANDARD LVCMOS33 [get_ports {sel[1]}]  
93.	set_property IOSTANDARD LVCMOS33 [get_ports {sel[0]}]  
94.	set_property PACKAGE_PIN U2 [get_ports {sel[1]}]  
95.	set_property PACKAGE_PIN V2 [get_ports {sel[0]}] 

到此,电路设计完成。

上板验证

基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习
可以正常输出4中波形。
基于FPGA的直接数字频率合成器,fpga开发,学习
基于FPGA的直接数字频率合成器,fpga开发,学习

碎碎念

在设计过程中还犯了一个低级错误,在写二进制数时,应当在前面定义“[位宽]’b”,这样程序在运行时才能将数以二进制数进行处理,否则就会以十进制数进行编译,这样写的结果虽然在语法上并没有问题,但是逻辑上并不正确。
基于FPGA的直接数字频率合成器,fpga开发,学习
找一找左右两边有什么不同。哎,当时找了一下午才反映过来文章来源地址https://www.toymoban.com/news/detail-767006.html

到了这里,关于基于FPGA的直接数字频率合成器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的数字频率计的设计与实现

    基于FPGA的数字频率计的设计与实现 数字频率计是一种重要的电子测试仪器,它可以用来测量信号的频率和周期等参数,被广泛应用于科学研究、工程设计及生产制造等领域。本文将介绍一种基于FPGA的数字频率计的设计与实现方法,并给出相应的源代码。 一、设计原理 数字

    2024年01月23日
    浏览(49)
  • 【FPGA & Modsim】数字频率计

    module flag(clk,rst_n,cnt); input clk; input rst_n; output [2:0]cnt ; reg[31:0]count ; reg [2:0]cnt; always@(posedge clk or negedge rst_n) begin if(~rst_n)begin count=0 ; cnt=3\\\'d0 ;end else if (count= 32\\\'d24 999) begin cnt=cnt+1\\\'b1 ;count=32\\\'d0 ; end else if (cnt=3\\\'d6) begin cnt=0;end else count=count+1\\\'b1 ; end endmodule \\\'timescale 1 ns/ 1ps / module seg (

    2024年01月16日
    浏览(44)
  • 基于FPGA的频率计

    好久没更了,百忙之中写一篇so easy的代码——基于FPGA的频率计设计。 废话不多说,下面是百度搜索关于频率计的简洁概念。 数字频率计是一种基本的测量仪器,被广泛应用于航天、电子、测控等领域。基于传统测频原理的频率计的测量精度将随被测信号频率的下降而降低,

    2024年02月12日
    浏览(44)
  • 【FPGA】时序逻辑电路——基于计数器实现一个以1秒频率闪烁的LED灯

    1 D触发器 分析: 特性:输出端Q只在CK处于上升沿的时候变化 图中波形的形成过程: 当D处于高电平时,CK未处于上升沿时,Q仍处于低电平 当CK来到上升沿,Q需要根据D发生变化,由于D是高电平,所以Q要从低电平变化成高电平 D从高电平变化成低电平,但是此时CK未来到上升沿

    2024年02月09日
    浏览(43)
  • 基于FPGA的DDS开发和实现,可修改输出正弦的频率和相位,包含testbench

    目录 1.算法仿真效果 2.算法涉及理论知识概要 3.Verilog核心程序 4.完整算法代码文件 vivado2019.2仿真结果如下: 输出2个不同频率的正弦信号:  修改相位,得到如下所示。      直接数字频率合成技术 (Direct Digital Synthesis)完全不同于我们己经熟悉的直接频率合成技术和锁相环频

    2024年02月04日
    浏览(48)
  • 基于FPGA的数字时钟系统设计

    在FPGA的学习中,数字时钟是一个比较基础的实验案例,通过该实验可以更好的锻炼初学者的框架设计能力以及逻辑思维能力,从而打好坚实的基本功,接下来就开始我们的学习吧! 1.数码管介绍 数码管通俗理解就是将8个LED(包含dp部分)灯拼接到一起组成的,分别标号为a~g。前

    2024年02月06日
    浏览(45)
  • 基于FPGA的数字钟设计

    这篇文章通过VHDL代码实现数字钟的功能,绑定引脚就可以看到实际的效果。 代码运行成功,就可以实现了计时(年月日/时分秒)、秒表、倒计时、闹钟的全部功能。

    2024年02月11日
    浏览(56)
  • 基于FPGA的数字密码锁

    testbench 到此结束,如有问题请留言评论

    2024年02月04日
    浏览(51)
  • 基于FPGA的可调数字钟设计

            在此特别感谢哔站up主 甘第 发布的FPGA企业实训课(基于FPGA的数字钟设计)教学视频,让一个FPGA小白开始了第一个FPGA设计开发流程。本设计参考了这个教学视频,在此基础上添加并修改了一些代码,完成了这个小小的不带任何功能的数字时钟。         初次学习

    2024年02月06日
    浏览(58)
  • 基于FPGA的数字时钟(使用vivado)

    使用两个四位数码管,可以实现时钟分钟秒钟显示,高两位设置不显示。 换了一个新开发板,nexys4ddr,资料不多,最多使用的就是一本英文Reference Manual。 其实是老师觉得我计数器还差点,得再练练。 Digilent NEXYS4DDR Vivado2018.3 60进制秒钟计数然后进1分钟 60进制分钟计数然后进

    2024年02月03日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包