当前位置:   article > 正文

基于FPGA实现的DDS双通道信号发生器_什么是双通道信号发生器

什么是双通道信号发生器


前言

本文使用Altera公司生产的EP4CE22F17C6开发板和小梅哥的高速DAC,——ACM9767,基于Quartus18.1实现对DDS信号发生器的设计。

一、DDS是什么?

DDS同 DSP(数字信号处理)一样,是一项关键的数字化技术。DS芯片中主要包括频率控制寄存器、高速相位累加器和正弦计算器三个部分(如Q2220)。DDS是直接数字式频率合成器(Direct Digital Synthesizer)的英文缩写。与传统的频率合成器相比,DDS具有低成本、低功耗、高分辨率和快速转换时间等优点,广泛使用在电信与电子仪器领域,是实现设备全数字化的一个关键技术。

二、设计步骤

1.DDS的基本结构

在这里插入图片描述
DDS的结构主要由相位累加器,相位调制器,波形数据表ROM,DAC组成。相位累加器和相位调制器的存在都是为了生成ROM的地址,与后续ROM的导入结合。

1.相位累加器

相位累加器为计数器对频率字输入的累加,其中加法器与寄存器均为N位(N一般取24~32位),在每个时钟的上升沿将频率控制字与寄存器中数据进行相加,相加结果再与下一个时钟上升沿的频率字相加,如此重复。频率控制字Fword与N决定了DDS输出的步频(频率),f out=Fword*f clk/2^N。

2.相位调制器

若ROM地址为M位,相位调制器则为取出相位累加器的高M位与相位控制字相加。Verilog里难以实现对于小数的除法,故对于缩小步频的操作可以使用结位的方法。Pword用于调制DDS输出相位。

3.ROM数据表的生成

ROM是只读储存器的简称,在ROM中一个地址对应一个输出值,基于相位累加器和相位调制器生成的地址,在ROM数据表内存入所输出波形的输出值。本文使用Quartus自带的IP核生成ROM,其中使用的mif文件使用Mif_maker生成。Mif_maker文件下载
在Mif_maker里可以设置所需波形类型,地址宽度,输出深度,生成mif文件后,在ROM中导入,在后续模块中例化使用。

2.对各结构的代码实现

1.DDS顶层代码`

采用了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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183

2.DDS主要发生模块

用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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

3.按键消抖模块

状态机实现按键消抖。

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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

3 testbench的编写

`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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

4.modelsim仿真波形

在这里插入图片描述

5.整体效果硬件下载结果

1khz时的正弦波
10MHZ时的正弦波
20MHZ时的正弦波,已出现失真现象
100HZ时的方波和三角波
100HZ时的正弦波和锯齿波

总结

DDS是大学学习FPGA以来第一个做的比较完整的模块, 跟着小梅哥的课,总算是有了一些自主能力。前路昭然,你我共进。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号