双路相位可控信号发生器(基于Keil5、Proteus8仿真)

本设计基于DDS原理,实现了一款可数控调整幅度、频率和相位的双路正弦波发生器,频率范围1Hz至1kHz,幅度可调0.8V至5V,相位分辨率不大于1°。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.设计内容

本信号发生器主要由DDS、AT89C51、独立按键、LCD1602显示,以及TLC5615实现幅度控制等模块组成,通过按键给AT89C51发送频率控制字、相位控制字和幅度控制字,使其输出一定频率、相位差和幅度值可调的双路正弦波信号,经过四阶sallen-key低通滤波器后形成平滑的正弦波形。

2基本指标要求

内容;基于DDS原理实现幅度、频率和相位均可数控调整的双路正弦波发生器。
要求如下:
(1)频率调整范围:1Hz~1kHz,步进不大于1Hz(原始信号需5KHZ(含预留)以上满足采样定理,),步进不大于1Hz(频率分辨率最大是1HZ,通过设置相位累加器位数和频率控制字实现);
(2)Vpp调整范围:0.8V~5V(通过控制DAC的参考电压实现);
(3)同频正弦时相位可设置,分辨率不大于1°(两个同频率的正弦波的相移就是相位累加器的时刻差,时刻差越大则相移越大)。

3.总体设计方案

采用直接数字合成(Direct Digital Synthesizer)方案,DDS原理框图如下
在这里插入图片描述
DDS技术频率分辨率高、转换速度快、信号纯度高、相位可控、输出信号无电流脉冲叠加、输出可平稳过渡且相位可保持连续变化。
DDS技术中的波形存储器采用生成正弦数表代替。相位累加器采用定时器与中断配合代替。
在这里插入图片描述

4.硬件电路设计

4.1 单片机最小系统电路设计
在这里插入图片描述
4.1.1时钟电路:
本系统采用单片机内部方式产生时钟信号,用于外接一个12MHZ石英晶体振荡器(X1)和两个30pF微调电容(C1、C2),构成稳定的自激振荡器,其发出的脉冲直接送入内部的时钟电路。
4.1.2复位电路:
确定单片机工作的起始状态,完成单片机的启动过程。单片机系统的复位方式又上电自动复位和手动按键复位。本设计采用手动按键复位,该复位方式同样具有上电自动复位功能。
4.2 TLC5615硬件电路设计
在这里插入图片描述
4.2.1电路功能:
通过TLC的DIN端输入需要转换的电压值的二进制数字量,经过Vout=D(数字量)*Vref/1024计算得到输出的电压值,LM324运放输出口VREF2接到DAC0832,用于改变0832的参考电压。
4.2.2TLC5615电路设计:
U8(TLC5615),因其芯片本身工作电压上限为+5V,所以输出电压经过测试最多只能达到4.7V,无法达到题目0.8-5V的要求,所以将TLC的OUT口输出电压最大值设置为4.2V,并且通过R21与R3对5V电源的分压来补偿一个稳定的0.8V的输入信号,由图可知5v电源分在R3上电压即为0.8V.
4.2.3加法运算电路设计:
通过U9(同相加法运算电路)将两信号进行相加,以满足最大输出电压5V的要求,当R20=R4时,Vout=U1+U2.
4.3 DAC0832硬件电路设计
在这里插入图片描述
4.3.1电路功能:
通过程序控制CPU向D/A转换器送入随时间呈一定规律变化的数字量,则D/A转换器输出端就可以输出随时间按一定规律变化的波形。
4.3.2电路设计:
由TLC5615输出端控制VREF端参考电压的大小,采取单缓冲方式连接,转换结果通过IOUT1口输出。
4.4sallen-key四阶低通滤波器硬件电路设计
在这里插入图片描述

4.4.1电路功能;
将DAC0832模拟输出的不平整电压波形整成平滑的正弦波。

