基于STM32与FPGA设计的DDS

概要

    本设计是由FPGA扩展MCU开发的DDS。具有两个波形通道、一个TTL通道和频率计通道。波形通道能够产生10MHz以内的正弦波、三角波和方波;TTL产生1M以内的TTL信号;频率计可测5M以内的信号。

实物图:

 DDS设计原理

    本设计最核心的部分是任意频率的输出与高精度频率的测量。

    频率可调:在FPGA中开辟8位数据位宽的ROM波形数据。通过改变地址计数器在每个时钟信号到来时所加的基数,然后读取的时候取地址计数器的高八位实现频率功能。地址计数器位宽为32位,最终输出的ROM地址取其高8位。那么输出信号的最低频率为 clk/2^32 。若时钟信号为100M,则最低频率为0.0232831Hz。想要其他的频率,再在这个基础频率上相乘就行了,如果我要得到10K的输出频率,则32位地址每个时钟到来所加的数值位10K/0.0232831 = 429496,让地址计数器每个时钟来了加 429496,取地址计数器的高8位作为ROM的地址读取数据,这样就可以方便的调频。

//A B通道信号控制输出

module dds_signal(
							clk_100M , rst_n ,
							
							add_frequency_A , add_frequency_B ,//控制信号
							wave_A , wave_B ,
							
							pass_A_data , pass_B_data ,    //输出信号
							
							duty_cycle_A , duty_cycle_B
					  );
					  
input clk_100M;    //100MHz时钟信号
input rst_n;       //复位信号

input [31:0] add_frequency_A;    //A通道频率加值
input [31:0] add_frequency_B;    //B通道频率加值
input [7:0] wave_A;              //A通道波形数据
input [7:0] wave_B;              //B通道波形数据

input [7:0] duty_cycle_A;              //A占空比数据 
input [7:0] duty_cycle_B;              //B占空比数据

output [7:0] pass_A_data;    //输出A波形数据
output [7:0] pass_B_data;    //输出B波形数据

//------------------------------------------//
//------------------------------------------//

//波形数据
wire [7:0] address_A;        //A通道数据存储地址
wire [7:0] address_B;        //B通道数据存储地址

wire [7:0] pass_A_sin_data;
wire [7:0] pass_B_sin_data;
wire [7:0] pass_A_tri_data;
wire [7:0] pass_B_tri_data;
/*
wire [7:0] pass_A_sqr_data;
wire [7:0] pass_B_sqr_data;
*/
//正弦波
sin i1( 
			.address(address_A),
			.clock(clk_100M),
			.q(pass_A_sin_data)
		);
		  
sin i2( 
			.address(address_B),
			.clock(clk_100M),
			.q(pass_B_sin_data)
		);	
		  
//三角波
wave_tri i3(
				.address(address_A),
				.clock(clk_100M),
				.q(pass_A_tri_data)
			  );
					
wave_tri i4(
				.address(address_B),
				.clock(clk_100M),
				.q(pass_B_tri_data)
			  );
				
//方波
/*
wave_sqr i5(
				 .address(address_A),
			    .clock(clk_100M),
				 .q(pass_A_sqr_data)
			  );
		  
wave_sqr i6(
				 .address(address_B),
			    .clock(clk_100M),
				 .q(pass_B_sqr_data)
			  );
			  */
			  
/
reg [7:0] pass_A_sqr_data;
			  
always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		pass_A_sqr_data <= 8'd0;
		
	else if( address_A < duty_cycle_A )
		pass_A_sqr_data <= 8'd255;
	else 
		pass_A_sqr_data <= 8'd0;
end

///

reg [7:0] pass_B_sqr_data;

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		pass_B_sqr_data <= 8'd0;
		
	else if( address_B < duty_cycle_B )
		pass_B_sqr_data <= 8'd255;
	else 
		pass_B_sqr_data <= 8'd0;
end
					
//------------------------------------------//
					
reg [7:0] pass_A_data_r;

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		pass_A_data_r <= 8'd0;
		
	else begin
		case( wave_A )
			8'haa: begin
				pass_A_data_r <= pass_A_sin_data;
			end
		
			8'hbb: begin
				pass_A_data_r <= pass_A_tri_data;
			end
			
			8'hcc: begin
				pass_A_data_r <= pass_A_sqr_data;
			end
			default: ;
		endcase
	end
end
					
assign pass_A_data = pass_A_data_r;

//------------------------------------------//

reg [7:0] pass_B_data_r;

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		pass_B_data_r <= 8'd0;
		
	else begin
		case( wave_B )
			8'haa: begin
				pass_B_data_r <= pass_B_sin_data;
			end
			
			8'hbb: begin
				pass_B_data_r <= pass_B_tri_data;
			end
			
			8'hcc: begin
				pass_B_data_r <= pass_B_sqr_data;
			end
			default: ;
		endcase
	end
end	

assign pass_B_data = pass_B_data_r;

//------------------------------------------//
//------------------------------------------//
//32位数据地址
reg [31:0] address_A_r;    

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n )
		address_A_r <= 32'd0;
		
	else 
		address_A_r <= address_A_r + add_frequency_A;
