先了解一下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(); //波形发生函数
}
}
点个赞喽!