4.4.2电路设计:
该四阶低通滤波器是由两个二阶sallen-key滤波器级联而成,根据题目要求所产生的正弦波频率范围为1HZ-1KHZ,所以设定的截至频率需大于1KHZ,此处设定截止频率=33KHZ,增益K=1,品质因数.
4.5 人机接口电路设计
在这里插入图片描述
4.5.1按键电路
如图可见,按键采取多外部中断源电路连接,四个按键通过AND_4(四通道与门)连接到单片机的外中断INT0,只要其中任一按键按下即可产生低电平触发INTT0的中断。
①P34(SELECT_SIN)为通道选择按键,初始为通道0,按下按键后转变为通道1。
②P35(SELECT_ELE)为元素选择按键,初始为幅度,按下一次后转变为频率,按下第二次转变为相位。
③P36(RISE)为增加按键,在选择完通道与元素后,此按键便可以增加数字。
④P37(DECLINE)为减少按键,用法与P36一致。
注:幅度的步进值为0.1V,频率的步进值为1HZ,幅度的分辨率为1°。
4.5.2显示电路
如图,显示采用LCD1602液晶屏显示。
①第一行为从左到右依次是通道0的正弦波频率;通道1的正弦波频率,初始化值为1HZ。
②第二行从左到右依次是通道0的正弦波VPP;通道1的正弦波VPP;两通道正弦波频率相同时的相位差,其中VPP初始化值为0.8V,相位初始化值为0°。

4.6 整体电路设计图
整体电路图

5.系统软件设计

5.1 软件总体设计思路
本组设计采用四按键控制信号。SELECT_SIN为通道选择,通道有01;SELECT_ELE为元素选择,元素有02(元素0~2分别为信号的幅度、频率、相位);RISE为对应通道对应元素上升按键;DECLINE为对应通道对应元素下降按键。LCD1602显示屏第一行显示通道0通道1信号的频率,第二行显示通道0通道1信号的频率以及通道1的相位。
主程序初始化通道号、元素号及电压频率相位,先在LCD1602显示屏上显示电压频率相位初始值,用TLC5615输出稳定信号作为参考电压控制幅值,相位累加器和频率控制字结合控制频率以及相位,DAC0832最终输出元素对应值的信号,并打开外部按钮中断,死循环等待中断。
5.2 主程序流程设计
主函数初始化通道号元素号以及双路信号初始元素参数,调用子函数调整各元素参数,LCD1602初步显示输出双路信号幅度频率相位参数,DAC0832输出双路正弦信号,等待外部按键中断。

在这里插入图片描述

/******包含头文件******/
#include "DoubleSin.h"

/**********************************
			 全局变量
**********************************/
float freq0,freq1;//两信号的频率(设置精度为0.5Hz)
float Phase;//相位,通道1的相位,通道0不动
float Voltage0,Voltage1;//TLC5615输出电压模拟量
uint K0,K1;//频率控制字
unsigned char key;
unsigned char Sin,Ele;//Sin=0~1,Ele=0~2

/******************************************************
	* 函 数 名					: main
	* 功		能				: 主函数
	* 输    入					: 无
	* 输    出					: 无
*******************************************************/

int main(void)
{
	Sin=Ele=0;            //初始化选择通道0和元素0(元素0是幅度,元素1是频率,元素2是相位)
	/********************幅度********************/
	Voltage0=Voltage1=4.2;//幅度初始化为0.8V,外部电路有加偏置0.8V
	TLC5615(Voltage0,0);
	TLC5615(Voltage1,1);
	/********************频率********************/
	freq0=freq1=500;//单位是Hz
	FretoK(freq0,0);
	FretoK(freq1,1);
	/********************相位********************/
	Phase=0;//通道1初始相位为0,和通道0没有相位差
	PhasetoPtr();//相位算时差(相位点个数差)
	/********************************************/
	
	LCDInit();//初始化LCD1602
	WriteCommandLCD(0x40,1);//准备写CGRAM
	
	Voltage_display(Voltage0,0);
	Voltage_display(Voltage1,1);
	Frequence_display(freq0,0);
	Frequence_display(freq1,1);
	Phase_display(Phase);//先显示
	
	DAC0832();//DAC输出信号
	EA=1;
	EX0=1;
	IT0=1;

	while(1);
}
void int0_ISR(void) interrupt 0 using 1
{
 key=Read_Key();
 if(key!=0xff)
	{
		switch(key)
		{
			case 1:Sin=Choose_Sin(Sin);
						break;
			case 2:Ele=Choose_Ele(Ele);
						break;
			case 3:Rise(Sin,Ele);
						break;
			case 4:Decline(Sin,Ele);
						break;
		}
	}	 
}

5.3 DAC0832信号输出子程序设计
通过MATLAB得出三角函数波形相位值将其存入程序存储器作为波形存储器,使用AT89C52的定时器0,设置一个10KHz的时钟,并设定变量作为相位累加器和频率控制字,每次输出波形相位累加器清零,以频率控制字为步长抽样读取波形存储器内容通过DAC0832输出。