end

assign address_A = address_A_r[31:24];

//------------------------------------------//

reg [31:0] address_B_r;    

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n )
		address_B_r <= 32'd0;
		
	else 
		address_B_r <= address_B_r + add_frequency_B;
end

assign address_B = address_B_r[31:24];	

//------------------------------------------//

endmodule
					  

高精度频率的测量:高精度的频率测量采用等精度频率测量的方法。

主体结构:

信号波形

     BCLK为100M时钟信号、TCLK为被测信号、CL为预置闸门信号、START为设计闸门信号。

     BZH与TF为32为计数器,BZH为实际闸门信号内时钟信号的周期个数,TF为实际闸门信号内被测信号的周期个数。

D触发器可以保证实际闸门信号的时间是被测信号的周期时间的整数倍,从而能够保持恒定精度。测得时钟信号的周期个数Na与被测信号的周期个数Nx后,由关系式 Fa/Na = Fx/Nx,可求出被测信号的频率。

//测频模块

module dds_extf(
                  clk_100M , rst_n ,
						sig_in ,
						cnt_bzh_value , cnt_tf_value ,
						led
               );
					
input clk_100M;     //100M输入数字信号
input rst_n;        //复位信号
input sig_in;       //测频信号输入

output [31:0] cnt_bzh_value;  //标准计数器输出
output [31:0] cnt_tf_value;   //测量计数器输出

output [2:0] led;
 
//-----------------------------//
parameter T_10ms = 20'd1000_000;  //时间10ms

reg [19:0] cnt0;  //计数寄存器
wire add_cnt0;    //加1条件
wire end_cnt0;    //结束条件

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		cnt0 <= 20'd0;
		
	else if( add_cnt0 ) begin
		if( end_cnt0 )
			cnt0 <= 20'd0;
		else
			cnt0 <= cnt0 + 1'b1;
	end
end

