初次接确ADC0804 A/D转换器的朋友,知道ADC0804在输入0~5V电压时显示在0~255,看起来显示数字与相应电压并不成比例,怎么办呢?当然 有方法去实现了,此文章包含电路和程序给大家参考,希望能给你帮助,也希望您批评指正!下图就是笔者实验的拍照图。
在此之前, 我们还是非常有必要先了解一下ADC0804的一些特性和功能。
一、关于ADC0804 ADC0804是8 BIT A/D转换集成电路,采用了逐次逼近的转换方法,在振动频率F为640KHZ时,取样时间仅为100US,转换出来的数字量是以8位二进制数码在DB0~DB7接脚输出的,那么我们需要用单片机调整为十进制来用于数码管或LCD显示,这样实际上我们就可以做成一个数字式电压表或温度表等。
● 特性: 8位元CMOS逐次逼近型ADC。 三态门锁输出。 最大误差:1LSB。 內部具有时钟产生电路,频率由外加之R、C決定 ( T=1.1RC)。 转换时间: 100uS@640KHz 。 功耗:875 mW●ADC0804管脚說明 ⊕ VCC (20):电源管脚。 ⊕ Vref/2 (9):参考电压管脚。 ⊕ V+,V- ( 6,7):差动模拟电压输入.输入单端正电压时,VIN(-)接地;而差动输入时,直接加入VIN(+) 。VIN(-). ⊕ AGND,DGND (8,10):AGND,DGND;模拟信号以及数字信号的接地。 ⊕ DB7~DB0 (11~18):具有三态门锁8 位的数字输出。 ⊕ /CS (1):芯片选择脚,低电平有效。⊕ /RD (2):读取转换结果控制。/RD 为1 时,DB0~DB7 处理高阻抗:/RD 为0 时,数字数据才会输出。 ⊕ /WR (3):启动转换控制。相当于ADC 的转换开始(/CS=0 时),当/WR 由1变为0时,转换器被清除:当/WR 回到1 时,转换正式开始。 ⊕ CLK (4):时钟脉冲输入脚。內部为斯密特电路,震荡周期T=1.1RC,其中100KHz < f < 1460KHz。 ⊕ CLKR (19):CLK之反相输出。⊕ /INTR (5):中断请求输出脚,低电平动作。
二、ADC0804数据转换表和计算
例:Vin+ = 2V,由上查表可知是高4位+低4位,即1.920+0.080=2V,为01100100=64H ,也可以根据以下式子得出:
关于输入测试和Vref/2脚的解读 1. 首先提示: ADC0804的Vin+脚最大只能输入5V电压,为FFH(即255)。2. Vref/2 (9脚)-此脚很重要!使用此引脚时,必须加入Vref/2之电压,且不可超过Vref电压的一半。若悬空则内部分压一半自动作为参考电压。 说明:VCC-即电源电压, Vref-外电压的最大值, 这是两个电压概念,虽然都可以是5V,但Vref不能超过VCC)。上面电路中推荐的2.50V是Vref/2参考电压值(ADC0804手册说明不可超过Vref电压最大值的一半),可以由外部电路供给。但如果所加的VCC 电源电压准确且稳定,可以作为参考基准,则ADC0804 芯片内部设置的分压电路,可以自行提供Vref/2,此时Vref/2 端可以不外加电压,浮空即可。3. 经过多次实践证明,为了使测试的模拟量与转换后显示对应更合理,我们最好用降低基准电压的办法来适应,根据上面提供的公式的计算我们放弃了2.56V。因此我们把公式的参考电压稍微改一下,变成:AD数据 = 满幅数据255*测量电压/(参考电压2.50*2)。
三、数字电压表电路图
(单片机和ADC0804电路 - 降压和Vref/2的电压值最好要用数字万用表核对一下)
四、参考C51程序 点击下载>> ADC0804+1602数字电压表.rar
//====================================================== // 程序名称:ADC0804 + 1602数字电压表0.00~50.0V // 实验对象:XY900_USB型单片机开发系统板 // 单 片 机:AT89S52或STC89C52 // 提 示:本板还有一个外接口,用于外部输入低电压的模拟量实验 // 若测高一点的电压如0~50V请先降压10倍后再输入ADC0804 // 月夜听风: mcusy_cn@126com //======================================================*/ //------------------------------------------------------------ #include <reg52.h> #include<absacc.h> #include<intrins.h> #define uchar unsigned char #define uint unsigned int //------------------------------------------------------------ #define DataPort P0 //LCD接口 #define ReadPort P1 //AD读取 sbit RS = P2^5; //LCD读写控制 sbit RW = P2^6; sbit EN = P2^7; sbit cs=P3^2; //芯片选择信号,低电平有效 sbit rd=P3^7; //读数据控制,低电平有效 sbit wr=P3^6; //AD转换起动控制,上升沿有效 //------------------------------------------------------------ uchar code tab0[] = {" Voltage test "}; //第一行'LCD电压表' uchar code tab1[] = {" = 00.0 V "}; //第二行数据 //====================== 延时程序 ===========================// void delay(uint ms) // 约1毫秒 { uint t; while(ms--) { for(t=0;t<112;t++){} } } //////////////////// 以下是LCD操作子函数 ////////////////////// //================函数名:LCD检测忙碌信号====================// void WaitEnable(void) { DataPort = 0xff; RS = 0; RW = 1; _nop_(); EN=1; _nop_(); _nop_(); while(DataPort&0x80); EN=0; } //------------------- 函数名:写命令到LCD -------------------// void WriteCommand(uchar Order,uchar Attribc) { if(Attribc)WaitEnable(); RS = 0; RW = 0; _nop_(); DataPort=Order; _nop_(); EN = 1; _nop_(); _nop_(); EN = 0; } //------------------- 函数名: LCD写数据 --------------------// void WriteData(uchar dataW) { WaitEnable(); RS = 1; RW = 0; _nop_(); DataPort=dataW; _nop_(); EN = 1; _nop_(); _nop_(); EN = 0; } //----------------- 函数名: LCD初始化 --------------------// void InitLcd() { WriteCommand(0x38,1); WriteCommand(0x08,1); WriteCommand(0x01,1); WriteCommand(0x06,1); WriteCommand(0x0c,1); } //------------ 函数名:显示指定坐标的一个字符 -------------// void DisplayOne(uchar X,uchar Y,uchar DData) { Y&=1; X&=15; if(Y)X|= 0x40; X|= 0x80; WriteCommand(X,0); WriteData(DData); } //------------- 函数名:显示指定坐标的一串字符 --------------// void DisplayList(uchar X,uchar Y,uchar code *DData) { uchar ListLength=0; Y&= 0x1; X&= 0xF; while(X<=15) { DisplayOne(X,Y,DData[ListLength]); ListLength++; X++; } } //////////////////// 以下是ADC0804操作子函数 //////////////// /*************读AD0804 子程序*******************************/
unsigned char adc0804( void ) { uchar read_ad; rd = 1; wr = 1; //读ADC ReadPort = 0xff; //P1置位 cs=0; wr = 0; wr = 1; //启动ADC rd=0; //开始读转换后数据 _nop_(); _nop_(); //稍延时,等待读完数 read_ad = ReadPort; //读出的数据赋与ad_data rd = 1; cs = 1; //读数完毕 return(read_ad);//返回最后读出的数据 } //============= 函数名:数据处理及LCD显示函数 ==============// void display(uint ad_data) { uint qian,bai,shi,ge; //定义变量 qian= ad_data/51+0x30; //千位数 bai = ad_data%51*10/51+0x30; //百位数 shi = ad_data%51*10%51*10/51+0x30; //十位数 ge = ad_data%51*10%51*10%51*10/51+0x30; //个位数 //以下为显示位置 DisplayOne(4,1,qian);_nop_(); //百 DisplayOne(5,1,bai);_nop_(); DisplayOne(7,1,shi);_nop_(); //个位显示省略 } //==================== 函数名:主函数 ========================// void main(void) { char i; InitLcd(); //LCD初始化 for(i=15;i>=0;i--) { DisplayList(i,0,tab0); DisplayList(i,1,tab1); delay(60); } while(1) display(adc0804()); //调用显示 }