在这里插入图片描述

#include "DoubleSin.h"
/**********************************
			全局变量
**********************************/
extern float freq0,freq1;//两信号的频率(设置精度为0.5Hz)
extern float Phase;//相位,通道1的相位,通道0不动
extern uint K0,K1;

/**********************************
			正弦相位值
**********************************/
uchar code sin_ROM[256]={128,131,134,137,140,143,146,149,152,156,159,162,165,
	168,171,174,176,179,182,185,188,191,193,196,199,201,204,206,209,211,213,216,
	218,220,222,224,226,228,230,232,234,235,237,239,240,242,243,244,246,247,248,
	249,250,251,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,
	253,253,252,252,251,250,249,248,247,246,245,244,242,241,239,238,236,235,233,
	231,229,227,225,223,221,219,217,215,212,210,207,205,202,200,197,195,192,189,
	186,184,181,178,175,172,169,166,163,160,157,154,151,148,145,142,138,135,132,
	129,126,123,120,117,113,110,107,104,101,98,95,92,89,86,83,80,77,74,71,69,66,
	63,60,58,55,53,50,48,45,43,40,38,36,34,32,30,28,26,24,22,20,19,17,16,14,13,
	11,10,9,8,7,6,5,4,3,3,2,2,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,4,5,6,7,8,9,11,12,
	13,15,16,18,20,21,23,25,27,29,31,33,35,37,39,42,44,46,49,51,54,56,59,62,64,
	67,70,73,76,79,81,84,87,90,93,96,99,103,106,109,112,115,118,121,124,127};
uint ptr0,ptr1;//各自通道读取ROM的位置
uchar ptr_real0,ptr_real1;//相位表中实际位置
	
/******************************************************
	* 函 数 名					: DAC0832
	* 功		能					: 调整正弦波频率
	* 输    入					: 无
	* 输    出					: 无
*******************************************************/
void DAC0832(void)//前两个是定时器次数,后两个是定时器TH、TL值
{
	ptr0=0;//每次修改频率或相位后,重新输出波形
	PhasetoPtr();//相位算时差(相位点个数差)
	ptr_real0=(ptr0>>8)-1;
	ptr_real1=(ptr1>>8)-1;
	TMOD=0x02;
	TL0=156;
	TH0=156;
	ET0=1;
	EA=1;
	TR0=1;
}

/******************************************************
	* 函 数 名					: T0_ISR
	* 功		能				: 定时器0
	* 输    入					: 无
	* 输    出					: 无
*******************************************************/
void T0_ISR(void) interrupt 1 using 1
{
	ptr0=ptr0+K0;
	if((ptr0>>8)>ptr_real0) P0=sin_ROM[ptr0>>8];
	ptr_real0=ptr0>>8;
	ptr1=ptr1+K1;
	if((ptr1>>8)>ptr_real1) P1=sin_ROM[ptr1>>8];
	ptr_real1=ptr1>>8;
}

/******************************************************
	* 函 数 名					: FretoK
	* 功		能				: 频率求得频率控制字
	* 输    入					: 无
	* 输    出					: 无
*******************************************************/

void FretoK(float freq,uchar select) 
{
	if(!select) K0=N*freq/fclk;
	else K1=N*freq/fclk;
}

/******************************************************
	* 函 数 名					: PhasetoT
	* 功		能				: 相位差算出时间差(相位点差)
	* 输    入					: 无
	* 输    出					: 无
*******************************************************/
void PhasetoPtr() 
{
	ptr1=Phase/(2*pi)*N;//相位累加器加上相位对应点数
}

5.4 TLC5615参考电压输出子程序设计
按键修改幅值后,全局变量幅值改变,调用子函数根据幅值计算得数字量,调用给TLC5615传数字量的函数,通过TLC5615输出模拟电压作为DAC0832的参考电压
在这里插入图片描述

#include "DoubleSin.h"

/******************************************************
	* 函 数 名					: TLC5615
	* 功		能					: 给DAC0832输出参考电压
	* 输    入					: 作为参考电压的电压值、通道号
	* 输    出					: 无
*******************************************************/
void TLC5615(float Voltage,uchar select)
{
	uint DAValue=0;
	DAValue=num(Voltage);      //输入需要转换的电压值
	DA_Conver(DAValue,select);        //调用DA_Conver函数
}