assign add_cnt0 = 1'b1;
assign end_cnt0 = add_cnt0 && ( cnt0==T_10ms-1'b1 );


parameter T_1s = 7'd101;

reg [6:0] cnt1;    
wire add_cnt1;
wire end_cnt1;

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		cnt1 <= 7'd0;
		
	else if( add_cnt1 ) begin
		if( end_cnt1 )
			cnt1 <= 7'd0;
		else 
			cnt1 <= cnt1 + 1'b1;
	end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && ( cnt1==T_1s-1'b1 );


//预置闸门
reg preset_gate;   //预置闸门信号

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n )
		preset_gate <= 1'b0;
		
	else if( cnt1 == 7'd1 )
		preset_gate <= 1'b1;
	else if( end_cnt1 )
		preset_gate <= 1'b0;
end

//-----------------------------//
//实际闸门
reg actual_gate;    //实际闸门信号

always @( posedge sig_in or negedge rst_n ) begin
	if( !rst_n ) 
		actual_gate <= 1'b0;
		
	else if( preset_gate == 1'b1 )
		actual_gate <= 1'b1;
	else 
		actual_gate <= 1'b0;
end

//-----------------------------//
//标准信号100M计数器
reg [31:0] cnt_bzh;

always @( posedge clk_100M or negedge rst_n ) begin
	if( !rst_n ) 
		cnt_bzh <= 32'd0;
		
	else if( actual_gate == 1'b1 )
			cnt_bzh <= cnt_bzh + 1'b1;
	else 
		cnt_bzh <= 32'd0;
end

//
//实际闸门的下降沿锁存
reg [31:0] cnt_bzh_value_r;

always @( negedge actual_gate or negedge rst_n ) begin
	if( !rst_n )
		cnt_bzh_value_r <= 32'd0;
		
	else 	
	cnt_bzh_value_r <= cnt_bzh;
end

assign cnt_bzh_value = cnt_bzh_value_r;

//-----------------------------//
//输入信号计数器
reg [31:0] cnt_tf;

always @( posedge sig_in or negedge rst_n ) begin
	if( !rst_n )
		cnt_tf <= 32'd0;
	
	else if( actual_gate == 1'b1 )
		cnt_tf <= cnt_tf + 1'b1;
	else 
		cnt_tf <= 32'd0;
end

//
//实际闸门的下降沿锁存
reg [31:0] cnt_tf_value_r;

always @( negedge actual_gate or negedge rst_n ) begin
	if( !rst_n )
		cnt_tf_value_r <= 32'd0;
		
	else 
		cnt_tf_value_r <= cnt_tf;
end

assign cnt_tf_value = cnt_tf_value_r;

//-----------------------------//

assign led = 3'b000;

//-----------------------------//
 
endmodule

硬件设计

     电源部分:

    电源由AC220V输入,经过前级稳压为双电源12V,正12V经过两路DC-DC分别变换为5V与3.3V,5V由LDO转为2.5V,3.3V由LDO转为1.2V。双电源12V是运放的电源,3.3V是单片机与FPGA的I/O口电源,2.5V是FPGA的配置电源,1.2V是FPGA的内核电源。

     单片机部分:

    单片机部分由单片机最小系统、输入控制、显示部分组成。输入控制由按键和旋转编码器输入,显示由Nokia5110来完成。

    FPGA部分:

    FPGA部分由FPGA最小系统、DAC、低通滤波器、输出放大、输入限幅、施密特触发器等组成。DAC由电阻分压网络和运放组成。

 

程序设计

    单片机部分:

    单片机采用STM32F103RCT6

    1.输入控制:单片机采集按键与数字编码器的变化改变频率、占空比数据。

    2.GUI显示:显示当前对应通道的频率值、占空比数据、被测信号频率。

    3.数据发送:将频率数据转换为地址计数器在每个时钟信号到来时所加的基数,用SPI发送到FPGA,并接收FPGA测得时钟信号的周期个数Na与被测信号的周期个数Nx。

#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "point.h"
#include "encoder.h"
#include "nokia5110.h"
#include "usart.h"

int main( void )
{	
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
	uart_init(115200);
	delay_init();
	
	Point_Init();
	LCD_init();
	
  	TIM3_Encoder_Init();     
	KEY_EXTIX_Init();       
	
	FPGA_Data_Init();       
  
	while(1)
	{
		Coder_Control();    
		LCD_GUI();        
		
		Send_Data_FPGA();   
		
		delay_ms(500);
	}
}

    FPGA部分:

    FPGA采用EP4CE6E22C8

    设计构架:

 1.PLL:将50MHz输入信号倍频为100MHz。

 2.dds_extf:频率计模块,采用等精度测量方法设计,采集输入信号输出定时器的计数值到SPI模块。

 3.SPI:完成单片机与FPGA之间的通信。

 4.AB_signal:通过SPI接收的数据改变A、B通道输出的波形及频率。

 5.TTL_signal:通过SPI接收的数据改变TTL输出的频率。

//工程top文件

module dds_top( 
						clk , rst_n ,
						SCLK , MOSI , MISO , CS , DC ,      //SPI模块
						pass_A_data , pass_B_data , led ,   //信号输出模块
						TTL , 
						sig_in
              );
				  
input clk;      //50MHz时钟信号
input rst_n;    //复位信号
//
output [7:0] pass_A_data;  //A通道数据输出
output [7:0] pass_B_data;  //B通道数据输出
output [2:0] led; //led指示输出
output TTL;     //TTL输出
//
input SCLK;     //SPI时钟 空闲高电平
input MOSI;     //从机输入
input CS;       //片选
input DC;       //数据目录选择
//
output MISO;    //从机输出
//
input sig_in;   //测频信号输入
//------------------------------------//
reg areset;
wire clk_100M;
wire locked;

doubling PLL(
					.areset(areset),
					.inclk0(clk),
					.c0(clk_100M),
					.locked(locked)
				);
//------------------------------------//

wire [31:0] add_frequency_A;
wire [31:0] add_frequency_B;
wire [7:0] wave_A;
wire [7:0] wave_B;

wire [31:0] add_frequency_TTL;

dds_signal AB_signal(
					.clk_100M(clk_100M) , .rst_n(rst_n) ,
					
					.add_frequency_A(add_frequency_A) , .add_frequency_B(add_frequency_B) ,  //控制信号
					.wave_A(wave_A) , .wave_B(wave_B) ,
					
					.pass_A_data(pass_A_data) , .pass_B_data(pass_B_data) ,
					
					.duty_cycle_A(duty_cycle_A) , .duty_cycle_B(duty_cycle_B)
				   );
				 
//------------------------------------//
wire [31:0] cnt_bzh_value;
wire [31:0] cnt_tf_value;

wire [7:0] duty_cycle_A;
wire [7:0] duty_cycle_B;

dds_spi spi( 
			    .clk(clk) , .rst_n(rst_n) ,
				 .SCLK(SCLK) , .MOSI(MOSI) , .MISO(MISO) , .CS(CS) , .DC(DC) ,
				 
				 .add_frequency_A(add_frequency_A) , .add_frequency_B(add_frequency_B) ,
				 .wave_A(wave_A) , .wave_B(wave_B) , 
				 .add_frequency_TTL(add_frequency_TTL) ,
				 
				 .cnt_bzh_value(cnt_bzh_value) , .cnt_tf_value(cnt_tf_value) , 
				 
				 .duty_cycle_A(duty_cycle_A) , .duty_cycle_B(duty_cycle_B)
		    ); 
			 
//------------------------------------//

dds_ttl TTL_signal(
                   .clk_100M(clk_100M) , .rst_n(rst_n) , 
				       .add_frequency_TTL(add_frequency_TTL) , 
						 .TTL(TTL) 
			         );
			  
//------------------------------------//

dds_extf extf(
               .clk_100M(clk_100M) , .rst_n(rst_n) ,
				   .sig_in(sig_in) ,
					.cnt_bzh_value(cnt_bzh_value) , .cnt_tf_value(cnt_tf_value) ,
					.led(led)
             );
					
//------------------------------------//

endmodule

资料下载:https://download.csdn.net/download/qq_37405067/10801971

 

 

 

 

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值