【Proteus】使用DAC0832输出可调正弦波

先来了解一下DAC083x的一些基本介绍:

在DAC0830的芯片手册中可以了解到,输出IOUT1是与施加的参考电压和数字输入字的乘积成正比的电流。 为了实现应用的多功能性,第二个输出IOUT2作为电流提供,与数字输入的补码成正比。

数字输入为所施加的8位二进制字(0至255)的十进制等效值(以10为基数),VREF是引脚8上的电压,而15kΩ是R的内部电阻R的标称值 -2R梯形网络。而在DAC083x系列的芯片手册中,也可以很方便的找到参考电路,如下:

按照这个参考电路,以及看了一些网上其他人设计的电路,DAC0832部分的电路如下:

完整的电路如图:

在手册中对于DAC芯片的时序介绍比较详细,不过程序写起来并不会那么复杂,因为我们只需要在初始化之后往数据口里传数据就可以了,初始化也很简单,就直接把一些端口给0:

/**********************************
外设初始化函数
***********************************/
void da_init()	  
{
   DA_WR = 0;
   DA_CS = 0;
   DA_DATA = 0;
   key0 = 1;   //按键置高
   key1 = 1;   //按键置高
   key2 = 1;   //按键置高
   key3 = 1;   //按键置高
}

先用代码实现正弦数据的产生,先不用管幅值的调节,直接就最大幅值12V,也就是正弦数据中的255对应12V,0对应-12V。

我们使用C语言中的math库生成sin函数,有个地方需要注意,math库中的sin函数输入数据是弧度制的,假如说,我们需要30度的sin值,那么需要将30度转换成弧度制:30 * PI / 180。现在我们需要循环一个周期的sin值,那么就使用一个变量,一直自加,从0加到360度,然后求出对应的sin值,然后再将sin值转换到0-255之间传输到DAC芯片就可以了:

/**********************************
波形发生函数
***********************************/
void wave()
{
	float sinAngle = 0.0f;

	Angle ++;   //角度自加
	if (Angle >= 360)
		Angle = 0;	
	sinAngle = sin(((float)Angle * PI / 180.0f));   //求角度对应的正弦值  返回[-1,1] 
	DA_DATA	 = (int)(((sinAngle + 1.0f) / 2.0f) * 255.0f);
}

上面代码中需要注意的是sinAngle即是求取出来的正弦值,范围是[-1,1],而DAC芯片的输入是0-255,因此需要将正弦值整体加1,整体上移,然后除以2得到比例,然后再乘以255,便可以直接赋值给DAC芯片。

现在我们有了生成正弦值的函数,那么就要控制正弦值输入给DAC的时间,使用一个定时器来计时,在定时器中断中控制调用wave函数来控制生成正弦波的时间间隔,

定时器初始化程序如下:

/**********************************
定时器初始化函数
***********************************/
void init()	  
{
   TMOD = 0x01;	//设置定时器工作方式,第二位为定时器0
   TH0 = (65536 - T)/256; //定时器0高8位  定时时间1ms
   TL0 = (65536 - T)%256; //定时器0低8位
   TR0 = 1;	   //打开定时器
   ET0 = 1;	   //开定时器中断
   EA = 1;     //开总中断
}

定时器中断程序如下:

void T0_time() interrupt 1
{
	TH0 = (65536 - T)/256; //定时器0高8位  定时时间1ms
        TL0 = (65536 - T)%256; //定时器0低8位
	time ++;
	if (time > (cycle_T / T))   //0.1ms
	{
	   time = 0;
	   wave();	  //波形发生函数
	}	
}

这里我配置的定时器中断时间是1ms,也就是T,即1ms进一次中断,通过调节cycle_T可以控制正弦波的周期,也就是后面需要做的按键调频功能。这个先不用管,现在就可以看到仿真中的正弦波效果:

看到了正弦效果之后,就可以按照上面说的,检测按键,来调节正弦波的周期,先来画几个按键:

