如图9-58所示, 由运算放大器进行电流→电压转换,使用内部反馈电阻。输出电压值VOUT和输入数字量D的关系:
VOUT = - VREF ×D/256
D = 0~255, VOUT = 0 ~ - VREF ×255/256
VREF = -5V, VOUT =0~5×(255/256)V
VREF = +5V, VOUT = 0 ~ -5×(255/256)V 如果实际应用系统中要求输出模拟电压为双极性,则需要用转换电路实现。如图9-59所示。
其中 R2=R3=2R1
VOUT= 2×VREF×D/256 -VREF= (2D/256-1)VREF
D = 0, VOUT= -VREF;
D = 128, VOUT= 0;
D = 255, VOUT= (2×255/256-1)×VREF= (254/255)VREF
即:输入数字为0~255时,输出电压在- VREF ~+ VREF之间变化。
1 运算放大器
运算放大器有三个特点:
⑴开环放大倍数非常高,一般为几千,甚至可高达10万。在正常情况下,运算放大器所需要的输入电压非常小。
⑵输入阻抗非常大。运算放大器工作时,输入端相当于一个很小的电压加在一个很大的输入阻抗上,所需要的输入电流也极小。
⑶输出阻抗很小,所以,它的驱动能力非常大。
2由电阻网络和运算放大器构成的D/A转换器
利用运算放大器各输入电流相加的原理,可以构成如图107所示的、由电阻网络和运算放大器组成的、最简单的4位D/A转换器。图中,V0是一个有足够精度的标准电源。运算放大器输入端的各支路对应待转换资料的D0,D1,…,Dn-1位。各输入支路中的开关由对应的数字元值控制,如果数字元为1,则对应的开关闭合;如果数字为0,则对应的开关断开。各输入支路中的电阻分别为R,2R,4R,…这些电阻称为权电阻。
假设,输入端有4条支路。4条支路的开关从全部断开到全部闭合,运算放大器可以得到16种不同的电流输入。这就是说,通过电阻网络,可以把0000B~1111B转换成大小不等的电流,从而可以在运算放大器的输出端得到相应大小不同的电压。如果数字0000B每次增1,一直变化到1111B,那么,在输出端就可得到一个0~V0电压幅度的阶梯波形。
3采用T型电阻网络的D/A转换器
从图107可以看出,在D/A转换中采用独立的权电阻网络,对于一个8位二进制数的D/A转换器,就需要R,2R,4R,…,128R共8个不等的电阻,最大电阻阻值是最小电阻阻值的128倍,而且对这些电阻的精度要求比较高。如果这样的话,从工艺上实现起来是很困难的。所以,n个如此独立输入支路的方案是不实用的。
在DAC电路结构中,最简单而实用的是采用T型电阻网络来代替单一的权电阻网络,整个电阻网络只需要R和2R两种电阻。在集成电路中,由于所有的组件都做在同一芯片上,电阻的特性可以做得很相近,而且精度与误差问题也可以得到解决。
图108是采用T型电阻网络的4位D/A转换器。4位元待转换资料分别控制4条支路中开关的倒向。在每一条支路中,如果(资料为0)开头倒向左边,支路中的电阻就接到地;如果(资料为1)开关倒向右边,电阻就接到虚地。所以,不管开关倒向哪一边,都可以认为是接“地”。不过,只有开关倒向右边时,才能给运算放大器输入端提供电流。
T型电阻网络中,节点A的左边为两个2R的电阻并联,它们的等效电阻为R,节点B的左边也是两个2R的电阻并联,它们的等效电阻也是R,…,依次类推,最后在D点等效于一个数值为R的电阻接在参考电压VREF上。这样,就很容易算出,C点、B点、A点的电位分别为-VREF/2,-VREF/4,-VREF/8。
在清楚了电阻网络的特点和各节点的电压之后,再来分析一下各支路的电流值。开关S3,S2,S1,S0分别代表对应的1位二进制数。任一资料位Di=1,表示开关Si倒向右边;Di=0,表示开关Si倒向左边,接虚地,无电流。当右边第一条支路的开关S3倒向右边时,运算放大器得到的输入电流为-VREF/(2R),同理,开关S2,S1,S0倒向右边时,输入电流分别为-VREF/(4R),-VREF/(8R),-VREF/(16R)。
如果一个二进制数据为1111,运算放大器的输入电流
I=-VREF/(2R)-VREF/(4R)-VREF/(8R)-VREF/(16R)
=-VREF/(2R)(20+2-1+2-2+2-3)
=-VREF/(24R)(23+22+21+20)
相应的输出电压
V0=IR0=-VREFR0(24R)(23+22+21+20)
将资料推广到n位,输出模拟量与输入数字量之间关系的一般表达式为:
V0=-VREFR0/(2nR)(Dn-12n-1+Dn-2 2n-2+…+D121+D020) (Di=1或0)
上式表明,输出电压V0除了和待转换的二进制数成比例外,还和网络电阻R、运算放大器反馈电阻R0、标准参考电压VREF有关。
2 D/A转换器性能参数
在实现D/A转换时,主要涉及下面几个性能参数。
⑴分辨率。分辨率是指最小输出电压(对应于输入数字量最低位增1所引起的输出电压增量)和最大输出电压(对应于输入数字量所有有效位全为1时的输出电压)之比,
例如,4位DAC的分辨率为1/(16-1)=1/15=667%(分辨率也常用百分比来表示)。8位DAC的分辨率为1/255=039%。显然,位数越多,分辨率越高。
⑵转换精度。如果不考虑D/A转换的误差,DAC转换精度就是分辨率的大小,因此,要获得高精度的D/A转换结果,首先要选择有足够高分辨率的DAC。
D/A转换精度分为绝对和相对转换精度,一般是用误差大小表示。DAC的转换误差包括零点误差、漂移误差、增益误差、噪声和线性误差、微分线性误差等综合误差。
绝对转换精度是指满刻度数字量输入时,模拟量输出接近理论值的程度。它和标准电源的精度、权电阻的精度有关。相对转换精度指在满刻度已经校准的前提下,整个刻度范围内,对应任一模拟量的输出与它的理论值之差。它反映了DAC的线性度。通常,相对转换精度比绝对转换精度更有实用性。
相对转换精度一般用绝对转换精度相对于满量程输出的百分数来表示,有时也用最低位(LSB)的几分之几表示。例如,设VFS为满量程输出电压5V,n位DAC的相对转换精度为±01%,则最大误差为±01%VFS=±5mV;若相对转换精度为±1/2LSB,LSB=1/2n,则最大相对误差为±1/2n+1VFS。
⑶非线性误差。D/A转换器的非线性误差定义为实际转换特性曲线与理想特性曲线之间的最大偏差,并以该偏差相对于满量程的百分数度量。转换器电路设计一般要求非线性误差不大于±1/2LSB。
⑷转换速率/建立时间。转换速率实际是由建立时间来反映的。建立时间是指数字量为满刻度值(各位全为1)时,DAC的模拟输出电压达到某个规定值(比如,90%满量程或±1/2LSB满量程)时所需要的时间。
建立时间是D/A转换速率快慢的一个重要参数。很显然,建立时间越大,转换速率越低。不同型号DAC的建立时间一般从几个毫微秒到几个微秒不等。若输出形式是电流,DAC的建立时间是很短的;若输出形式是电压,DAC的建立时间主要是输出运算放大器所需要的响应时间。
1033 DAC0832及接口电路
DAC0832是美国资料公司研制的8位双缓冲器D/A转换器。芯片内带有资料锁存器,可与数据总线直接相连。电路有极好的温度跟随性,使用了COMS电流开关和控制逻辑而获得低功耗、低输出的泄漏电流误差。芯片采用R-2RT型电阻网络,对参考电流进行分流完成D/A转换。转换结果以一组差动电流IOUT1和IOUT2输出。
1DAC0832的内部结构
DAC0832中有两级锁存器,第一级锁存器称为输入寄存器,它的锁存信号为ILE;第二级锁存器称为DAC寄存器,它的锁存信号为传输控制信号 。因为有两级锁存器,DAC0832可以工作在双缓冲器方式,即在输出模拟信号的同时采集下一个数字量,这样能有效地提高转换速度。此外,两级锁存器还可以在多个D/A转换器同时工作时,利用第二级锁存信号来实现多个转换器同步输出。
ILE为高电平、WR1 和 CS为低电平时, LE1为高电平,输入寄存器的输出跟随输入而变化;此后,当WR1 由低变高时, LE1为低电平,资料被锁存到输入寄存器中,这时的输入寄存器的输出端不再跟随输入资料的变化而变化。对第二级锁存器来说, WR2和XFER 同时为低电平时, LE2为高电平,DAC寄存器的输出跟随其输入而变化;此后,当WR2 由低变高时, LE2变为低电平,将输入寄存器的资料锁存到DAC寄存器中。
2 DAC0832的引脚特性
DAC0832是20引脚的双列直插式芯片。各引脚的特性如下:
CS——片选信号,和允许锁存信号ILE组合来决定 是否起作用,低有效。
ILE——允许锁存信号,高有效。
WR1——写信号1,作为第一级锁存信号,将输入资料锁存到输入寄存器(此时, 必须和 、ILE同时有效),低有效。
WR2——写信号2,将锁存在输入寄存器中的资料送到DAC寄存器中进行锁存(此时,传输控制信号 必须有效)低有效。
XFER——传输控制信号,低有效。
DI7~DI0——8位数据输入端。
IOUT1——模拟电流输出端1。当DAC寄存器中全为1时,输出电流最大,当DAC寄存器中全为0时,输出电流为0。
IOUT2——模拟电流输出端2。IOUT1+IOUT2=常数。
Rfb——反馈电阻引出端。DAC0832内部已经有反馈电阻,所以,RFB端可以直接接到外部运算放大器的输出端。相当于将反馈电阻接在运算放大器的输入端和输出端之间。
VREF——参考电压输入端。可接电压范围为±10V。外部标准电压通过VREF与T型电阻网络相连。
VCC——芯片供电电压端。范围为+5V~+15V,最佳工作状态是+15V。
AGND——模拟地,即模拟电路接地端。
DGND——数字地,即数字电路接地端。
3DAC0832的工作方式
DAC0832进行D/A转换,可以采用两种方法对数据进行锁存。
第一种方法是使输入寄存器工作在锁存状态,而DAC寄存器工作在直通状态。具体地说,就是使 和 都为低电平,DAC寄存器的锁存选通端得不到有效电平而直通;此外,使输入寄存器的控制信号ILE处于高电平、 处于低电平,这样,当 端来一个负脉冲时,就可以完成1次转换。
第二种方法是使输入寄存器工作在直通状态,而DAC寄存器工作在锁存状态。就是使 和 为低电平,ILE为高电平,这样,输入寄存器的锁存选通信号处于无效状态而直通;当WR2 和XFER 端输入1个负脉冲时,使得DAC寄存器工作在锁存状态,提供锁存数据进行转换。
根据上述对DAC0832的输入寄存器和DAC寄存器不同的控制方法,DAC0832有如下3种工作方式:
⑴单缓冲方式。单缓冲方式是控制输入寄存器和DAC寄存器同时接收资料,或者只用输入寄存器而把DAC寄存器接成直通方式。此方式适用只有一路模拟量输出或几路模拟量异步输出的情形。
⑵双缓冲方式。双缓冲方式是先使输入寄存器接收资料,再控制输入寄存器的输出资料到DAC寄存器,即分两次锁存输入资料。此方式适用于多个D/A转换同步输出的情节。
⑶直通方式。直通方式是资料不经两级锁存器锁存,即 CS,XFER ,WR1 ,WR2 均接地,ILE接高电平。此方式适用于连续反馈控制线路和不带微机的控制系统,不过在使用时,必须通过另加I/O接口与CPU连接,以匹配CPU与D/A转换。
4 DAC0832的应用举例
⑴DAC0832实现一次D/A转换,可以采用下面程序段。设定要转换的数据放在1000H单元中。
MOV BX,100H
MOV AL,[BX] ;取转换资料
OUT DX,AL
⑵在实际应用中,经常需要用到一个线性增长的电压去控制某一个检测过程,或者作为扫描电压去控制一个电子束的移动。执行下面的程序段,利用D/A转换器产生一个锯齿波电压,实现此类控制作用。
MOV DX,PORTA ;PORTA为D/A转换器端口地址
MOV AL,OFFH ;置初值
ROTAT:INC AL
OUT DX,AL ;往D/A转换器输出资料
CALL DELP ;调用延迟子程序
JMP ROTAT
DELY: MOV CX, DATA ;置延迟常数DATA
DELY1: LOOP DELY1
RET
如果需要一个负向的锯齿波,只要将指令INC AL改成DEC AL就可以了。
⑶从两个不相关的文件中输出一批X-Y资料,驱动X-Y记录仪,或者控制加工复杂零件的走刀(X轴)和进刀(Y轴)。这些在控制过程中是很有用的。下面程序驱动X-Y记录仪的100点输出,并用软件驱动记录仪的抬笔和放笔控制。
MOV SI, XDATA ;X轴资料指针→SI
MOV DI, YDATA ;Y轴资料指针→DI
MOV CX, 100
WE0: MOV AL,[SI]
OUT PORTX, AL ;往X轴的D/A转换器输出资料
MOV AL,[DI]
OUT PORTY,AL;往Y轴的D/A转换器输出资料
CALL DELY1 ;调延迟子程序1,等待笔移动
MOV AL,01H
OUT PORTM,AL;输出升脉冲,控制笔放下
CALL DELY2 ;调延迟子程序2,等待完成
MOV AL,00H
OUT PORTM,AL;输出降脉冲,控制笔抬起
CALL DELY2 ;调延迟子程序2,等待完成
INC SI
INC DI
LOOP WE0
HLT
DELY1:┇
RET
DELY2:┇
RET
XDATA DB…
YDATA DB…
(4)利用C语言编程:
#pragma db oe sb
#i nclude<reg51h>
#i nclude<absacch>
#define DAC0832 XBYTE[0x7fff] / 定义DAC0832端口地址 /
#define uchar unsigned char
void delay(uchar t) { / 延时函数 /
while(t--);
}
void saw(void) { / 锯齿波发生函数 /
uchar i;
for (i=0;i<255;i++) {
DAC0832=i;
}
}
void square(void) { / 方波发生函数 /
DAC0832=0x00;
delay(0x10);
DAC0832=0xff;
delay(0x10);
}
void main(void) {
uchar i,j;
i=j=0xff;
while(i--) {
saw(); / 产生一段锯齿波 /
}
while(j--) {
square(); / 产生一段方波 /
}
}
#include<reg51h>
sbit P10=P1^0;
void main()
{ EA=1;ET1=1;TR0=1;
TMOD=01;
TH0=65536-2000/256;
TL0=65536-2000%256;
while(1)
{
P10=~P10;
}
}
void NT1() interrupt 3
{
TH0=65536-2000/256;
TL0=65536-2000%256;
}
以下程序是0832产生的三种波形 三角波 锯齿波 方波
#include <AT89X51H>
#include<absacch>
#define PP XBYTE[0x7fff]
#define uint unsigned int
uint i,j,k;
void delay(uint z);
void main()
{
while(1)
{
if(P1_0==0)
{ delay(10);
if(P1_0==0)
{ while(P1_2!=0&&P1_1!=0)
{ P1_3=0;
for(i=255;i>=0;i--)
}
while(P1_0!=1);
} }
if(P1_1==0)
{ delay(10);
if(P1_1==0)
{ P1_4=0;
while(P1_0!=0&&P1_2!=0)
{ for(j=0;j<=254;j++)
for(j=255;j>=0;j--)
}
while(P1_1!=1); }}
if(P1_2==0)
{ delay(10);
if(P1_2==0)
{ while(P1_0!=0&&P1_1!=0)
{P1_5=0;
PP=255;
delay(10);
PP=0;
delay(10);} } }
} }
void delay(uint z)
{ uint x,y;
for(x=z;x>0;x--)
for(y=120;y>0;y--);
}
可以用一个定时器中断,在中断服务程序里面,直接把对应的正弦采样数据置入P1口,通过修改定时器的中断间隔,达到调整输出频率的目的;
假设你的采样数据的原始采样率为1KHz, 被采样正弦波频率为100Hz,当Timer中断间隔为1ms时,DAC那里输出处理后输出即为100Hz, 如果中断间隔为500us,输出就是200Hz
static unsigned char byIndex=0;
中断函数里面包含如下两句
P1 = Sin[byIndex++];
byIndex &= 0x7f;DAC832是一个数模转换芯片,要用它产生三角波,只需要将AD转换的值从低到高,再从高到低传送给它就可以实现了,以下是具体例程:
ORG 0000H
JMP START
ORG 0030H
START:
CLR A
LOOP: ;该循环产生上升波形
MOV P1, A ;输出,D/A 转换
INC A
CALL DELAY ;延时
CJNE A,#250,LOOP
LOOP1: ;该循环产生下降波形
DEC A
MOV P1,A
JNZ LOOP1
SJMP START
DELAY: ;延时子程序
MOV R6, #2
DEL1:
MOV R7, #250
DEL2:
DJNZ R7, DEL2 ;内循环250遍
DJNZ R6, DEL1 ;外循环2遍
RET
END引言
目前所使用的直流可调电源中,几乎都为旋纽开关调节电压,调节精度不高,而且经常跳变,使用麻烦。利用数控电源,可以达到每步01V的精度,输出电压范围0~15V,电流可以达到2A。
对选用芯片说明
DAC0832是一款常用的数摸转换器,它有两种连接模式,一种是电压输出模式,另外一种是电流输出模式,为了设计的方便,选用电压输出模式,如电路图所示,Iout1和Iout2之间接一参考电压, VREF输出可控制电压信号。它有三种工作方式:不带缓冲工作方式,单缓冲工作方式,双缓冲工作方式。该电路采用单缓冲模式,由电路图可知,由于/WR2 =/XFER=0,DAC寄存处于直通状态。又由于ILE=1,故只要在选中该片(/CS=0)的地址时,写入(/WR=0)数字量,则该数字信号立即传送到输入寄存器,并直通至DAC寄存器,经过短暂的建立时间,即可以获得相应的模拟电压,一旦写入 *** 作结束,/WR1和/CS立即变为高电平,则写入的数据被输入寄存器锁存,直到再次写入刷新。
AT24C02是一款常用的可掉电保存数据的ROM,2K比特容量,采用I2C总线 *** 作,关于它的具体 *** 作方法参考相关资料。
硬件电路设计
采用常用的51芯片作为控制器,P0口和 DAC0832的数据口直接相连,DA的/CS和/WR1连接后接P20,/WR2和/XEFR接地,让DA工作在单缓冲方式下。DA的11脚接参考电压,参考电压电路如图2所示,通过调节可调电阻调节LM336的输出电压为512V,所以在DAC的8脚输出电压的分辨率为512V/256= 002V,也就是说DA输入数据端每增加1,电压增加002V。
DA的电压输出端接放大器OP07的输入端,放大器的放大倍数为 R8/(R8+R9)=1K/(1K+4K)=5,输出到电压模块LM350的电压分辨率=002V×5=01V。所以,当MCU输出数据增加1的时候,最终输出电压增加01V,当调节电压的时候,可以以每次01V的梯度增加或者降低电压。
本电路设计三个按键,KEY1为翻页按键,最近设置的电压大小保存在EEROM里面,比如10个电压,按一下KEY1,电压变为下一个,省去了反复设置电压的麻烦,KEY2为电压+,KEY3为电压+,按一下KEY2,当前电压增加01V,按一下KEY3,当前电压减小01V。
该系统使用3个数码管,可以显示三位数,一个小数位,比如可以显示125V,采用动态扫描驱动方式。本主电路的原理是通过MCU控制DA的输出电压大小,通过放大器放大,给电压模块作为最终输出的参考电压,真正的电压,电流还是由电压模块LM350输出。
为了达到2A的输出电流,LM350必须选用金属外壳封装,并且带稍大面积的散热片。#include<reg52h> //包含头文件
#include<intrinsh>
#define uchar unsigned char //宏定义
#define uint unsigned int
sbit s1=P3^5; //定义按键的接口
sbit s2=P3^6;
sbit s3=P3^7;
sbit s4=P3^4;
sbit s5=P2^3;
sbit led0=P3^0; //定义四个LED,分别表示不同的波形
sbit led1=P3^1;
sbit led2=P3^2;
sbit led3=P3^3;
sbit lcdrs=P2^7; //液晶控制引脚,还有一个控制脚是RW,因为我们只需要向液晶里写数据系那是就好了,所以,我们直接将RW引脚接地
sbit lcden=P2^6;
char num,boxing,u; //定义全局变量
uchar pinlv=100,bujin=1,bujin1=1; //频率初始值是10Hz,步进值默认是01,显示步进值变量
uchar code table[]="0123456789"; //定义显示的数组
uchar code table1[]="Fout= Wave form:"; //初始化显示字符
unsigned int m,pwm=50; //定义变量 m
int a,b,h,num1; //定义全局变量
//自定义字符
uchar code zifu[]={ //此数组内数据为液晶上显示波形符号的自定义字符
0x0e,0x11,0x11,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x11,0x11,0x0e,0x00, //正弦波 0 1
0x00,0x07,0x04,0x04,0x04,0x04,0x1c,0x00,
0x00,0x1c,0x04,0x04,0x04,0x04,0x07,0x00, //矩形波 2 3
0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00,
0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00, //三角波 4 5
0x00,0x01,0x03,0x05,0x09,0x11,0x00,0x00, //锯齿波 6
};
uchar code sin[64]={ //此数组内的数据为,da输出对应电压值对应的数字量,0是0V,255是5V
135,145,158,167,176,188,199,209,218,226,234,240,245,249,252,254,254,253,251,247,243,237,230,222,213,204,193,182,170,158,
146,133,121,108,96,84,72,61,50,41,32,24,17,11,7,3,1,0,0,2,5,9,14,20,28,36,45,55,66,78,90,102,114,128
}; //正弦波取码
uchar code juxing[64]={ //一个周期是采样64个点, 所以数组内是64个数据
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}; //矩形波取码
uchar code sanjiao[64]={
0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,
248,240,232,224,216,208,200,192,184,176,168,160,152,144,136,128,120,112,104,96,88,80,72,64,56,48,40,32,24,16,8,0
}; //三角波取码
uchar code juchi[64]={
0,4,8,12,16,20,24,28,32,36,40,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,130,134,138,142,
146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,215,219,223,227,231,235,239,243,247,251,255
}; //锯齿波取码
void delay(uint xms) //延时函数
{
int a,b;
for(a=xms;a>0;a--)
for(b=110;b>0;b--);
}
void write_com(uchar com) //写命令函数
{
lcdrs=0;
P0=com;
delay(1);
lcden=0;
delay(1);
lcden=1;
}
void write_date(uchar date) //写数据函数
{
lcdrs=0;
P0=date;
delay(1);
lcden=0;
delay(1);
lcden=1;
}
//自定义字符集
void Lcd_ram()
{
uint i,j,k=0,temp=0x04;
for(i=0;i<7;i++)
{
for(j=0;j<8;j++)
{
write_com(temp+j);
write_date(zifu[k]);
k++;
}
temp=temp+8;
}
}
void init_lcd() //初始化函数
{
uchar i;
lcden=0; //默认开始状态为关使能端,见时序图
Lcd_ram();
write_com(0x01); //显示清屏,将上次的内容清除,默认为0x01
write_com(0x0f);
write_com(0x38); //显示模式设置,默认为0x38,不用变。
write_com(0x0c); //显示功能设置0x0f为开显示,显示光标,光标闪烁;0x0c为开显示,不显光标,光标不闪
write_com(0x06); //设置光标状态默认0x06,为读一个字符光标加1
write_com(0x80); //设置初始化数据指针,是在读指令的 *** 作里进行的
for(i=10;i<20;i++) //显示初始化
{
write_date(table1[i]); //显示第一行字符
}
write_com(0x80+40); //选择第二行
for(i=0;i<9;i++)
{
write_date(table1[i]); //显示第二行字符
}
write_com(0x80+10); //选择第一行第十个位置
write_date(0);
write_date(1);
write_date(0);
write_date(1);
write_date(0);
write_date(1); //显示自定义的波形图案
write_com(0x80+40+9); //选择第二行第九个位置
write_date(' ');
write_date('1');
write_date('0');
write_date('');
write_date('0');
write_date('H');
write_date('z'); //显示初始的频率值
}
void initclock() //定时器初始化函数
{
TMOD=0x01; //定时器的工作方式
TH0=a;
TL0=b; //定时器赋初值
EA=1; //打开中断总开关
ET0=1; //打开定时器允许中断开关
TR0=1; //打开定时器定时开关
}
void display() //显示函数
{
uchar qian,bai,shi,ge; //定义变量用于显示
qian=pinlv/1000; //将频率值拆成一位的数据,将数据除以1000,得到的商是一位数,赋值给qian
bai=pinlv%1000/100; //将频率除以1000的余数再除以100就得到了频率的百位,赋值给bai
shi=pinlv%1000%100/10; //同上,得到频率的十位
ge=pinlv%1000/100%10;
write_com(0x80+40+9); //选中第二行第九个位置
if(qian==0) //千位如果为0
write_date(' '); //不显示
else //千位不为0
write_date(table[qian]); //正常显示千位
if(qian==0&&bai==0) //千位和百位都为0
write_date(' '); //百位不显示
else //不都为0
write_date(table[bai]); //百位正常显示
write_date(table[shi]); //显示十位数
write_date(''); //显示小数点
write_date(table[ge]); //显示个位
write_date('H'); //显示频率的单位Hz
write_date('z');
if(boxing==0) //判断波形为正弦波
{
write_com(0x80+10); //选中一行频率图案位置
write_date(0); //显示正弦波图案
write_date(1);
write_date(0);
write_date(1);
write_date(0);
write_date(1);
led3=1;
led0=0; //点亮正弦波指示灯
}
if(boxing==1) //注释同上
{
write_com(0x80+10);
write_date(2);
write_date(3);
write_date(2);
write_date(3);
write_date(2);
write_date(3);
led0=1;
led1=0;
}
if(boxing==2)
{
write_com(0x80+10);
write_date(4);
write_date(5);
write_date(4);
write_date(5);
write_date(4);
write_date(5);
led1=1;
led2=0;
}
if(boxing==3)
{
write_com(0x80+10);
write_date(6);
write_date(6);
write_date(6);
write_date(6);
write_date(6);
write_date(6);
led2=1;
led3=0;
}
}
void keyscan() //频率调节键盘检测函数
{
if(s1==0) //加按键是否按下
{
EA=0; //关闭中断
while(!s1); //按键松开
pinlv+=bujin; //频率以步进值加
if(pinlv>1000) //最大加到100Hz
{
pinlv=100; //100Hz
}
display(); //显示函数
m=65536-(15000/pinlv);//计算频率
/频率值最小是10Hz,pinlv的值是100(因为要显示小数点后一位),150000/100=1500,这个1500就是定时器需要计时的,单位是us,65536-1500得到的是定时器的初值,
先不管初值,先看定时时间,1500us,一个波形的周期是由64个定时组成的,所以,一个波形周期就是641500us=96000,也就是96ms,约等
于100ms,也就是10Hz的频率/
a=m/256; //将定时器的初值赋值给变量
b=m%256;
EA=1; //打开中断总开关
}
if(s2==0) //减按键按下
{
EA=0;
while(!s2);
pinlv-=bujin; //频率以步进值减
if(pinlv<100)
{
pinlv=100;
}
display();
m=65536-(15000/pinlv);
a=m/256;
b=m%256;
EA=1;
}
if(s3==0) //波形切换按键
{
EA=0;
while(!s3);
boxing++; //波形切换
if(boxing>=4) //4种波形
{
boxing=0;
}
display();
EA=1;
}
if(s5==0) //PWM切换按键
{
EA=0;
while(!s5);
pwm+=10;
if(pwm>90)
{
pwm=10;
}
// display();
EA=1;
}
}
void bujindisplay() //步进值设置界面显示程序
{
uint bai,shi,ge; //定义步进值 百十个位
bai=bujin1/100; //将步进值除以100得到百位,也就是频率值的十位,因为有一个小数位
shi=bujin1%100/10; //将步进值除以100的余数除以十得到十位
ge=bujin1%100%10; //取余10后得到个位,也就是频率步进值的小数点后一位
write_com(0x80+11); //选中液晶第一行第十一列
if(bai==0) //百位是否为0
write_date(' '); //百位不显示
else //百位不为0
write_date(table[bai]); //显示百位数据
write_date(table[shi]); //显示十位数据
write_date(''); //显示小数点
write_date(table[ge]); //显示个位,也就是小数点后一位
}
void bujinjiance() //步进值设置键盘程序
{
if(s4==0) //步进设置按键按下
{
delay(5); //延时去抖
if(s4==0) //再次判断按键
{
while(!s4); //按键释放,按键松开才继续向下执行
h++; //变量加
if(h==1) //进入设置状态时
{
write_com(0x01); //清屏
write_com(0x80); //初始化显示步进设置界面
write_date('S');delay(1); //step value
write_date('t');delay(1);
write_date('e');delay(1);
write_date('p');delay(1);
write_date(' ');delay(1);
write_date('v');delay(1);
write_date('a');delay(1);
write_date('l');delay(1);
write_date('u');delay(1);
write_date('e');delay(1);
write_date(':');delay(1);
bujin1=bujin; //步进值赋值给临时变量
bujindisplay(); //显示步进值
}
if(h==2) //退出设置
{
h=0; //清零
bujin=bujin1; //设置好的临时步进值赋值给步进变量
init_lcd(); //初始化液晶显示
initclock(); //定时器初始化
display(); //调用显示程序
}
}
}
if(h==1) //设置步进值时
{
if(s1==0) //加按键按下
{
delay(5); //延时去抖
if(s1==0) //再次判断
{
while(!s1); //按键释放
bujin1++; //步进值加1
if(bujin1>=101) //步进值最大100,也就是100Hz
{
bujin1=1; //超过最大值就恢复到01Hz
}
bujindisplay(); //步进显示
}
}
if(s2==0) //减按键,注释同上
{
delay(5);
if(s2==0)
{
while(!s2);
bujin1--; //步进减
if(bujin1<=0)
{
bujin1=100;
}
bujindisplay();
}
}
}
}
void main() //主函数
{
init_lcd(); //调用初始化程序
m=65536-(15000/pinlv); //定时器初值
a=m/256;
b=m%256;
initclock(); //定时器初始化
led0=0; //点亮第一个波形指示灯
while(1) //进入while循环,括号内为1,一直成立,所以也叫死循环,程序不会跳出,一直在内执行
{
if(h==0) //正常模式不是步进调节
{
keyscan(); //扫描按键
// display();
}
bujinjiance(); //扫描步进调节程序
switch(boxing) //选择波形
{
case 0 : P1=sin[u]; break; //正弦波
case 1 : //矩形波
if(u<pwm64/100)P1=255;
else
P1=0;
break;
case 2 : P1=sanjiao[u]; break; //三角波
case 3 : P1=juchi[u]; break; //锯齿波
}
}
}
void T0_time()interrupt 1 //定时器
{
TH0=a;
TL0=b;
u++; //变量加
if(u>=64) //一个周期采样64个点, 所以加到64就清零
u=0; //u清零
//根据不同的初值,定时器定时时间不同,达到不同频率的目的
}
采用一片AT89C51单片机和两片DAC0832数模转换器组成数字式低频信号发生器,它具有价格低、性能高和在低频范围内稳定性好、 *** 作方便、体积小、耗电少等特点。
信号发生器采用数字波形合成技术通过硬件电路和软件程序相结合可输出自定义波形如正弦波、方波、三角波、三角波、梯形波及其他任意波形,波形的频率和幅度在一定范围可任意改变。波形和频率的改变通过软件控制,幅度的改变通过硬件实现。介绍了波形的生成原理、硬件电路和软件部分的设计原理。本系统可以产生最高频率7986HZ的波形。该信号发生器具有体积小、价格低、性能稳定、功能齐全的优点。
DAC0832是8分辨率的D/A转换集成芯片。与微处理器完全兼容。这个DA芯片以其价格低廉、接口简单、转换控制容易等优点,在单片机应用系统中得到广泛的应用。D/A转换器由8位输入锁存器、8位DAC寄存器、8位D/A转换电路及转换控制电路构成。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)