资讯详情

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

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

在DAC从0830的芯片手册中可以了解到,输出IOUT与参考电压和数字输入字的乘积成正比。 第二个输出是为了实现应用程序的多功能性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;   //每次增加200000us     /*限幅*/     if (cycle_T > CYCLE_MAX)     {      cycle_T =  CYCLE_MAX;     }   }   while(!key0); //等待按钮松开    }    /*减小周期*/    if(key1 == 0)    {      delayms(5);  //按钮抖动   if(key1 == 0)      {     cycle_T = cycle_T - 2000;   ///每次减少200000us     /*限幅*/     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(!key2); //等待按钮松开    }    /*减小幅值*/    if(key3 == 0)    {      delayms(5);  //按钮抖动   if(key3 == 0)      {    }   while(!key3); //等待按钮松开    }  }

每次按下这里的按钮,我都会调整那个cycle_T值,并对此值进行限幅,避免出现溢出等情况。

按键调频效果如下:

DAC调频视频

龙猫的视频

·97播放

修改幅值后,修改幅值实际上是修改并传输到DAC0-255的范围,如果占0-255是最大值,那么可以修改wave使用另一个单独的变量函数Amp除此之外,我们还需要确定最大幅值为12V,Amp修改如下:

/********************************** 波形发生函数 ***********************************/ 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); //等待按键松开    }

之后可以看到效果p

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();	  //波形发生函数
	}	
}

点个赞喽!

标签: 电阻083

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台