简易函数信号发生器设计.docx
《简易函数信号发生器设计.docx》由会员分享,可在线阅读,更多相关《简易函数信号发生器设计.docx(32页珍藏版)》请在冰点文库上搜索。
简易函数信号发生器设计
简易函数信号发生器设计
摘要:
本设计采用80c51单片机为核心,设计制作可以按键控制波形切换,调节幅度和频率的多波形信号发生器。
这次的设计分为五个模块:
单片机控制及显示模块、数模转换模块、波形产生模块、输出显示模块、电源模块。
使用AT89C52作为主控台结合芯片DAC0832产生1HZ-300HZ频率可调的五种信号波(正弦波、三角波和方波)。
这几种波形有几个开关控制,可以随意进行切换,十分方便。
另外,波形的频率和振幅也可以通过开关进行更改。
在编程语言上,我们选择自身比较熟悉的C语言,这样在后期波形的调试及与硬件衔接方面更容易发挥出自身优势。
经过设计及后期长时间的调试,设计的所有功能均已实现。
函数信号源是使用最广的通用信号源,它能提供正弦波、锯齿波、方波、脉冲串等波形,有的还同时具有调制和扫描能力。
关键字:
信号发生器、频率、幅度、AT98C52、DAC0832
1、设计要求
1)以单片机为核心,经过D/A转换和放大电路的处理,最后输出信号;
2)要求能输出正弦波、三角波和方波四种信号;
3)输出信号可以通过按键来改变;
4)频率可变,范围在1---300hz;
5)幅度可调0---10v;
6)可实现四路A/D电压采样;
2、总体设计
2.1 系统组成及工作原理
该函数信号发生器可以输出四种波形,有正弦波、三角波和方波。
在此基础上进一步实现对波形频率和占空比的调节,并用液晶屏分两行显示波形名称和波形频率。
函数信号发生器的设计总体框图如图1所示,主要有单片机AT89C52,电源,键盘模块,LCD1602显示模块构成。
按案件模块:
由5个复位开关与74LS21组成的系统通过对单片机传输中断信号来实现波形切换及频率和占空比的调节。
显示模块:
用LCD1602,分行显示波形类型和波形频率的显示。
图1系统总体框图
2.2测量原理
我们这个系统可实现四路A/D电压采样,使用的算法是:
V=5*N/256,取五个点电压进行测量,并将测量完的十进制数据转化为二进制数据。
AD采样数据
电压源输入
0.10
0.20
0.30
0.40
0.45
电压表测得
(放大后)
1.01
2.00
3.02
4.01
4.51
采集系统测得
1.01
2.00
3.02
4.02
4.52
3、硬件设计
3.1硬件组成
3.1.1资源分配
晶振采用12MHZ。
P1口的P1.0-P1.4分别与四个按键连接,分别控制波形切换、频率加、频率减,占空比加,占空比减。
P2口与DAC0832的D0-D7数据输入端相连。
P3口用来控制DAC0832的输入寄存器选择信号CS。
3.1.2D/A转换模块部件
DAC0832芯片原理
管脚功能介绍(如图2所示)
图2DAC0832管脚图
DI7~DI0:
8位的数据输入端,DI7为最高位。
ILE:
数据锁存允许控制信号输入线,高电平有效。
CS:
选片信号输入线(选通数据锁存器),低电平有效。
WR1:
数据锁存器写选选通输入线,负脉冲有效,由ILE、CS、WR1的逻辑组合产生LE1,当LE1为高电平时,数据锁存器状态随输入数据线变化,LE1的负跳变时将输入数据锁存。
XFER:
数据传输控制信号输入线,低电平有效,负脉冲有效。
WR2:
DAC寄存器选通输入线,负脉冲有效,由WR2、XFER的逻辑组合产生LE2,当LE2为高电平时,DAC寄存器的输出随寄存器的输入而变化,LE2的负跳变时将数据锁存器的内容打入DAC寄存器并开始D/A转换。
IOUT1:
模拟电流输出端1,当DAC寄存器中数据全为1时,输出电流最大,当DAC寄存器中数据全为0时,输出电流为0。
IOUT2:
模拟电流输出端2,IOUT2与IOUT1的和为一个常数,即IOUT1+IOUT2=常数。
RFB:
反馈电阻引出端,DAC0832内部已经有反馈电阻,所以RFB端可以直接接到外部运算放大器的输出端,这样相当于将一个反馈电阻接在运算放大器的输出端和输入端之间。
VREF:
参考电压输入端,此端可接一个正电压,也可接一个负电压,它决定0至255的数字量转化出来的模拟量电压值的幅度,VREF范围为(+10~-10)V。
VREF端与D/A内部T形电阻网络相连。
Vcc:
芯片供电电压,范围为(+5~+15)V。
AGND:
模拟量地,即模拟电路接地端。
DGND:
数字量地。
3.1.3放大部分
放大部分采用双极运算放大电路,LM358内部包括有两个独立的、高增益、内部频率补偿的双运算放大器,适合于电源电压范围很宽的单电源使用,也适用于双电源工作模式,在推荐的工作条件下,电源电流与电源电压无关。
它的使用范围包括传感放大器、直流增益模块和其他所有可用单电源供电的使用运算放大器的场合。
图3lm358
3.2 单片机核心模块
3.2.1AT89C52单片机及其说明
AT89C52为8位通用微处理器:
图4PDIP封装的AT89C52引脚图
采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52相同,其主要用于会聚调整时的功能控制。
功能包括对会聚主IC内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。
主要管脚有:
XTAL1(19脚)和XTAL2(18脚)为振荡器输入输出端口,外接12MHz晶振。
RST/Vpd(9脚)为复位输入端口,外接电阻电容组成的复位电路。
VCC(40脚)和VSS(20脚)为供电端口,分别接+5V电源的正负端。
P0~P3为可编程通用I/O脚,其功能用途由软件定义,在本设计中,P0端口(32~39脚)被定义为N1功能控制端口,分别与N1的相应功能管脚相连接,13脚定义为IR输入端,10脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12脚、27脚及28脚定义为握手信号功能端口,连接主板CPU的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。
P0口
P0口是一组8位漏极开路型双向I/O口,也即地址/数据总线复用口。
作为输出口用时,每位能吸收电流的
方式驱动8个TTL逻辑门电路,对端口P0写“1”时,可作为高阻抗输入端用。
在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8位)和数据总线复用,在访问期间激活内部上拉电阻。
在Flash编程时,P0口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。
P1口
P1是一个带内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑
门电路。
对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。
作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。
P2口
P2是一个带有内部上拉电阻的8位双向I/O口,P2的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑
门电路。
对端口P2写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。
在访问外部程序存储器或16位地址的外部数据存储器(例如执行MOVX@DPTR指令)时,P2口送出高8位地址数据。
在访问8位地址的外部数据存储器(如执行MOVX@RI指令)时,P2口输出P2锁存器的内容。
Flash编程或校验时,P2亦接收高位地址和一些控制信号。
P3口
P3口是一组带有内部上拉电阻的8位双向I/O口。
P3口输出缓冲级可驱动(吸收或输出电流)4个TTL逻
辑门电路。
对P3口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。
此时,被外部拉低的P3口将用上拉电阻输出电流(IIL)。
P3口除了作为一般的I/O口线外,更重要的用途是它的第二功能
P3口还接收一些用于Flash闪速存储器编程和程序校验的控制信号。
RST
复位输入。
当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。
ALE/PROG
当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8位字节。
一般情况下,ALE仍以时钟振荡频率的1/6输出固定的脉冲信号,因此它可对外输出时钟或用于定时目的。
要注意的是:
每当访问外部数据存储器时将跳过一个ALE脉冲。
对Flash存储器编程期间,该引脚还用于输入编程脉冲(PROG)。
如有必要,可通过对特殊功能寄存器(SFR)区中的8EH单元的D0位置位,可禁止ALE操作。
该位置位后,只有一条MOVX和MOVC指令才能将ALE激活。
此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE禁止位无效。
PSEN
程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C52由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN有效,即输出两个脉冲。
在此期间,当访问外部数据存储器,将跳过两次PSEN信号。
EA/VPP
外部访问允许。
欲使CPU仅访问外部程序存储器(地址为0000H—FFFFH),EA端必须保持低电平(接地)。
需注意的是:
如果加密位LB1被编程,复位时内部会锁存EA端状态。
如EA端为高电平(接Vcc端),CPU则执行内部程序存储器中的指令。
Flash存储器编程时,该引脚加上+12V的编程允许电源Vpp,当然这必须是该器件是使用12V编程电压Vpp。
XTAL1
振荡器反相放大器的及内部时钟发生器的输入端。
XTAL2
振荡器反相放大器的输出端。
特殊功能寄存器
在AT89C52片内存储器中,80H-FFH共128个单元为特殊功能寄存器(SFE),SFR的地址空间映象如表2所示。
并非所有的地址都被定义,从80H—FFH共128个字节只有一部分被定义,还有相当一部分没有定义。
对没有定义的单元读写将是无效的,读出的数值将不确定,而写入的数据也将丢失。
不应将数据“1”写入未定义的单元,由于这些单元在将来的产品中可能赋予新的功能,在这种情况下,复位后这些单元数值总是“0”。
AT89C52除了与AT89C51所有的定时/计数器0和定时/计数器1外,还增加了一个定时/计数器2。
定时/计数器2的控制和状态位位于T2CON(参见表3)T2MOD(参见表4),寄存器对(RCAO2H、RCAP2L)是定时器2在16位捕获方式或16位自动重装载方式下的捕获/自动重装载寄存器。
数据存储器
AT89C52有256个字节的内部RAM,80H-FFH高128个字节与特殊功能寄存器(SFR)地址是重叠的,也就是高128字节的RAM和特殊功能寄存器的地址是相同的,但物理上它们是分开的。
当一条指令访问7FH以上的内部地址单元时,指令中使用的寻址方式是不同的,也即寻址方式决定是访问高128字节
RAM还是访问特殊功能寄存器。
如果指令是直接寻址方式则为访问特殊功能寄存器。
例如,下面的直接寻址指令访问特殊功能寄存器0A0H(即P2口)地址单元。
MOV0A0H,#data
间接寻址指令访问高128字节RAM,例如,下面的间接寻址指令中,R0的内容为0A0H,则访问数据字节地址为0A0H,
而不是P2口(0A0H)。
MOV@R0,#data
堆栈操作也是间接寻址方式,所以,高128位数据RAM亦可作为堆栈区使用。
·定时器0和定时器1:
3.2.2单片机最小系统版模块
图5
3.3两级运放电路
图6
芯片特性:
内部频率补偿
直流电压增益高(约100dB)
单位增益频带宽(约1MHz)
电源电压范围宽:
单电源(3—30V)
双电源(±1.5一±15V)
低功耗电流,适合于电池供电
·低输入偏流
低输入失调电压和失调电流
共模输入电压范围宽,包括接地
差模输入电压范围宽,等于电源电压范围
输出电压摆幅大(0至Vcc-1.5V)
3.4显示电路
图7
LCD1602
主要功能A、40通道点阵LCD驱动;B、可选择当作行驱动或列驱动;C、输入/输出信号:
输出,能产生20×2个LCD驱动波形;输入,接受控制器送出的串行数据和控制信号,偏压(V1∽V6);D、通过单片机控制将所测的频率信号读数显示出来
4 、程序设计
4.1 主程序设计
图8
4.2 子程序设计
4.2.1三角波程序流程图
三角波的实现是设置一个初值,然后进行加数,同样是加到某个数之后再进行减数,减到初值之后就再返回到先前的操作,这个操作跟锯齿波的实现是相似的。
此程序输入的VREF的电压是+5V,因此该波形输出的最大频率是初值为00H和最终值为0FFH,且步数为1,这样输出的波形是最大的。
程序流程图如下图所示:
图9
4.2.2方波程序流程图
此波形的实现更加简单,只需开始的时候设置一个初值然后直接输出这个值就行了,输出一段时间后,然后再重新置一个数据,然后再输出这个数据一段时间,但是此时的时间一定要等于前面那段时间。
这样才是一个方波,如果两个时间不相同,那就相当于一个脉冲波了。
流程图如下图所示:
图10
4.2.3正弦波程序流程图
正弦波的实现则相对比较复杂,因为正弦波的实现是输出各个点的值就行了,可是各个点值则要通过正弦函数来求出,不过这些值直接去网上下载下来使用就可以了。
输出的数据刚好是256个数据,这样则可以直接相加就行了。
流程图如下图所示:
图11
程序设计
#include
typedefunsignedcharuchar;
unsignedchari,j=0,sqar_num=128;//最大值100,默认值50
unsignedcharcho=0;//0:
正弦波。
1:
方波。
2:
三角波。
3:
锯齿波。
unsignedcharnum=0;
unsignedcharTIME0_H=0xff,TIME0_L=0xd9;//定时器0的初值设置;全局变量.对应正弦波,锯齿波50HZ
sbitchg=P1^0;//三角波100Hz.
sbitfreq_u=P1^1;
sbitfreq_d=P1^2;
sbitduty_u=P1^3;
sbitduty_d=P1^4;
sbitcs=P3^7;
bitflag=0;
unsignedintFREQ=150;//初始化频率,50HZ
sbitrw=P3^6;
sbitrs=P3^5;
sbitlcde=P3^0;
unsignedcharTempBuffer[7];
unsignedcharvalue1[]={"Frequency:
"};
voiddelay(unsignedintms)
{
unsignedinti,j;
for(j=0;jfor(i=0;i<120;i++);
}
unsignedcharcodesin_num[]={
0,0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,
2,3,3,4,4,4,5,5,6,6,7,7,8,8,9,9,
10,10,11,12,12,13,14,15,15,16,17,18,18,19,20,21,
22,23,24,25,25,26,27,28,29,30,31,32,34,35,36,37,
38,39,40,41,42,44,45,46,47,49,50,51,52,54,55,56,
57,59,60,61,63,64,66,67,68,70,71,73,74,75,77,78,
80,81,83,84,86,87,89,90,92,93,95,96,98,99,101,102,
104,106,107,109,110,112,113,115,116,118,120,121,123,124,126,128,
129,131,132,134,135,137,139,140,142,143,145,146,148,149,151,153,
154,156,157,159,160,162,163,165,166,168,169,171,172,174,175,177,
178,180,181,182,184,185,187,188,189,191,192,194,195,196,198,199,
200,201,203,204,205,206,208,209,210,211,213,214,215,216,217,218,
219,220,221,223,224,225,226,227,228,229,230,230,231,232,233,234,
235,236,237,237,238,239,240,240,241,242,243,243,244,245,245,246,
246,247,247,248,248,249,249,250,250,251,251,251,252,252,253,253,
253,253,254,254,254,254,254,255,255,255,255,255,255,255,255,255
};
//调节部分--频率
voidfreq_ud(void)
{
unsignedinttemp;
if(freq_d==0)
{FREQ--;}
elseif(freq_u==0)
{FREQ++;}
if(cho==1|cho==3)//锯齿波256次中断一周期,特殊处理下。
否则他的频率是100(+\-)n*2Hz.
{
temp=0xffff-3906/FREQ;//方波,三角波默认为100hz,切换后频率也为50HZ65336-10^6/(256*FREQ)
TIME0_H=temp/256;
TIME0_L=temp%256;
}
elseif(cho==0|cho==3)//正弦波三角波默认周期50hz65536-10^6//(512*FREQ)
{
temp=0xffff-1953/FREQ;
TIME0_H=temp/256;
TIME0_L=temp%256;
}
}
//调节部分--方波的占空比
voidduty_ud(void)//方波也采用512次中断构成一个周期。
{
if(duty_d==0&sqar_num>0)
sqar_num--;
elseif(duty_u==0&sqar_num<255)
sqar_num++;
}
//波形发生函数
voidsint(void)
{
if(!
flag)
{
cs=0;P2=sin_num[num++];cs=1;
if(num==0){num=255;flag=1;}
}
elseif(flag)
{
cs=0;P2=sin_num[num--];cs=1;
if(num==255){num=0;flag=0;}
}
}
voidsquare(void)
{
if(i++{cs=0;P2=0XFF;cs=1;}
else{cs=0;P2=0X00;cs=1;}
}
voidtriangle(void)
{
cs=0;P2=num++;cs=1;
}
voidstw(void)
{
if(~flag)
{cs=0;P2=num++;cs=1;
if(num==0){num=255;flag=1;}
}
elseif(flag)
{
cs=0;P2=num--;cs=1;
if(num==255){num=1;flag=0;}
}
}
//1602显示开始
voidwrite_command(unsignedcharcommand)
{
rs=0;
P0=command;
lcde=1;
lcde=0;
}
voidwrite_data(unsignedchardata0)
{
rs=1;
P0=data0;
lcde=1;
lcde=0;
}
voidinit_1602()
{
delay(5);
write_command(0x38);
delay(5);
write_command(0x01);
delay(5);
write_command(0x06);
delay(5);
write_command(0x0c);
delay(5);
}
//1602显示结束
/*******************频率值转换为字符串**********************/
voidtemp_to_str()
{
//TempBuffer[0]=FREQ/1000+'0';//千位
TempBuffer[1]=FREQ%1000/100+'0';//百位
TempBuffer[2]=FREQ%1000%100/10+'0';//十位
TempBuffer[3]=FREQ%1000%100%10+'0';//个位
TempBuffer[4]='H';
TempBuffer[5]='z';
//TempBuffer[6]='\0';
}
voidLCD_disp_str(ucharx,uchary,uchar*str)
{ucharaddress;
if(y==1)
address=0x80+x;
else
address=0xc0+x;
write_command(address);
while(*str!
='\0')
{
write_data(*str);
str++;
}
}
/*******************频率显示*****************/
voidshow_frequency()
{
unsignedchari,j;
//in