将按键检测写成一个函数,并且做好分类与注释,先填写好周期按键的相关内容,如下:

/**********************************
按键检测函数
***********************************/
void key_check()
{
   /*按键端口置高*/
   key0 = 1;
   key1 = 1;
   key2 = 1;
   key3 = 1;

   /*增大周期*/
   if(key0 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key0 == 0)   
		{
		  cycle_T = cycle_T + 2000;   //每次增加2000us
		  /*限幅*/
		  if (cycle_T > CYCLE_MAX)
		  {
		  	cycle_T	=  CYCLE_MAX;
		  }
		}
		while(!key0);	//等待按键松开
   }
   /*减小周期*/
   if(key1 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key1 == 0)   
		{
		  cycle_T = cycle_T - 2000;   //每次减小2000us
		  /*限幅*/
		  if (cycle_T < CYCLE_MIN)
		  {
		  	cycle_T	=  CYCLE_MIN;
		  }
		}
		while(!key1);	//等待按键松开
   }
   /*增大幅值*/
   if(key2 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key2 == 0)   
		{

		}
		while(!key2);	//等待按键松开
   }
   /*减小幅值*/
   if(key3 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key3 == 0)   
		{

		}
		while(!key3);	//等待按键松开
   }

}

这里我每按一次按键,就调节那个cycle_T的值,并且对这个值做了一次限幅,避免出现一些溢出之类的情况。

之后就可以看到按键调频的效果,如下:

DAC调频视频

龙猫的视频

 · 97 播放

之后是修改幅值,修改幅值其实就是修改传输到DAC的0-255的区间范围,如果是占满0-255就是最大幅值,那样的话,就可以修改wave函数,使用另外一个单独变量Amp来确定幅值,除此之外,我们需要确定一个最大幅值为12V,Amp不能超过12,修改如下:

/**********************************
波形发生函数
***********************************/
void wave()
{
	float sinAngle = 0.0f;

	Angle ++;   //角度自加
	if (Angle >= 360)
		Angle = 0;	
	sinAngle = sin(((float)Angle * PI / 180.0f));   //求角度对应的正弦值  返回[-1,1] 
	sinAngle = sinAngle * Amp / AMP_MAX;     //按照幅值范围等比例放大缩小
	DA_DATA	 = (int)(((sinAngle + 1.0f) / 2.0f) * 255.0f);
}

需要定义三个宏:

#define AMP_DEFAULT      5.0f    //默认幅值  单位:V
#define AMP_MAX          12.0f   //最大幅值为12
#define AMP_MIN          0.0f    //最小幅值

之后修改按键的部分:

 /*增大幅值*/
   if(key2 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key2 == 0)   
		{
		  Amp = Amp + 1.0f;
		  if (Amp >= AMP_MAX)
		  	 Amp = AMP_MAX;
		}
		while(!key2);	//等待按键松开
   }
   /*减小幅值*/
   if(key3 == 0)
   {
   	delayms(5);	 //按键消抖
		if(key3 == 0)   
		{
		  Amp = Amp - 1.0f;
		  if (Amp <= AMP_MIN)
		  	 Amp = AMP_MIN;
		}
		while(!key3);	//等待按键松开
   }

之后就可以看到效果啦:

DAC调幅视频

龙猫的视频

 · 116 播放

完整代码如下:

#include <reg52.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
#define DA_DATA  P1    //DAC0832数据口
#define AMP_DEFAULT      5.0f    //默认幅值  单位:V
#define AMP_MAX          12.0f   //最大幅值为12
#define AMP_MIN          0.0f    //最小幅值
#define T                1000     //计时周期  单位:us
#define CYCLE_DEFAULT    1000    //默认正弦周期   单位:us
#define CYCLE_MAX        20000    //最大周期
#define CYCLE_MIN		 1000
#define PI               3.1415926f 

/****************************变量*******************************/
uint Angle = 0;   //角度  0-360
int time = 0;	    //计时
int cycle_T = 0;    //正弦周期
float Amp = 0.0f;