/******************************************************
	* 函 数 名					: num
	* 功		能					: 将输入的电压值转换为数字量
	* 输    入					: 需转换的电压值
	* 输    出					: 电压值的数字量
*******************************************************/
uint num(float V)
{
   uint DA;		 //转换电压值的数字量	   
	 DA=V*1024/5;    //V=DA*VREF/1024
	 return DA;	     //返回的电压值的数字量
}

/******************************************************
	* 函 数 名					: DA_Conver
	* 功		能					: 将数字量传进TLC5615输出模拟电压
	* 输    入					: 电压的数字量、通道号
	* 输    出					: 无
*******************************************************/
void DA_Conver(unsigned int d10,uchar select)
{
	unsigned char i;
	TLC5615CLK=0;   
	if(!select){	//select=0  选择为通道0时 
		TLC5615_CS0=0;    
		for(i=0;i<12;i++) 
		{
			if(d10&0x0200) TLC5615DATA0=1; //从第10位开始发送数据 每发送完一位,左移一位
			else TLC5615DATA0=0;
			TLC5615CLK=1;
			d10<<=1;
			TLC5615CLK=0;
		}
		TLC5615_CS0=1;
	}
	else{				  //select=0 选择为通道1时 
		TLC5615_CS1=0;    
		for(i=0;i<12;i++) 
		{
			if(d10&0x0200) TLC5615DATA1=1; //从第10位开始发送数据 每发送完一位,左移一位
			else TLC5615DATA1=0;
			TLC5615CLK=1;
			d10<<=1;
			TLC5615CLK=0;
		}
		TLC5615_CS1=1;
	}
}

5.5 中断服务子程序设计
主程序等待中断,按键按下,中断触发,调用读按键子函数,子函数内部消抖,返回按键值给中断服务子程序,选择调用对应按键子函数。
在这里插入图片描述

#include "DoubleSin.h"
/**********************************
							全局变量
**********************************/
extern float freq0,freq1;//两信号的频率(设置精度为0.5Hz)
extern float Phase;//相位,通道1的相位,通道0不动
extern float Voltage0,Voltage1;//TLC5615输出电压模拟量

/******************************************************
	* 函 数 名					: Read_Key
	* 功		能					: 读按键是否按下
	* 输    入					: 无
	* 输    出					: 按键号
*******************************************************/
uchar Read_Key(void) 
{ 
	if(!Key1)
	{
		Delay_ms(10);
		if(!Key1)   return 1; 
	}
	else if(!Key2)
	{
		Delay_ms(10);
	 if(!Key2)   return  2; 
	}
	else if(!Key3)
	{
		Delay_ms(10);
		if(!Key3)   return  3; 
	}
	else if(!Key4)
	{
		Delay_ms(10);
		if(!Key4)   return  4; 
	}	
	return 0xff;
}
/******************************************************
	* 函 数 名					: Choose_Sin
	* 功		能					: 选择通道
	* 输    入					: 前通道号
	* 输    出					: 后通道号
*******************************************************/
uchar Choose_Sin(uchar Sin)
{
	if(Sin==1) return 0;
	else return 1;
}
/******************************************************
	* 函 数 名					: Choose_Ele
	* 功		能					: 选择元素
	* 输    入					: 前元素号
	* 输    出					: 后元素号
*******************************************************/
uchar Choose_Ele(uchar Ele)
{
	if(Ele==2) return 0;
	else return (Ele+1);
}

/******************************************************
	* 函 数 名					: Rise
	* 功		能					: 上升
	* 输    入					: 通道号、元素号
	* 输    出					: 无
*******************************************************/
void Rise(uchar Sin,uchar Ele)
{
	TR0=0;
	if(Ele==0)    //选择元素0,幅度
	{
		if(Sin==0)  //通道0
		{
			if(Voltage0<=4.1) Voltage0+=0.1;
			Voltage_display(Voltage0,0);//先显示
			TLC5615(Voltage0,0);
			DAC0832();
		}
		else       //通道1
		{
			if(Voltage1<=4.1) Voltage1+=0.1;
			Voltage_display(Voltage1,1);//先显示
			TLC5615(Voltage1,1);
			DAC0832();
		}
	}
	else if(Ele==1)  //选择元素1,频率
	{
		if(freq0==freq1) Phase=0;//假设频率变化之前是相等的,则相位清零
		Phase_display(Phase);//先显示
		PhasetoPtr();
		if(Sin==0) //通道0
		{
			if(freq0<=999.5) freq0+=0.5;//单位是Hz
			Frequence_display(freq0,0);//先显示
			FretoK(freq0,0);
			DAC0832();
		}
		else       //通道1
		{
			if(freq1<=999.5) freq1+=0.5;
			Frequence_display(freq1,1);//先显示
			FretoK(freq1,1);
			DAC0832();
		}
	}
	else             //选择元素2,相位
	{
		if(freq0==freq1)
		{
			if(Phase<=2*pi*359/360) Phase+=2*pi/360;
			Phase_display(Phase);//先显示
			PhasetoPtr();
			DAC0832();
		}
	}
}

