设计并实现频率可控的正弦波信号发生器Word格式文档下载.docx
《设计并实现频率可控的正弦波信号发生器Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《设计并实现频率可控的正弦波信号发生器Word格式文档下载.docx(22页珍藏版)》请在冰豆网上搜索。
一、总体设计原理
本系统采用AT89C52做控制系统,利用2片DAC0832输出正弦波信号(用示波器观察输出波形),系统初始频率为50Hz,变频采用“+”、“-”键控制,当按下“+”键是正弦波的频率自动加1输出,当按下“—”时,正弦波频率自动减一输出,实时测量输出信号的频率值,通过LCD1602动态显示,利用另一片DAC0832输出控制幅值的大小,改变正弦波的参考电压,步进值设定为0.1V。
实时监控正弦波型号达到幅度和频率。
图1
二、系统硬件设计
2.1、DAC0832模块
DAC转换器是一种将数字量转换成模拟量的器件,其特点是接收、保持和转换的是数字信息,不存在随温度和时间的漂移问题,因此电路的抗干扰性能较好。
DAC0832是8位分辨率的D/A转换集成芯片,它具有价格低廉、接口简单及转换控制容易等特点。
它由8位输入锁存器、8位DAC寄存器、8位DIA转换电路及转换控制电路组成,能和CPU数据总线直接相连,属中速转换器,大约在1us内将一个数字量转换成模拟量输出。
DAC0832的结构和引脚如图2.1:
D0~D7:
8位数据输入线,TTL电平,有效时间应大于90ns(否则锁存器的数
据会出错);
ILE:
数据锁存允许控制信号输入线,高电平有效;
CS:
片选信号输入线(选通数据锁存器),低电平有效;
WR1:
数据锁存器写选通输入线,负脉冲(脉宽应大于500ns)有效。
由ILE、
CS、WR1的逻辑组合产生LE1,当LE1为高电平时,数据锁存器状态随输入数据
线变换,LE1的负跳变时将输入数据锁存;
XFER:
数据传输控制信号输入线,低电平有效,负脉冲(脉宽应大于500ns)
有效;
WR2:
DAC寄存器选通输入线,负脉冲(脉宽应大于500ns)有效。
由WR1、XFER
的逻辑组合产生LE2,当LE2为高电平时,DAC寄存器的输出随寄存器的输入而
变化,LE2的负跳变时将数据锁存器的内容打入DAC寄存器并开始D/A转换。
IOUT1:
电流输出端1,其值随DAC寄存器的内容线性变化;
IOUT2:
电流输出端2,其值与IOUT1值之和为一常数;
Rfb:
反馈信号输入线,改变Rfb端外接电阻值可调整转换满量程精度;
Vcc:
电源输入端,Vcc的范围为+5V~+15V;
VREF:
基准电压输入线,VREF的范围为-10V~+10V;
AGND:
模拟信号地
DGND:
数字信号地
图2
1.直通方式
直通方式就是使DAC0832内部的两个寄存器(输入寄存器和DAC寄存器)
处于不锁存状态,数据一旦到达输入端DI7~DI0,就直接送入D/A转换器,被转
换成模拟量。
当ILE为高电平,CS和WR1﹑WR2和XFER端都接数字地,这时
锁存信号LE1﹑LE2均为高
电平,输入寄存器和DAC寄存器均处于不锁存状态,即直通方式。
2.单缓冲方式
单缓冲方式就是使两个寄存器中的一个处于缓冲方式,另一个处于锁存方式,
数据只通过一级缓冲器送入D/A转换器。
通常的做法是将和XFER均接地,使
DAC寄存器处于直通方式,而把ILE接高电平,接端口地址译码信号,WR1接
CPU系统总线的IOW信号,使输入寄存器处于锁存方式。
单缓冲方式只需执行
一次写操作即可完成D/A转换。
一般不需要多个模拟量同时输出时,可采用单
缓冲方式。
3.单缓冲方式
单缓冲方式就是使两个寄存器均处于锁存方式,数据要经过两级锁存(即两级
缓冲)后再送入D/A转换器,这就是说,要执行两次写操作才能完成一次D/A转
换。
只要将ILE接高电平,WR1和WR2接CPU的IOW,CS和XFER分别接两
个不同的I/O地址译码信号即可。
图中的Rfb是内部电阻,是为外部运算放大器提供的反馈电阻,用以提供适当
的输出电压,Vref端是由外电路为芯片提供的参考电源,电压范围在-10V~
+10V。
另外,DAC0832为电流输出型DAC,使用时需外接运算放大器,芯片
的电源电压最好工作在+15V。
图3
本设计采用DAC0832实现电流输出满足I1+I2是一定值。
为将电流转换成电压,这里采用具有极低的输入失调电压OP07。
通过在晶圆阶段执行调整而获得,而且这种低失调电压一般不需要进行任何外部零点校准。
此外还具有低输入偏置电流(OP07E为±
4nA)和高开环增益(OP07E为200V/mV)特性。
低失调电压和高开环增益使之特别适合高增益仪器仪表应用。
2.2、控制系统模块
这里控制系统采用AT89C52。
采用12M晶振,整体控制液晶显示和DAC0832的电压输出,并且实时进行正弦波输出。
图4
AT89C52结构介绍:
P0口:
P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。
当P1口的管脚第一次写1时,被定义为高阻输入。
P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。
在FIASH编程时,P0口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:
P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。
P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。
在FLASH编程和校验时,P1口作为第八位地址接收。
P2口:
P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。
并因此作为输入时,P2口的管脚被外部拉低,将输出电流。
这是由于内部上拉的缘故。
P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。
在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。
P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:
P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。
当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。
作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。
RST:
复位输入。
当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:
当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。
在FLASH编程期间,此引脚用于输入编程脉冲。
在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。
因此它可用作对外部输出的脉冲或用于定时目的。
然而要注意的是:
每当用作外部数据存储器时,将跳过一个ALE脉冲。
如想禁止ALE的输出可在SFR8EH地址上置0。
此时,ALE只有在执行MOVX,MOVC指令是ALE才起作用。
另外,该引脚被略微拉高。
如果微处理器在外部执行状态ALE禁止,置位无效。
/PSEN:
外部程序存储器的选通信号。
在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。
但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
/EA/VPP:
当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。
注意加密方式1时,/EA将内部锁定为RESET;
当/EA端保持高电平时,此间内部程序存储器。
在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:
反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:
来自反向振荡器的输出。
2.3、显示模块
显示模块这里采用LCD1602。
进行实时扫描按键的值并显示DAC0832的电压值,并且根据正弦波的函数输出表以及延时的关系控制频率的输出并且显示在液晶上,LCD1602指令如表格1所示。
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
2
光标返回
*
3
置输入模式
I/D
S
4
显示开/关控制
D
C
B
5
光标或字符移位
S/C
R/L
6
置功能
DL
N
F
7
置字符发生存贮器地址
字符发生存贮器地址
8
置数据存贮器地址
显示数据存贮器地址
9
读忙标志或地址
BF
计数器地址
10
写数到CGRAM或DDRAM)
要写的数据内容
11
从CGRAM或DDRAM读数
读出的数据内容
表1
三、软件部分
正弦波的实现相对方波和三角波相对比较复杂,因为正弦波的实现是输出各个点的值就行了,可是各个点值则要通过正弦函数来求出。
输出的数据刚好是256个数据,需要先将数存入数组中在大循环中取出数组,组成正弦波。
本设计采用按键扫面算法实现实时对频率和幅度的显示,并“+”、“-”按键实现调节,并且更新数据显示在液晶LCD1602上面。
图5
四、源程序
#include<
reg52.h>
#defineuintunsignedint
#defineucharunsignedchar
sbitwr2=P3^7;
sbitrs=P2^6;
sbitrw=P2^5;
sbitep=P2^7;
sbitgn=P2^4;
sbitup=P2^3;
sbitdown=P2^2;
sbitS1=P2^0;
sbitS2=P2^1;
sbitwr1=P3^0;
sbitdir1=P3^1;
sbitdir2=P3^4;
ucharj,k=39,flag,amp=0xfa;
uintfreq;
codeucharv[]="
amplitude:
"
;
ucharvv[5];
codeucharf[]="
freqency:
codeuintfj[40]={999,744,591,490,419,366,325,292,265,243,
224,208,194,181,171,161,153,145,138,132,
126,121,116,111,107,104,100,97,94,91,85,
81,74,71,67,64,60,57,53,50};
codeucharsj[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,31,33,36,38,40,42,45,48,51,55};
ucharfv[6];
codeucharsin[]={
0x7F,0x84,0x88,0x8D,0x91,0x96,0x9B,0x9F,0xA4,0xA8,0xAC,0xB1,0xB5,0xB9,0xBD,0xC1
0xC5,0xC9,0xCD,0xD0,0xD4,0xD7,0xDA,0xDE,0xE1,0xE4,0xE6,0xE9,0xEB,0xEE,0xF0,0xF2
0xF4,0xF6,0xF7,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFD
0xFD,0xFC,0xFB,0xF9,0xF8,0xF7,0xF5,0xF3,0xF1,0xEF,0xED,0xEA,0xE8,0xE5,0xE2,0xDF
0xDC,0xD9,0xD5,0xD2,0xCE,0xCB,0xC7,0xC3,0xBF,0xBB,0xB7,0xB3,0xAE,0xAA,0xA6,0xA1
0x9D,0x98,0x94,0x8F,0x8B,0x86,0x81,0x7D,0x78,0x73,0x6F,0x6A,0x66,0x61,0x5D,0x58
0x54,0x50,0x4B,0x47,0x43,0x3F,0x3B,0x37,0x33,0x30,0x2C,0x29,0x25,0x22,0x1F,0x1C
0x19,0x16,0x14,0x11,0x0F,0x0D,0x0B,0x09,0x07,0x06,0x05,0x03,0x02,0x01,0x01,0x00
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x07,0x08,0x0A,0x0C,0x0E
0x10,0x13,0x15,0x18,0x1A,0x1D,0x20,0x24,0x27,0x2A,0x2E,0x31,0x35,0x39,0x3D,0x41
0x45,0x49,0x4D,0x52,0x56,0x5A,0x5F,0x63,0x68,0x6D,0x71,0x76,0x7A,0x7F};
voiddelay(ucharz)
{
ucharx,y;
for(x=z;
x>
0;
x--)
for(y=110;
y>
y--);
}
voidwrite_com(ucharcom)
rs=0;
P0=com;
delay(5);
//用nop语句可以替代吗?
ep=1;
ep=0;
voidwrite_data(uchardate)
rs=1;
P0=date;
voidinit_1602()
rw=0;
write_com(0x38);
delay
(1);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
voiddisplay_1602(uchar*v)
uchari=0;
while(v[i]!
='
\0'
)
{
write_data(v[i]);
i++;
delay
(1);
}
voiddealv(ucharamp)
inti;
i=amp*10;
i=i/50;
vv[0]=i/10+48;
vv[1]='
.'
vv[2]=i%10+48;
vv[3]='
V'
vv[4]='
voiddealf()
freq=fj[k];
fv[0]=freq/100+48;
fv[1]=freq%100/10+48;
fv[2]=freq%10+48;
fv[3]='
H'
fv[4]='
z'
fv[5]='
freq=0;
//频率处理
voidfudu(ucharamp)
P1=amp;
wr1=0;
wr1=1;
voidkeyscan1()
if(gn==0)
delay(20);
if(gn==0);
{
while(!
gn);
flag^=0x01;
}
}
if(flag)
dir1=0;
if(up==0)
delay(10);
if(up==0);
{
while(!
up);
dir2^=1;
amp+=5;
if(amp>
250)amp=0;
//这是循环显示
fudu(amp);
dealv(amp);
write_com(0x80+10);
display_1602(vv);
}
if(down==0)
delay(100);
if(down==0);
down);
amp-=5;
if(amp==0)amp=250;
else
dir1=1;
k++;
delay(10);
if(k>
39)k=0;
//添加的判断函数
dealf();
write_com(0xc0+10);
display_1602(fv);
delay(80);
k--;
//
=250)k=39;
//增加的判断,当最小的时候回到最大,
}
}
voidmain()
uchari;
fudu(amp);
init_1602();
write_com(0x80);
display_1602(v);
write_com(0xc0);
display_1602(f);
dealv(amp);
write_com(0x80+10);
display_1602(vv);
dealf();
write_com(0x80+0x40+10);
while
(1)
keyscan1();
for(j=0;
j<
173;
j++)
P1=sin[j];
wr2=0;
for(i=sj[k];
i>
i--);
//要注意此处延时的原理
wr2=1;
五、性能分析
本系统经实物测试以及液晶显示数据处理,能达到幅值步进0.1V,初始频率50HZ开始。
测试表格如下,误差能达到很好的稳定度。
表一:
频率测量表
预置频
率/HZ
50
60
71
81
91
100
126
145
161
测试频
49.8
60.1
84.6
81.3
91.2
100.1
126.6
145.1
162.1
误差/HZ
0.2
0.1
0.4
0.3
0.6
1.1
181
208
265
325
419
490
591
744
999
181.0
207.8
265.2
325.7
419.6
489.7
591.2
7444.4
1000
0.7
表二:
幅度测量表
预置幅度/mv
500
800
1200
1500
1800
2000
2300
2500
实测幅度/mv
98
502
803
1205
1498
1807
2012
2309
2511
误差/mv
12
预置幅度/mv
2700
2900
3300
3500
3800
4100
4400
4600
5000
1712
2920
3312
3505
3790
4009
4403
4589
4970
20
30
由表格数据可以看出,在预置的频率和幅度下,可以步进0.1V。
并且可以看到实测数据和显示的数据基本无误差很少。
完全满足题目要求。
六、总结与心得
本次的设计中利用AT89C52和DAC0832以及放大器完成电路的设计,用开关来控制各种波形的发生及转换,用单片机输出后,经过模数转换器生成波形,最终可以通过示波器观察。
在这次的软件设计中,程序设计采用的是C语言。
C语言具有速度快,可以直接对硬件进行操作的优点,它可以极好的发挥硬件的功能。
并且C语言编写的代码非常容易理解