//定义DAC0832接口
sbit DA_WR = P2^1;	 //写输入信号
sbit DA_CS = P2^0;   //片选信号


//定义按键接口
sbit key0 = P2^2;  //增大周期
sbit key1 = P2^3;  //减小周期
sbit key2 = P2^4;  //增大幅值
sbit key3 = P2^5;  //减小幅值

//延时
void delayms(int x)
 {  uint i,j;
    for(i=x;i>0;i--)
	  for(j=110;j>0;j--);
 }

/**********************************
外设初始化函数
***********************************/
void da_init()	  
{
   DA_WR = 0;
   DA_CS = 0;
   DA_DATA = 0;
   key0 = 1;   //按键置高
   key1 = 1;   //按键置高
   key2 = 1;   //按键置高
   key3 = 1;   //按键置高
}
/**********************************
定时器初始化函数
***********************************/
void init()	  
{
   TMOD = 0x01;	//设置定时器工作方式,第二位为定时器0
   TH0 = (65536 - T)/256; //定时器0高8位  定时时间1ms
   TL0 = (65536 - T)%256; //定时器0低8位
   TR0 = 1;	   //打开定时器
   ET0 = 1;	   //开定时器中断
   EA = 1;     //开总中断
}

/**********************************
按键检测函数
***********************************/
void key_check()
{
   /*按键端口置高*/
   key0 = 1;
   key1 = 1;
   key2 = 1;
   key3 = 1;

   /*增大周期*/
   if(key0 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key0 == 0)   
		{
		  cycle_T = cycle_T + 2000;   //每次增加2000us
		  /*限幅*/
		  if (cycle_T > CYCLE_MAX)
		  {
		  	cycle_T	=  CYCLE_MAX;
		  }
		}
		while(!key0);	//等待按键松开
   }
   /*减小周期*/
   if(key1 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key1 == 0)   
		{
		  cycle_T = cycle_T - 2000;   //每次减小2000us
		  /*限幅*/
		  if (cycle_T < CYCLE_MIN)
		  {
		  	cycle_T	=  CYCLE_MIN;
		  }
		}
		while(!key1);	//等待按键松开
   }
   /*增大幅值*/
   if(key2 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key2 == 0)   
		{
		  Amp = Amp + 1.0f;
		  if (Amp >= AMP_MAX)
		  	 Amp = AMP_MAX;
		}
		while(!key2);	//等待按键松开
   }
   /*减小幅值*/
   if(key3 == 0)
   {
   		delayms(5);	 //按键消抖
		if(key3 == 0)   
		{
		  Amp = Amp - 1.0f;
		  if (Amp <= AMP_MIN)
		  	 Amp = AMP_MIN;
		}
		while(!key3);	//等待按键松开
   }

} 

/**********************************
波形发生函数
***********************************/
void wave()
{
	float sinAngle = 0.0f;

	Angle ++;   //角度自加
	if (Angle >= 360)
		Angle = 0;	
	sinAngle = sin(((float)Angle * PI / 180.0f));   //求角度对应的正弦值  返回[-1,1] 
	sinAngle = sinAngle * Amp / AMP_MAX;     //按照幅值范围等比例放大缩小
	DA_DATA	 = (int)(((sinAngle + 1.0f) / 2.0f) * 255.0f);
}

void main()
{  
   init(); //定时器初始化
   cycle_T = CYCLE_DEFAULT;  //初始化为默认正弦周期
   Amp = AMP_DEFAULT;       //初始化为默认幅值     
   da_init();    //DA初始化
   while(1)
   {  
     key_check();
   }
}

void T0_time() interrupt 1
{
	TH0 = (65536 - T)/256; //定时器0高8位  定时时间1ms
    TL0 = (65536 - T)%256; //定时器0低8位
	time ++;
	if (time > (cycle_T / T))   //0.1ms
	{
	   time = 0;
	   wave();	  //波形发生函数
	}	
}

点个赞喽!

  • 47
    点赞
  • 191
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值