本程序要求设计一个波形发生器,生成正弦波、三角波、经过ASK调制的正弦波和经过BSPK调制的正弦波,通过开关可以选择波形,改变输出频率。各开关的控制功能如表 9-1和表 9-2所示。

表 9-1 波形选择控制

输入端口SW1 SW2波形
wave_selc 0 0ASK调制的正弦波
0 1正弦波
1 0三角波
1 1BPSK调制的正弦波

表 9-2 频率选择控制

输入端口SW3 SW4频率
fre 0 0500KHZ,每周期采样100点
0 11MHZ,每周期采样50点
1 02MHZ,每周期采样25点
1 15MHZ每周期采样10点



图9-1 任意波形发生器原理图

图9-1 任意波形发生器原理图

本实验运用查表法来实现信号发生器,查表法的由相位累加器和存储器构成,如图9 1所示。相位累计器的功能是产生正弦波和三角波的相位值。每隔一个时钟周期,累加器的相位值自动增加一定的相位值,并将当前的相位值作为查找表的输入值进行查表。通过改变每次增加的相位值可以控制输出信号的频率。例如,每个时钟周期累加器的相位值增加90度,则4个时钟周期产生一个完整的正弦波。输出信号的周期为时钟周期的1/4。

查找表用RAM来构造。例如,如果把相位值作为RAM的地址,只要在该地址中存储相应的正余弦幅度值,就可通过相位值寻址RAM,输出正弦函数。

由于FPGA芯片的存储器资源非常有限,如何有效的利用资源成为本实验非常关键的地方。考虑到正弦波以及三角波的周期性与对称性,在RAM表中只需要存储1/2 周期的波形数据即可。在本设计中,一个波形周期内的采样点为100个,因此实际在RAM表中只需存50个采样点,这样就减少了芯片硬件资源的消耗。



3.1 程序架构

程序的总体架构如图9 2所示,程序的顶层模块为arbtywave。其中有四个模块Sinewave、ASKsquwave、BPSKsquwave和triwave,分别生成正弦波、ASK正弦波、BPSK正弦波和三角波。通过一个多路选择器选择需要输出的波形,由输入信号waveselc来控制。 图9-2 程序架构

图9-2 程序架构

顶层模块arbty_wave的输入输出接口如下:

 
input clk;					//系统时钟, 50MHz。
input rst_n;				//异步复位,低电平有效。
input [1:0]wave_selc;		//波形选择开关, sw1, sw2。
input [1:0]fre;				//频率选择开关, sw3, sw4
output [13:0]wave;			//输出波形。
output clk_out;				// D/A转换的时钟

程序中的四个模块发生器的结构非常类似,在此以正弦波为例介绍设计思路。

3.2 sine_wave模块

sine_wave产生频率可调的正弦波形,输入输出接口如下:

 
input clk;				//系统时钟,50MHZ
input clr;				//异步置位,低电平有效
input [1:0]fre;			//频率选择开关
output [13:0]wave_si;   //输出正弦波

本实验要生成的正弦波形图如图9 3所示,过零点在2000H处。在实验原理中已经指出,本实验中采用查表法生成所需要的波形,查找表中存储了正弦波的相位和幅度之间的对应关系,查找表存储在FPGA的内部存储器中,使用QuartusⅡ的Mega Winzard来定制需要的RAM。

每一个周期的正弦波有100个采样点,原则上要在RAM中存储这100个采样点的幅度值,但是由于正弦波的前半个时钟周期和后半个时钟周期是对称的,因此只需要存储前面50个采样点的幅度值即可。后半个时钟周期采样点N的幅度值等于2000H-采样点(N-50)的幅度值。 图9-3  正弦波形图

图9-3 正弦波形图

在生成RAM前,先用matlab计算正弦波的幅度值:

 
          x=round(sin(linspace(0,pi,49))*5200);
          for i=1:1:49
               y=x(i)
          end
y=
0    340  679  1014  1346 1671  1990 2300
2600 2889 3166 3429  3677 3910  4125 4324
4503 4664 4804 4924  5023 5100  5156  5189
5200 5189 5156 5100  5023 4924  4804 4664 
4503 4324 4125 3910  3677 3429  3166 2889
2600 2300 1990 1671  1346 1014  679  340

在Quartus II中新建一个.mif文件,用于存储正弦函数的幅度值,这些值将初始到内部存储器中。在QuartusⅡ中新建.mif文件的过程为:File-〉New-〉Other Files-〉Memory Initialization File。将上述数据复制到.mif文件的表格中(图9 4),保存上述.mif文件为data_sine.mif。 图9-4  mif文件内容

图9-4 mif文件内容

用Quartus II中的Mega Winzard定制一个单端口ROM,具体流程如下:
1) 点击Tools菜单栏下的“Megawizard Plug-in Wizard”选项,新建一个megafunction variation(图 9-5)。 图 9-5 新建megafunction variation

图 9-5 新建megafunction variation

2) 选择ROM:1-PORT,设置器件类型为CycloneⅡ,输出文件类型为Verilog HDL,输入文件名sine,点击下一步(图9-6)。 图9-6 选择RAM类型