/******************************************************
	* 函 数 名					: Decline
	* 功		能					: 下降
	* 输    入					: 通道号、元素号
	* 输    出					: 无
*******************************************************/
void Decline(uchar Sin,uchar Ele)
{
	TR0=0;
	if(Ele==0)       //选择元素0,幅度
	{
		if(Sin==0) //通道0
		{
			if(Voltage0>=0.1) Voltage0-=0.1;
			Voltage_display(Voltage0,0);//先显示
			TLC5615(Voltage0,0);
			DAC0832();
		}
		else       //通道1
		{
			if(Voltage1>=0.1) Voltage1-=0.1;
			Voltage_display(Voltage1,1);//先显示
			TLC5615(Voltage1,1);
			DAC0832();
		}
	}
	else if(Ele==1)  //选择元素1,频率
	{
		if(freq0==freq1) Phase=0;//假设频率变化之前是相等的,则相位清零
		Phase_display(Phase);//先显示
		PhasetoPtr();
		if(Sin==0) //通道0
		{
			if(freq0>=1.5) freq0-=0.5;//单位是Hz
			Frequence_display(freq0,0);//先显示
			FretoK(freq0,0);
			DAC0832();
		}
		else       //通道1
		{
			if(freq1>=1.5) freq1-=0.5;
			Frequence_display(freq1,1);//先显示
			FretoK(freq1,1);
			DAC0832();
		}
	}
	else             //选择元素2,相位
	{
		if(freq0==freq1)
		{
			if(Phase>=2*pi/360) Phase-=2*pi/360;
			Phase_display(Phase);//先显示
			PhasetoPtr();
			DAC0832();
		}
	}
}

6.系统仿真结果显示

6.1示波器显示说明:
①ChannelA(黄色线条)为通道0未经过滤波电路前输出的正弦波形
②ChannelB(蓝色线条)为通道1未经过滤波电路前输出的正弦波形
③ChannelC(粉色线条)为通道0经过滤波电路后输出的正弦波形
③ChannelD(绿色线条)为通道1经过滤波电路后输出的正弦波形
四个通道其中竖轴每一小格的电压值都为1V,横轴每一小格时间值不固定,详情见keil仿真波形。
6.2 keil显示说明:
利用keil更直观的显示正弦波的频率值。
6.3显示情况
低频时配合调试情况:
6.3.1选择通道0,元素为幅度时,按下RISE按键至2.0V时显示情况:
LCD显示图
Keil仿真图
Proteus示波器仿真图
6.3.2选择通道0,元素为频率时,按下RISE按键至10HZ时显示情况:
LCD显示图Keil仿真图Proteus示波器仿真图
高频时显示情况:(因为此部分只为了观察高频时的波形的情况,所以幅度统一设定为5V)
6.3.3选择通道0,元素为频率时,按下RISE键至500HZ,切换通道1,元素为频率时,按下RISE键至800HZ。
LCD显示图
Keil仿真图
Proteus仿真图
6.3.4两通道高频相等时,元素为相位时,p=180°显示情况:
LCD显示图
Keil仿真图
Proteus示波器仿真图

7.总结

本设计内容:基于DDS原理实现幅度、频率和相位均可数控调整的双路正弦波发生器。要求:
(1)频率调整范围:1Hz—1kHz,步进不大于1Hz;
(2)Vpp调整范围:0.8V~5V;
(3)同频正弦时相位可设置,分辨率不大于1°。
本组双路正弦波发生器设计为四按键控制以及LCD1602显示人机界面。
本设计完成的功能:
(1)双路信号幅度、频率的升降按键控制;
(2)当频率相等时,通道0相位不动,通道1相位可通过按键控制调整升降;
(3)当频率相等时,若通过按键调整频率,通道1相位自动清零;
(4)LCD1602实时显示双路正弦信号个元素(幅度、频率和相位)参数;

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值