这样,A/D转换的最高位数字量就形成了。
控制电路依次对N-1、N-2、…、N-(N-1)位重复上述过程,就可使“N位寄存器”中得到和模拟电压Vx相对应的数字量。
“控制电路”在A/D转换完成后,自动使“DONE”输出端为高电平【在ADC0809中为“EOC”】。
CPU查询DONE端的状态(或作为中断请求信号)就可以从A/D转换器读出A/D转换后的数字量。
逐次逼近型结构的关键是仅有一个比较器。
要达到8位分辨率,逐次逼近A/D转换器必须完成8次比较操作,每一次比较的结果,都被顺序存储在寄存器中。
所以8位逐次逼近型转换器对每一个输入信号要进行8次比较操作。
【因此,8次比较操作有一定的延时】
10.1.3A/D转换器的主要技术指标
A/D转换器按照输出数字量的有效位数分为:
4位、8位、10位、12位、14位、16位并行输出以及BCD码输出的3位半、4位半、5位半等多种。
A/D转换器按照转换速度可大致分为超高速(转换时间≤1ns)、高速(转换时间≤1μs)、中速(转换时间≤1ms)、低速(转换时间≤1s)等几种不同转换速度的芯片。
为适应系统集成的需要,通常将转换器、多路转换开关、时钟电路、基准电压源、二-十进制译码器和转换电路集成在一个芯片内,方便用户的使用。
(1)转换时间和转换速率
A/D完成一次转换所需要的时间。
转换速率是转换时间的倒数。
是一个很重要的指标。
ADC型号不同,转换速率差别很大。
通常,8位逐次比较型ADC的转换时间为100μs左右。
(2)分辨率
在A/D转换器中,分辨率是衡量A/D转换器能够分辨出输入模拟量最小变化程度的技术指标。
分辨率取决于A/D转换器的位数,所以习惯上用输出的二进制位数或BCD码位数表示。
【LSB:
LeastSignificantBit,最低有效位】
例如,A/D转换器AD1674的满量程输入电压为5V,可输出12位二进制数,即5V用212(4096)个数进行量化,其分辨率(1LSB)为:
5V/212=1.22mV,或说A/D转换器能分辨出输入电压的最小变化值为1.22mV。
【或者输入有1.22mV的变化时,才能引起输出数字量的变化】
ADC0809的满量程输入电压为5V,其分辨率(1LSB)为:
5V/28=0.01953V=19.53mV,或说A/D转换器能分辨出输入电压的最小变化值为19.53mV。
又如,双积分型输出BCD码的A/D转换器MC14433,其满量程输入电压为2V,其输出最大的十进制数为1999,为三位半(BCD码),如果换算成二进制位数表示,约为11位,因为1999最接近于211=2048。
三位半是相对于10进制而言,因为在0000~1999之间,共有2000数字,其中低3位是可以在0~9之间作任意变化,而最高位则只能是0或1,相当于半位,合起来称三位半。
分辨率(1LSB)为:
2/2000=0.001V=1mV。
量化过程引起的误差称为量化误差。
是由于有限位数字量对模拟量进行量化而引起的误差。
理论上规定为一个单位分辨率的-1/2-+1/2LSB,提高A/D位数既可以提高分辨率,又能够减少量化误差。
【但是有干扰问题】
(3)转换精度
A/D转换器的转换精度定义为一个实际A/D转换器与一个理想A/D转换器在量化值上的差值,可用绝对误差或相对误差表示。
10.2.2AT89C51与逐次比较型8位A/D转换器――ADC0809的接口
1.ADC0809的内部结构
ADC0809的结构如图10-3所示。
采用逐次比较法完成A/D转换,单一的+5V电源供电。
片内带有地址锁存与译码功能的8选1模拟量开关,由C、B、A的编码来决定所选的通道。
完成一次转换需100μs左右(在fCLK=640KHz时,转换时间与CLK脚的时钟频率有关),具有TTL三态输出锁存器,可直接连到单片机数据总线上。
通过适当的外接电路,ADC0809可对0~5V的模拟信号进行转换。
【相当于满量程Vx为5V】
图10-3ADC0809结构框图
2.ADC0809引脚及功能
ADC0809逐次比较型8路模拟输入、8位数字量输出的A/D转换器,其引脚如图10-4所示。
图10-4ADC0809引脚图
共28个引脚,双列直插式封装(DIP)。
引脚功能如下:
IN0~IN7:
8路模拟信号输入端。
用于输入要转换的模拟电压。
D0~D7:
转换完后的8位数字量输出端。
C、B、A:
3位地址输入线,C、B、A = 000~111分别对应IN0~IN7通道的地址(注:
C为高位,A为低位)。
各路模拟输入之间切换由软件改变C、B、A引脚的编码来实现。
用于选择8路模拟输入通道的一路。
图10-5通道选择(C为高位,A为低位)
ALE:
地址(C、B、A)锁存允许信号,输入。
在ALE的上升沿将C、B、A三条地址线上的地址锁存到内部的地址锁存器中,经译码后控制8路模拟开关。
START:
A/D转换启动信号输入线,该线上的正脉冲由CPU送来。
正脉冲宽度应大于100ns。
上升沿清零SAR,下降沿启动ADC工作。
EOC:
A/D转换结束信号输出线。
EOC=0,正在进行转换;【需要进行8位逐次比较】
EOC=1,表示一次转换完成,数字量已经锁入“三态输出锁存器”。
OE:
数据输出允许信号输入线,高电平有效。
当转换结束后,如果从该引脚输入高电平,则打开输出三态门,输出“三态输出锁存器”中保存的转换后的数据量,可以从D0~D7输出。
CLK:
时钟脉冲输入端。
用于为AD0809提供逐次比较所需的640KHz时钟脉冲信号。
(转换时间为100μs),但实际上AD0809的时钟输入工作频率可以为10kHz~1280kHz,大于1.43MHz将停止工作。
一般可以采用单片机的ALE信号(经过分频后,几分频视振荡频率而定)。
VR(+)、VR(−):
为参考电压输入端。
决定输入模拟量的范围。
VR(+)通常和VCC相连,VR(−)常接地。
【典型值分别为+5V和0V】
VCC:
电源,接+5V。
GND:
地。
3.80C51单片机与ADC0809的接口
80C51与ADC的接口,必须注意三个问题:
(1)要给START线上送一个100ns宽的启动正脉冲;
(2)获取EOC线上的状态信息;【查询或中断,A/D转换的结束标志】
(3)要给“三态输出锁存器”分配一个端口地址,也就是给OE线上送一个地址译码器输出信号。
【使OE为高电平,打开三态输出锁存器】
单片机读取ADC的转换结果时,可以采用查询或中断两种方式。
采用查询方法时,在把启动信号送到ADC之后,对ADC0809的EOC引脚不断进行检测,以查询ADC变换是否已经完成。
如果为低电平(EOC=0),表示A/D正在进行转换,单片机应当继续查询;如查询到变换已经结束(EOC=1),则给OE线送一个高电平,打开输出三态门,以便从D0~D7线上读取A/D转换后的数字量。
采用中断方式时,是在启动信号送到ADC之后,EOC线作为单片机的中断请求输入线。
单片机响应中断后,应在中断服务程序中使OE线变为高电平,以读取A/D转换后的数字量。
【注意:
在主函数中启动ADC0809后,等待中断。
进入中断服务函数后,读出转换后的结果后,要再次启动ADC0809,然后从中断函数中返回,等待下一次中断】
中断控制方式效率高,所以特别适合于转换时间较长的ADC。
ADC0809和单片机的连线如下:
【CAP101138】
//电位器用“Resistors”中的“POT-HG”
【
注意ADC0809的引脚对应关系为:
OUT1为最高位,OUT8为最低位)
D7
D6
D5
D4
D3
D2
D1
D0
21
20
19
18
8
15
14
17
】
#include
unsignedcharcodeLEDData[]=//【P82,共阳方式】
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
sbitOE=P1^0;
sbitEOC=P1^1;
sbitSTART=P1^2;
sbitCLK=P1^3;
voidDelay(unsignedintcount)
{unsignedchari;
while(count--)
for(i=0;i<120;i++);
}
voidDisplay_Result(unsignedcharnum)//应该学会这种取待显示数字的方法
{P2=0xF7;//F7=11110111,LED上的“4”引脚为低,显示最低位
P0=LEDData[num%10];//取个位数码
Delay(5);
P2=0xFB;//FB=11111011,LED上的“3”引脚为低,显示左起第二位
P0=LEDData[num%100/10];//取十位数码
Delay(5);
P2=0xFD;//FD=11111101,LED上的“2”引脚为低,显示右起第二位
P0=LEDData[num/100];//取百位数码
Delay(5);
}
voidmain()
{TMOD=0x02;//02=00000010,定时器T0,定时方式,模式2
TH0=0x14;
TL0=0x14;
IE=0x82;//10000010,EA=1,ET0=1,GATE0=0
//EA=1;ET0=1;和上面的一样
TR0=1;//启动T0
P1=0x3F;//3f=00111111(P16=0,P15=1,P14=1,011,选择IN3通道)
while
(1)
{START=0;//一个机器周期就为1微秒>100ns
START=1;//START线上加一个正脉冲【正脉冲宽度应大于100ns】
START=0;//START线上加一个负脉冲,下降沿启动ADC
while(EOC==0);//等待转换结束【查询转换是否结束】
OE=1;//结束后,输出三态门打开,允许输出
Display_Result(P3);//从LED上显示结果
OE=0;//关闭输出三态门
}
}
voidTimer0_INT()interrupt1//定时器0中断服务程序
{
CLK=!
CLK;//CLK端上产生时钟信号。
频率为XX
}
【定时时间t=计数值×机器周期
=(28-初值)×(1/晶体振荡频率)×12】
定时时间t=28-20=256-20=236
236×2=472,1/472=2.1186KHz
1/640KHZ=1.5625微秒
1.56=28-初值,初值=255
【改写其中的一部分内容,程序如下】
#include
unsignedcharcodeLEDData[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
sbitOE=P1^0;
sbitEOC=P1^1;
sbitSTART=P1^2;
sbitCLK=P1^3;
sbitADDA=P1^4;
sbitADDB=P1^5;
sbitADDC=P1^6;
voidDelay(unsignedintcount)
{unsignedchari;
while(count--)
for(i=0;i<120;i++);
}
voidDisplay_Result(uchard)//应该学会这种取待显示数字的方法
{P2=0xF7;//F7=11110111,LED上的“4”引脚为低,显示最低位
P0=LEDData[d%10];//取个位数码
Delay(5);
P2=0xFB;//FB=11111011,LED上的“3”引脚为低,显示左起第二位
P0=LEDData[d%100/10];//取十位数码
Delay(5);
P2=0xFD;//FD=11111101,LED上的“2”引脚为低,显示右起第二位
P0=LEDData[d/100];//取百位数码
Delay(5);
}
voidmain()
{
TMOD=0x02;//02=00000010,定时器T0,定时方式,模式2
TH0=0x14;
TL0=0x14;
EA=1;
ET0=1;
TR0=1;//启动T0
【P1=0x3F;//3f=00111111(P16=0,P15=1,P14=1,011选择IN3通道)】
ADDC=0;【011=3,选择通道3】
ADDB=1;
ADDA=1;
while
(1)
{
START=0;
START=1;//START线上加一个正脉冲【正脉冲宽度应大于100ns】
START=0;//START线上加一个负脉冲,下降沿启动ADC
while(EOC==0);//等待转换结束【查询转换是否结束】
OE=1;//结束后,输出三态门打开,允许输出
Display_Result(P3);//转换数据从P3口输入,送LED上显示
OE=0;//关闭输出三态门
}
}
voidTimer0_INT()interrupt1//定时器0中断服务程序
{
CLK=!
CLK;//CLK端上产生时钟信号。
频率为XX
}