图2是实验框图。
图2:
本实验示意图
接下来我们首先介绍实现本实验的电路设计,然后介绍软件实现方法。
2.2硬件设计
本部分,我们首先介绍ADC0804芯片的一些相关知识,然后介绍基于ADC0804和51单片机实现A/D转换的电路设计。
2.2.1ADC0804芯片介绍
图3:
ADC0804规格及引脚分配图
本实验采用的A/D芯片为ADC0804,它是CMOS8位单通道逐次渐近型的模/数转换器,其规格及引脚图如图3所示,根据手册我们可以得到各个引脚的大致功能如下:
/CS:
芯片片选信号,低电平有效,即/CS=0,该芯片才能正常工作,在外接多个ADC0804芯片时,该信号可以作为选择地址使用,通过不同的地址信号使能不同的ADC0804芯片,从而可以实现多个ADC通道的分时复用。
/WR:
启动ADC0804进行ADC采样,该信号低电平有效,即/WR信号由高电平变成低电平时,触发一次ADC转换。
/RD:
低电平有效,即/RD=0时,可以通过数据端口DB0~DB7读出本次的采样结果。
UIN<+)和UIN<-):
模拟电压输入端,模拟电压输入接UIN<+)端,UIN<-)端接地。
双边输入时UIN<+)、UIN<-)分别接模拟电压信号的正端和负端。
当输入的模拟电压信号存在“零点漂移电压”时,可在UIN<-)接一等值的零点补偿电压,变换时将自动从UIN<+)中减去这一电压。
VREF/2:
参考电压接入引脚,该引脚可外接电压也可悬空,若外界电压,则ADC的参考电压为该外界电压的两倍,如不外接,则Vref与Vcc共用电源电压,此时ADC的参考电压即为电源电压Vcc的值。
CLKR和CLKIN:
外接RC电路产生模数转换器所需的时钟信号,时钟频率CLK=1/1.1RC,一般要求频率范围100KHz~1.28MHz。
AGND和DGND:
分别接模拟地和数字地。
/INT:
中断请求信号输出引脚,该引脚低电平有效,当一次A/D转换完成后,
将引起/INT=0,实际应用时,该引脚应与微处理器的外部中断输入引脚相连<如51单片机的INT0,INT1脚),当产生/INT信号有效时,还需等待/RD=0才能正确读出A/D转换结果,若ADC0804单独使用,则可以将/INT引脚悬空。
DB0~DB7:
输出A/D转换后的8位二进制结果。
2.2.2外围电路设计
图4:
ADC0804的外围电路
图4为ADC0804外围电路原理图,其中,AVCC=5V,引脚VREF/2悬空,因此ADC转换的参考电压为AVCC的值,即5V。
VIN-接地,而VIN+连接滑动变阻器VR1的输出,因此VIN+的电压输入范围为0V~5V,正好处于参考电压范围内。
引脚CS_1,WR_1和RD_1分别连接单片机的P3_5,P3_6以及P3_7脚,而DB0~DB7连接单片机的P2脚.
下面介绍一些电路设计方面的知识
初学者看到这里可能会有这样的疑问,就是“图4的外围电路为什么是这样设计?
CLKR引脚为什么要外接一个电阻R36和一个电容C15?
引脚CLKIN为什么要外接一个电容C15?
)。
其实这里并没有任何神秘的地方,我们仔细看看ADC0804的手册就知道答案了,手册(本实验所属的文件夹中包含了这个pdf文件>的第12页有一段内容为“TestingtheA/DConveter”,该段介绍了一个简易的芯片测试方法,其中的“FIGURE18”就给出了进行这个简易实验的原理图,以及计算公式。
如图5所示
图5:
ADC0804手册给出的参考电路图
大家仔细看看,图5给出中的手册中的参考电路图是不是和图4的原理图如出一辙?
的确,我们就是参考了手册的推荐电路从而确定了ADC0804的外围电路的设计。
手册中甚至连RC电路的电容和电阻的取值都给出来了,照搬就是了!
真的是没有任何神秘之处!
下面介绍一下datasheet对电路设计以及软件编写的重要作用。
根据我们多年的设计经验,当我们的电路中需要用到某一块芯片的时候,往往首先去下载它的手册,也就是datasheet,有很多专门提供datasheet下载的网站,推荐一个我们常用的网址:
。
进入该页面后输入我们所要查询的芯片名称<如这里的ADC0804)即可得到该芯片的datasheet。
芯片的datasheet会介绍你所需要的芯片信息,从典型外围电路的搭建,到芯片的封装,电气特性以及软件编程模型。
一般来说,直接copy手册中给出的推荐外围电路即可。
当然,若是阅读完手册后还是无法确定外围电路的搭建,则可以直接联系生产这块芯片的公司的技术服务部门<这里可以联系AD公司),他们肯定给你提供一套完整详尽的电路解决方案的<包括外围电路的设计以及甚至是软件的示例代码)。
这也就是现在比较流行的单芯片解决方案的含义所在,芯片提供商提供一块芯片后往往会提供一套基于该芯片的完整解决方案,该解决方案包括基于这块芯片的电路设计,软件设计。
产品制造厂商只要根据这个解决方案做及少的改动,即可以设计出满足自身需要的产品来!
2.2软件设计
下面我们介绍软件的编写。
本实验的软件需要实现一下几个步骤
1.控制ADC0804芯片进行正确采样,读取采样结果。
2.对采样值进行运算变换,换算出实际的滑动变阻器输入电压值。
3.将该电压值通过八段数码管显示出来,从而实现一个简易的数字电压测量表功能。
其中第三个步骤涉及到八段数码管显示相关知识,其内容在本套学习板的“”实验中有详细的介绍。
下面我们主要介绍实现前两个步骤的方法。
步骤一:
控制ADC进行正确采样,读取正确的采样值。
前面我们已经提到了芯片的datasheet对于硬件设计以及软件编程的重要性。
同样,要使得ADC0804正常工作,我们依然首先需要仔细的阅读其使用手册。
仔细阅读手册后,我们发现了在手册的第7页给出了一个时序图(TimingDiagrams>,如图6所示
图6:
ADC0804手册给出的ADC转换时序图
图6给出的其实就是使ADC0804正确工作的软件编程模型。
由图可见,实现一次ADC转换主要包含下面三个步骤:
1.启动转换:
由图6中的上部“FIGURE10A”可知,在/CS信号为低电平的情况下,将/WR引脚先由高电平变成低电平,经过至少tW(WR>I延时后,再将/WR引脚拉成高电平,即启动了一次AD转换。
注:
手册中给出了要正常启动AD转换/WR的低电平保持时间tW(WR>I的最小值为100ns,<见手册第4页的ElectricalSpecification,如图7红圈所示)即/WR拉低后延时大于100ns即可以,具体做法可通过插入NOP指令或者调用delay(>延时函数实现,不用太精确,只要估计插入的延时大于100ns即可。
2.延时等待转换结束:
依然由图6中的上部“FIGURE10A”可知,由拉低/WR信号启动AD采样后,经过1到8个Tclk+INTERNALTc延时后,AD转换结束,因此,启动转换后必须加入一个延时以等待AD采样结束。
注:
手册中给出了内部转换时间“INTERNALTc”的时间范围为62~73个始终周期<见手册第4页的ElectricalSpecification,如图7兰圈所示),因此延时等待时间应该至少为8+73=81个时钟周期。
本实验时钟频率约为Fclk=1/1.1R36C15=606KHz,其中R36约为150K,C15约为150pF,因此时钟周期约为Tclk=1/Fclk=1.65us。
所以该步骤至少应延时81*Tclk=133.65us.具体做法可通过插入NOP指令或者调用delay(>延时函数实现,不用太精确,只要估计插入的延时大于133.65us即可。
3.读取转换结果:
由图6的下部“FIGURE10B”可知,采样转换完毕后,再/CS信号为低的前提下,将/RD脚由高电平拉成低电平后,经过tACC的延时即可从DB脚读出有效的采样结果。
注:
手册中给出了tACC的典型值和最大值分别为135ns和200ns<见手册第4页的ElectricalSpecification,如图7绿圈所示),因此将/RD引脚拉低后,等待大于200ns后即可从DB读出有效的转换结果。
具体做法可通过插入NOP指令或者调用delay(>延时函数实现,不用太精确,只要估计插入的延时大于200ns即可。
图7:
ADC0804手册给出的电器特性表
步骤二:
对采样值进行运算变换,换算出实际的滑动变阻器输入电压值。
对于任何一个A/D采样器而言,其转换公式如下:
其中:
:
输入ADC的模拟电压值。
:
ADC转换后的二进制值。
本实验的ADC0804为八位。
:
ADC能够表示的刻度总数。
ADC0804为八位ADC,因此
:
ADC参考电压值,本实验ADC0804的
被设置为5V
因此,对于本实验,转换公式为
步骤三:
将该电压值通过八段数码管显示出来,从而实现一个简易的数字电压测量表功能。
涉及到八段数码管显示相关知识,其内容在本套学习板的“”实验中有详细的介绍。
综上所述,我们给出了完成单次采样的详细流程图,如图8所示
图8:
ADC0804完成单次采样的软件控制流程图
下面给出程序的主程序代码
详细的代码见本实验文件夹中的源程序部分,代码中有非常详细的注释。
////////////////////////////////////////////////////////////////////////
//名称:
单片机控制ADC0804模数转换实现电压测量(0~5V>
//作者:
飛星科技
//芯片:
AT89S52
//晶振:
12M
//编译器:
伟福6000
//日期:
2007-08-23
////////////////////////////////////////////////////////////////////////
//控制口定义//////////////////////
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
intad_data。
#definead0_7P3//AD数据口
sbitcs=P1^0。
//芯片选择信号,控制芯片的启动和结果读取,低电平有效
sbitrd=P1^1。
//读数据控制,低电平有效
sbitwr=P1^2。
//AD转换起动控制,上升沿有效
sbitintr=P1^3。
//AD转换结束输出低电平
ucharled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}。
//5ms延时子程序/////////////////
voiddelay(uintms>
{
uintx,y。
for(x=ms。
x>0。
x-->
for(y=255。
y>0。
y-->。
}
//启动AD转换子程序//////////////////////////////////////////////////////////
voidstart_ad(>
{cs=0。
//允许进行A/D转换
wr=0。
_nop_(>。
wr=1。
//WR由低变高时,AD开始转换
while(intr>。
//查询转换结束产生INTR信号(低电平有效>
cs=1。
//停止AD转换
}
//读A/D数据子程序///////////////////////////////////////
voidread_ad(>
{
cs=0。
//允许读
rd=0。
//读取转换数据结果数据结果
delay(1>。
ad_data=ad0_7。
//把数据存到ad_data中
rd=1。
cs=1。
//停止A/D读取
}
//数据处理与显示子程序//////////////////////////////////////
//说明:
当输入电压为5V时,A/D输出为FFH,即输入电压=AD数据*(5/255>=AD数据/(255/5>=AD数据/51
//用四位数码管进行显示,数码管的A~H接于P3口,公共端从最低位是P2.0,最高位是P2.3
voiddata_shout(>//观察0-5v的变化
{uinta=20,one,two,three,four。
four=ad_data/51。
//第四位数码管(最高位>
three=ad_data%51*10/51。
//第三位数码管
two=ad_data%51*10%51*10/51。
//第二位数码管
one=ad_data%51*10%51*10%51*10/51。
//第一位数码管(最低位>
while(a-->
{
P0=led[four]-0x80。
。
P2=0x01。
delay(1>。
P0=0XFF。
P2=0。
P0=led[three]。
P2=0x02。
delay(1>。
P0=0XFF。
P2=0。
P0=led[one]。
P2=0x04。
delay(1>。
P0=0XFF。
P2=0。
P0=led[two]。
P2=0x08。
delay(1>。
P0=0XFF。
P2=0。
}
}
/*voiddata_shout(>//观察0-255的变化
{uinta=20,bai,shi,ge。
bai=ad_data/100。
//第四位数码管(最高位>
shi=ad_data/10%10。
//第三位数码管
ge=ad_data%100%10。
//第二位数码管
while(a-->
{
P0=led[bai]。
P2=0x01。
delay(1>。
P0=0XFF。
P2=0。
P0=led[shi]。
P2=0x02。
delay(1>。
P0=0XFF。
P2=0。
P0=led[ge]。
P2=0x04。
delay(1>。
P0=0XFF。
P2=0。
}
}*/
/*voiddata_shout(>//观察00-ff的变化
{uinta=50,shi,ge。
//第四位数码管(最高位>
shi=ad_data/16。
//第三位数码管
ge=ad_data%16。
//第二位数码管
while(a-->
{
P0=led[shi]。
P2=0x01。
delay(1>。
P0=0XFF。
//消隐,排除干扰断码
P2=0。
//消隐,排除干扰位码
P0=led[ge]。
P2=0x02。
delay(1>。
P0=0XFF。
P2=0。
}
}*/
voidmain(>
{while(1>
{start_ad(>。
//启动AD
read_ad(>。
data_shout(>。
//读AD数据并显示
}
}
程序能在仿真图中运行,显示结果如下;
调节滑动变阻器可观察模拟量转化为数字量的现实<可观察到0到5v的变化)