图9-6 选择RAM类型

3) 定义存储器深度为50个字(word),存储器的深度为14bit。使用M4K存储器。点击下一步(图9-7)。 图9-7 设置RAM参数

图9-7 设置RAM参数

4) 将新建的data_sine.mif文件导入至RAM中(图9-8)。 图9-8 导入mif文件

图9-8 导入mif文件

5) 然后按finish完成了1-PORT ROM的定制。 在sine_wave模块中,计数器counter作为相位控制器来根据频率的来决定相位的变化。

 
module BPSK_sqwave(clk, clr, fre, bpsk_sq);
		input clk;				//时钟信号,50MHZ
		input clr;				//复位信号
		input [1:0]fre;			//频率控制信号
 
		output [13:0]wave_si;	//正弦波形输出
		reg [13:0]wave_si;
		reg [5:0]index;			//RAM地址
		//counter控制正弦波的相位,根据频率的不同控制相位的变化。
reg [6:0]counter;		
		wire [13:0]q;
		//正弦波幅度存储器,index和clk是输入,q为幅度输出。
		sine sine (index, clk ,q); 
 
//phase_controller确定正弦波的相位counter。
always @(posedge clk or negedge clr) begin  : phase_controller 
if(!clr)
   	counter<=7'b0;
else begin
case(fre)
2'b00: begin //频率500KHz,每信号周期采样100个点。
			if(counter>=7'b110_0011)
				counter<=7'b0;
			else
			     counter<=counter+7'b1; //每时钟周期加1。
		end
		2'b01: begin //频率1MHz,每信号周期采样50个点。
			if(counter>=7'b110_0010)
		 		counter<=7'b0;
			 else
			     counter<=counter+7'd2; //每时钟周期加2。
		end
		2'b10: begin //频率2MHz,每个信号周期采样25个点。
			if(counter>=7'b110_0000)
			  	counter<=7'b0;
			  else
			 	counter<=counter+7'd4; //每时钟周期加4。
		end
2'b11: begin //频率5MHz,每信号周期采样10个点。
			if(counter>=7'b101_1010)
			  	counter<=7'b0;
			else
				counter<=counter+7'd10; //每时钟周期加10。
		end
endcase
		end
end
 
	//index_controller控制RAM访问地址index,由于sine的对称性,
//当相位小于50时,index等于相位;当相位超过50时,相位减去50得到index。
always @ (counter ) begin : index_controller
		if(counter<=7'b011_0001)
			index<=counter;
		else 
		   	index<=counter-8'd50;
	end
 
	//由于对RAM的访问需要两个时钟周期,因此对相位counter延时2个时钟周期,得到
	//counter2,counter2和RAM的输出q同步。
	reg [6:0] counter1;
	reg [6:0] counter2;
	always @(posedge clk or negedge clr) begin
		if(!clr)  begin
			counter1 <= 0;
			counter2 <= 0;
		end
		else begin
			counter1 <= counter;
			counter2 <= counter1;
		end
	end
 
	//wave_si_out产生正弦波波形输出。
	always @(posedge clk or negedge clr) begin : wave_si_out
		if(!clr)  begin
	     	wave_si<=14'b0;
	    end
		else begin			
			if( counter2<=7'd50 ) 
				wave_si<={1'b1,q}; //相位小于50时,将q信号加上2000h输出。加2000h的目的是2000h为正弦波的过零位置。
			else
				wave_si<=14'h2000-q //相位大于50时,取的q值是counter2-50的幅度值,需要由过零值2000h减去q,得到对应的值。
		end
	end
endmodule



图9-9到图9-12为通过SignalTap看到的运行结果,分别是正弦波、三角波、ASK调制波形和BPSK调制波形。 图9-9 SignalTap波形——正弦波

图9-9 SignalTap波形——正弦波

图9-10 SignalTap波形——三角波

图9-10 SignalTap波形——三角波

图9-11 SignalTap波形——ASK调制正弦波

图9-11 SignalTap波形——ASK调制正弦波

图9-12 SignalTap波形——BPSK调制正弦波

图9-12 SignalTap波形——BPSK调制正弦波

用逻辑分析仪观测波形时要注意,在Data栏右键点击wave信号,选择Bus Display Format→Unsigned Line Chart,这样可以更形象地考到波形输出。

此外,从SignalTap看到的波形是未经过D/A转换的数字波形图,用示波器连接到D/A芯片的输出管脚可以看到经过D/A转换后的模拟波形。



文件名功能
arbtywave.v|主程序| |sinwave.v频率可调正弦波发生程序
triwave.v|频率可调三角波发生程序| |Pwmtest.mpf|ModelSim仿真工程| |ASKsq.v频率可调ASK调制正弦波发生程序
BPSK_sq.v频率可调BPSK调制正弦波发生程序



演示设备要求:核心板,扩展板。
演示步骤:把程序下载到开发板上之后,配置好逻辑分析仪,通过逻辑分析仪观察输出结果。通过扩展板上的按键可观察到波形的变化,通过拨动SW1、SW2,可观察到波形的改变;通过波动SW3、SW4,可观察到波形频率的改变。